evm_client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +26 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.travis.yml +32 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/LICENSE.txt +21 -0
- data/PREREQUISITES.md +75 -0
- data/README.md +665 -0
- data/Rakefile +11 -0
- data/bin/console +14 -0
- data/bin/install_parity +22 -0
- data/bin/setup +7 -0
- data/contracts/AccountingLib.sol +112 -0
- data/contracts/AuditorInterface.sol +4 -0
- data/contracts/AuditorRegistry.sol +14 -0
- data/contracts/CustodianInterface.sol +27 -0
- data/contracts/CustodianRegistry.sol +40 -0
- data/contracts/DigixConfiguration.sol +68 -0
- data/contracts/Directory.sol +67 -0
- data/contracts/DoublyLinked.sol +54 -0
- data/contracts/GenericInterface.sol +56 -0
- data/contracts/GenericRegistry.sol +15 -0
- data/contracts/Gold.sol +105 -0
- data/contracts/GoldRegistry.sol +82 -0
- data/contracts/GoldTokenLedger.sol +3 -0
- data/contracts/Interface.sol +27 -0
- data/contracts/Minter.sol +3 -0
- data/contracts/Recaster.sol +3 -0
- data/contracts/Testing.sol +59 -0
- data/contracts/VendorInterface.sol +82 -0
- data/contracts/VendorRegistry.sol +39 -0
- data/contracts/classic/Digixbot.sol +106 -0
- data/contracts/classic/DigixbotConfiguration.sol +62 -0
- data/contracts/classic/DigixbotEthereum.sol +86 -0
- data/contracts/classic/DigixbotUsers.sol +103 -0
- data/contracts/classic/Gold.sol +497 -0
- data/contracts/classic/GoldRegistry.sol +503 -0
- data/contracts/classic/GoldTokenLedger.sol +560 -0
- data/contracts/classic/GoldTokenMinter.sol +607 -0
- data/contracts/classic/ParticipantRegistry.sol +94 -0
- data/contracts/classic/QueueSample.sol +54 -0
- data/evm_client.gemspec +36 -0
- data/lib/evm_client.rb +15 -0
- data/lib/evm_client/abi.rb +32 -0
- data/lib/evm_client/client.rb +146 -0
- data/lib/evm_client/contract.rb +341 -0
- data/lib/evm_client/contract_event.rb +32 -0
- data/lib/evm_client/contract_initializer.rb +54 -0
- data/lib/evm_client/decoder.rb +99 -0
- data/lib/evm_client/deployment.rb +49 -0
- data/lib/evm_client/encoder.rb +118 -0
- data/lib/evm_client/event_log.rb +88 -0
- data/lib/evm_client/explorer_url_helper.rb +25 -0
- data/lib/evm_client/formatter.rb +146 -0
- data/lib/evm_client/function.rb +40 -0
- data/lib/evm_client/function_input.rb +14 -0
- data/lib/evm_client/function_output.rb +14 -0
- data/lib/evm_client/http_client.rb +44 -0
- data/lib/evm_client/initializer.rb +27 -0
- data/lib/evm_client/ipc_client.rb +57 -0
- data/lib/evm_client/project_initializer.rb +28 -0
- data/lib/evm_client/railtie.rb +12 -0
- data/lib/evm_client/singleton.rb +39 -0
- data/lib/evm_client/solidity.rb +40 -0
- data/lib/evm_client/transaction.rb +41 -0
- data/lib/evm_client/version.rb +3 -0
- data/lib/tasks/ethereum_contract.rake +27 -0
- data/lib/tasks/ethereum_node.rake +52 -0
- data/lib/tasks/ethereum_test.rake +32 -0
- data/lib/tasks/ethereum_transaction.rake +24 -0
- metadata +219 -0
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
|
4
|
+
import "./lib/tasks/ethereum_test.rake"
|
5
|
+
import "./lib/tasks/ethereum_node.rake"
|
6
|
+
import "./lib/tasks/ethereum_contract.rake"
|
7
|
+
import "./lib/tasks/ethereum_transaction.rake"
|
8
|
+
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
10
|
+
|
11
|
+
task :default => :spec
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'evm_client'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require 'irb'
|
14
|
+
IRB.start
|
data/bin/install_parity
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
echo "Installing parity..."
|
4
|
+
sudo add-apt-repository ppa:ethereum/ethereum -y
|
5
|
+
sudo apt-get update
|
6
|
+
sudo apt-get -y install dpkg
|
7
|
+
sudo apt-get -y install libssl-dev
|
8
|
+
curl -o /usr/bin/solc -fL https://github.com/ethereum/solidity/releases/download/v0.5.16/solc-static-linux \
|
9
|
+
&& chmod 775 /usr/bin/solc \
|
10
|
+
&& chown travis:travis /usr/bin/solc
|
11
|
+
echo "Solc version"
|
12
|
+
solc --version
|
13
|
+
|
14
|
+
wget https://releases.parity.io/ethereum/v$PARITY\/x86_64-unknown-linux-gnu/parity
|
15
|
+
chmod u+x parity
|
16
|
+
chown travis:travis parity
|
17
|
+
|
18
|
+
echo "Setuping parity..."
|
19
|
+
mkdir -p ~/.local/share/io.parity.ethereum/keys/DevelopmentChain
|
20
|
+
chown -R travis:travis ~/.local/share/io.parity.ethereum
|
21
|
+
echo $devwallet > ~/.local/share/io.parity.ethereum/keys/DevelopmentChain/UTC--2017-03-31T14-19-47Z--c05e3b8b-18aa-ab4f-c5ec-09f555bf5357
|
22
|
+
echo $devpassword > ~/.devpass
|
data/bin/setup
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
// Accounting v0.1
|
2
|
+
|
3
|
+
/// @title Accounting Lib - Accounting utilities
|
4
|
+
/// @author Piper Merriam - <pipermerriam@gmail.com>
|
5
|
+
library AccountingLib {
|
6
|
+
struct Bank {
|
7
|
+
mapping (address => uint) accountBalances;
|
8
|
+
}
|
9
|
+
|
10
|
+
/// @dev Low level method for adding funds to an account. Protects against overflow.
|
11
|
+
/// @param self The Bank instance to operate on.
|
12
|
+
/// @param accountAddress The address of the account the funds should be added to.
|
13
|
+
/// @param value The amount that should be added to the account.
|
14
|
+
function addFunds(Bank storage self, address accountAddress, uint value) public {
|
15
|
+
/*
|
16
|
+
* Helper function that should be used for any addition of
|
17
|
+
* account funds. It has error checking to prevent
|
18
|
+
* overflowing the account balance.
|
19
|
+
*/
|
20
|
+
if (self.accountBalances[accountAddress] + value < self.accountBalances[accountAddress]) {
|
21
|
+
// Prevent Overflow.
|
22
|
+
throw;
|
23
|
+
}
|
24
|
+
self.accountBalances[accountAddress] += value;
|
25
|
+
}
|
26
|
+
|
27
|
+
event _Deposit(address indexed _from, address indexed accountAddress, uint value);
|
28
|
+
|
29
|
+
/// @dev Function wrapper around the _Deposit event so that it can be used by contracts. Can be used to log a deposit to an account.
|
30
|
+
/// @param _from The address that deposited the funds.
|
31
|
+
/// @param accountAddress The address of the account the funds were added to.
|
32
|
+
/// @param value The amount that was added to the account.
|
33
|
+
function Deposit(address _from, address accountAddress, uint value) public {
|
34
|
+
_Deposit(_from, accountAddress, value);
|
35
|
+
}
|
36
|
+
|
37
|
+
/// @dev Safe function for depositing funds. Returns boolean for whether the deposit was successful
|
38
|
+
/// @param self The Bank instance to operate on.
|
39
|
+
/// @param accountAddress The address of the account the funds should be added to.
|
40
|
+
/// @param value The amount that should be added to the account.
|
41
|
+
function deposit(Bank storage self, address accountAddress, uint value) public returns (bool) {
|
42
|
+
/*
|
43
|
+
* Public API for depositing funds in a specified account.
|
44
|
+
*/
|
45
|
+
if (self.accountBalances[accountAddress] + value < self.accountBalances[accountAddress]) {
|
46
|
+
return false;
|
47
|
+
}
|
48
|
+
addFunds(self, accountAddress, value);
|
49
|
+
return true;
|
50
|
+
}
|
51
|
+
|
52
|
+
event _Withdrawal(address indexed accountAddress, uint value);
|
53
|
+
|
54
|
+
/// @dev Function wrapper around the _Withdrawal event so that it can be used by contracts. Can be used to log a withdrawl from an account.
|
55
|
+
/// @param accountAddress The address of the account the funds were withdrawn from.
|
56
|
+
/// @param value The amount that was withdrawn to the account.
|
57
|
+
function Withdrawal(address accountAddress, uint value) public {
|
58
|
+
_Withdrawal(accountAddress, value);
|
59
|
+
}
|
60
|
+
|
61
|
+
event _InsufficientFunds(address indexed accountAddress, uint value, uint balance);
|
62
|
+
|
63
|
+
/// @dev Function wrapper around the _InsufficientFunds event so that it can be used by contracts. Can be used to log a failed withdrawl from an account.
|
64
|
+
/// @param accountAddress The address of the account the funds were to be withdrawn from.
|
65
|
+
/// @param value The amount that was attempted to be withdrawn from the account.
|
66
|
+
/// @param balance The current balance of the account.
|
67
|
+
function InsufficientFunds(address accountAddress, uint value, uint balance) public {
|
68
|
+
_InsufficientFunds(accountAddress, value, balance);
|
69
|
+
}
|
70
|
+
|
71
|
+
/// @dev Low level method for removing funds from an account. Protects against underflow.
|
72
|
+
/// @param self The Bank instance to operate on.
|
73
|
+
/// @param accountAddress The address of the account the funds should be deducted from.
|
74
|
+
/// @param value The amount that should be deducted from the account.
|
75
|
+
function deductFunds(Bank storage self, address accountAddress, uint value) public {
|
76
|
+
/*
|
77
|
+
* Helper function that should be used for any reduction of
|
78
|
+
* account funds. It has error checking to prevent
|
79
|
+
* underflowing the account balance which would be REALLY bad.
|
80
|
+
*/
|
81
|
+
if (value > self.accountBalances[accountAddress]) {
|
82
|
+
// Prevent Underflow.
|
83
|
+
throw;
|
84
|
+
}
|
85
|
+
self.accountBalances[accountAddress] -= value;
|
86
|
+
}
|
87
|
+
|
88
|
+
/// @dev Safe function for withdrawing funds. Returns boolean for whether the deposit was successful as well as sending the amount in ether to the account address.
|
89
|
+
/// @param self The Bank instance to operate on.
|
90
|
+
/// @param accountAddress The address of the account the funds should be withdrawn from.
|
91
|
+
/// @param value The amount that should be withdrawn from the account.
|
92
|
+
function withdraw(Bank storage self, address accountAddress, uint value) public returns (bool) {
|
93
|
+
/*
|
94
|
+
* Public API for withdrawing funds.
|
95
|
+
*/
|
96
|
+
if (self.accountBalances[accountAddress] >= value) {
|
97
|
+
deductFunds(self, accountAddress, value);
|
98
|
+
if (!accountAddress.send(value)) {
|
99
|
+
// Potentially sending money to a contract that
|
100
|
+
// has a fallback function. So instead, try
|
101
|
+
// tranferring the funds with the call api.
|
102
|
+
if (!accountAddress.call.value(value)()) {
|
103
|
+
// Revert the entire transaction. No
|
104
|
+
// need to destroy the funds.
|
105
|
+
//throw;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
return true;
|
109
|
+
}
|
110
|
+
return false;
|
111
|
+
}
|
112
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
contract AuditorRegistry {
|
2
|
+
|
3
|
+
address config;
|
4
|
+
Directory.AddressBoolMap auditors;
|
5
|
+
|
6
|
+
function CustodianRegistry(address _conf) {
|
7
|
+
config = _conf;
|
8
|
+
}
|
9
|
+
|
10
|
+
function isAuditor(address _audt) public returns (bool) {
|
11
|
+
return Directory.contains(auditors, _audt);
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import "contracts/Interface.sol";
|
2
|
+
import "contracts/Gold.sol";
|
3
|
+
import "contracts/GoldRegistry.sol";
|
4
|
+
|
5
|
+
contract CustodianInterface is Interface {
|
6
|
+
|
7
|
+
function CustodianInterface(address _config) {
|
8
|
+
owner = msg.sender;
|
9
|
+
config = _config;
|
10
|
+
}
|
11
|
+
|
12
|
+
function receiveFromVendor(address _gold, bytes32 _doc) ifemployee {
|
13
|
+
GoldRegistry(goldRegistry()).receiveFromVendor(_gold, _doc);
|
14
|
+
}
|
15
|
+
|
16
|
+
function transferCustodian(address _gold, address _cstdn) ifemployee {
|
17
|
+
}
|
18
|
+
|
19
|
+
function isRedeemable(address _gold) public returns (bool) {
|
20
|
+
return true;
|
21
|
+
}
|
22
|
+
|
23
|
+
}
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import "contracts/Directory.sol";
|
2
|
+
import "contracts/GenericRegistry.sol";
|
3
|
+
|
4
|
+
contract CustodianRegistry is GenericRegistry {
|
5
|
+
|
6
|
+
Directory.AddressBoolMap custodians;
|
7
|
+
|
8
|
+
struct Custodian {
|
9
|
+
bytes32 name;
|
10
|
+
}
|
11
|
+
|
12
|
+
mapping (address => Custodian) custodianNames;
|
13
|
+
|
14
|
+
function CustodianRegistry(address _conf) {
|
15
|
+
config = _conf;
|
16
|
+
}
|
17
|
+
|
18
|
+
function register(address _acct) ifadmin {
|
19
|
+
if (!Directory.insert(custodians, _acct))
|
20
|
+
throw;
|
21
|
+
}
|
22
|
+
|
23
|
+
function unregister(address _acct) ifadmin {
|
24
|
+
if (!Directory.remove(custodians, _acct))
|
25
|
+
throw;
|
26
|
+
}
|
27
|
+
|
28
|
+
function setCustodianName(address _cstdn, bytes32 _name) ifadmin {
|
29
|
+
custodianNames[_cstdn].name = _name;
|
30
|
+
}
|
31
|
+
|
32
|
+
function getCustodianName(address _cstdn) public returns (bytes32) {
|
33
|
+
return custodianNames[_cstdn].name;
|
34
|
+
}
|
35
|
+
|
36
|
+
function isCustodian(address _cust) public returns (bool) {
|
37
|
+
return Directory.contains(custodians, _cust);
|
38
|
+
}
|
39
|
+
|
40
|
+
}
|
@@ -0,0 +1,68 @@
|
|
1
|
+
contract DigixConfiguration {
|
2
|
+
|
3
|
+
address owner;
|
4
|
+
Directory.AddressBoolMap admins;
|
5
|
+
|
6
|
+
mapping (bytes32 => address) configaddr;
|
7
|
+
mapping (bytes32 => uint256) configint;
|
8
|
+
|
9
|
+
event SetOwner(address indexed owner, address indexed by);
|
10
|
+
event AddConfigEntryA(bytes32 indexed key, address indexed val, address indexed by);
|
11
|
+
event AddConfigEntryI(bytes32 indexed key, uint256 indexed val, address indexed by);
|
12
|
+
event RegisterAdmin(address indexed account, address indexed by);
|
13
|
+
event UnregisterAdmin(address indexed account, address indexed by);
|
14
|
+
|
15
|
+
function DigixConfiguration() {
|
16
|
+
owner = msg.sender;
|
17
|
+
}
|
18
|
+
|
19
|
+
modifier ifowner { if(msg.sender == owner) _ }
|
20
|
+
modifier ifadmin { if((msg.sender == owner) || isAdmin(msg.sender)) _ }
|
21
|
+
|
22
|
+
function getOwner() public constant returns (address) {
|
23
|
+
return owner;
|
24
|
+
}
|
25
|
+
|
26
|
+
function setOwner(address _newowner) ifowner {
|
27
|
+
address _oldaddress = owner;
|
28
|
+
owner = _newowner;
|
29
|
+
SetOwner(_newowner, msg.sender);
|
30
|
+
}
|
31
|
+
|
32
|
+
function addConfigEntryAddr(bytes32 _key, address _val) ifowner {
|
33
|
+
address _oldaddress = configaddr[_key];
|
34
|
+
configaddr[_key] = _val;
|
35
|
+
AddConfigEntryA(_key, _val, msg.sender);
|
36
|
+
}
|
37
|
+
|
38
|
+
function getConfigEntryAddr(bytes32 _key) public constant returns (address) {
|
39
|
+
return configaddr[_key];
|
40
|
+
}
|
41
|
+
|
42
|
+
function addConfigEntryInt(bytes32 _key, uint256 _val) ifowner {
|
43
|
+
uint256 _oldaddress = configint[_key];
|
44
|
+
configint[_key] = _val;
|
45
|
+
AddConfigEntryI(_key, _val, msg.sender);
|
46
|
+
}
|
47
|
+
|
48
|
+
function getConfigEntryInt(bytes32 _key) public constant returns (uint256) {
|
49
|
+
return configint[_key];
|
50
|
+
}
|
51
|
+
|
52
|
+
function registerAdmin(address _acct) ifowner {
|
53
|
+
if (!Directory.insert(admins, _acct))
|
54
|
+
throw;
|
55
|
+
RegisterAdmin(_acct, msg.sender);
|
56
|
+
}
|
57
|
+
|
58
|
+
function unregisterAdmin(address _acct) ifowner {
|
59
|
+
if (!Directory.remove(admins, _acct))
|
60
|
+
throw;
|
61
|
+
UnregisterAdmin(_acct, msg.sender);
|
62
|
+
}
|
63
|
+
|
64
|
+
function isAdmin(address _acct) public returns (bool) {
|
65
|
+
return Directory.contains(admins, _acct);
|
66
|
+
}
|
67
|
+
|
68
|
+
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
library Directory {
|
2
|
+
|
3
|
+
struct AddressBytesMap { mapping(address => bytes32) bytesentries; }
|
4
|
+
|
5
|
+
struct AddressAddressMap { mapping(address => address) addrentries; }
|
6
|
+
|
7
|
+
struct AddressBoolMap { mapping(address => bool) boolentries; }
|
8
|
+
|
9
|
+
function insert(AddressBytesMap storage self, address key, bytes32 val) returns (bool) {
|
10
|
+
if (self.bytesentries[key] == val) return false;
|
11
|
+
self.bytesentries[key] = val;
|
12
|
+
return true;
|
13
|
+
}
|
14
|
+
|
15
|
+
function insert(AddressBoolMap storage self, address key) returns (bool) {
|
16
|
+
if (self.boolentries[key]) return false;
|
17
|
+
self.boolentries[key] = true;
|
18
|
+
return true;
|
19
|
+
}
|
20
|
+
|
21
|
+
function insert(AddressAddressMap storage self, address key, address val) returns (bool) {
|
22
|
+
if (self.addrentries[key] == val) return false;
|
23
|
+
self.addrentries[key] = val;
|
24
|
+
return true;
|
25
|
+
}
|
26
|
+
|
27
|
+
function remove(AddressBytesMap storage self, address key) returns (bool) {
|
28
|
+
if (self.bytesentries[key] == 0x0) return false;
|
29
|
+
self.bytesentries[key] = 0x0;
|
30
|
+
return true;
|
31
|
+
}
|
32
|
+
|
33
|
+
function remove(AddressBoolMap storage self, address key) returns (bool) {
|
34
|
+
if (!self.boolentries[key]) return false;
|
35
|
+
self.boolentries[key] = false;
|
36
|
+
return true;
|
37
|
+
}
|
38
|
+
|
39
|
+
function remove(AddressAddressMap storage self, address key) returns (bool) {
|
40
|
+
if (self.addrentries[key] == 0x0000000000000000000000000000000000000000) return false;
|
41
|
+
self.addrentries[key] = 0x0000000000000000000000000000000000000000;
|
42
|
+
return true;
|
43
|
+
}
|
44
|
+
|
45
|
+
function contains(AddressBytesMap storage self, address key) returns (bool) {
|
46
|
+
if (self.bytesentries[key] != 0x0) return true;
|
47
|
+
}
|
48
|
+
|
49
|
+
function contains(AddressBoolMap storage self, address key) returns (bool) {
|
50
|
+
return self.boolentries[key];
|
51
|
+
}
|
52
|
+
|
53
|
+
function contains(AddressAddressMap storage self, address key) returns (bool) {
|
54
|
+
if (self.addrentries[key] != 0x0000000000000000000000000000000000000000) return true;
|
55
|
+
}
|
56
|
+
|
57
|
+
function containsAndMatches(AddressBytesMap storage self, address key, bytes32 val) returns (bool) {
|
58
|
+
return (self.bytesentries[key] == val);
|
59
|
+
}
|
60
|
+
|
61
|
+
function containsAndMatches(AddressAddressMap storage self, address key, address val) returns (bool) {
|
62
|
+
return (self.addrentries[key] == val);
|
63
|
+
}
|
64
|
+
|
65
|
+
}
|
66
|
+
|
67
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
library DoublyLinked {
|
2
|
+
|
3
|
+
struct List {
|
4
|
+
uint80 first;
|
5
|
+
uint80 last;
|
6
|
+
uint80 count;
|
7
|
+
Item[] items;
|
8
|
+
}
|
9
|
+
|
10
|
+
uint80 constant None = uint80(-1);
|
11
|
+
|
12
|
+
struct Item {
|
13
|
+
uint80 prev;
|
14
|
+
uint80 next;
|
15
|
+
bytes32 data;
|
16
|
+
}
|
17
|
+
|
18
|
+
function append(List storage self, bytes32 _data) {
|
19
|
+
var index = self.items.push(Item({prev: self.last, next: None, data: _data}));
|
20
|
+
if (self.last == None)
|
21
|
+
{
|
22
|
+
if (self.first != None || self.count != 0) throw;
|
23
|
+
self.first = self.last = uint80(index - 1);
|
24
|
+
self.count = 1;
|
25
|
+
}
|
26
|
+
else
|
27
|
+
{
|
28
|
+
self.items[self.last].next = uint80(index - 1);
|
29
|
+
self.last = uint80(index - 1);
|
30
|
+
self.count ++;
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
function remove(List storage self, uint80 _index) {
|
35
|
+
Item item = self.items[_index];
|
36
|
+
if (item.prev == None)
|
37
|
+
self.first = item.next;
|
38
|
+
if (item.next == None)
|
39
|
+
self.last = item.prev;
|
40
|
+
if (item.prev != None)
|
41
|
+
self.items[item.prev].next = item.next;
|
42
|
+
if (item.next != None)
|
43
|
+
self.items[item.next].prev = item.prev;
|
44
|
+
delete self.items[_index];
|
45
|
+
self.count++;
|
46
|
+
}
|
47
|
+
|
48
|
+
// Iterator interface
|
49
|
+
function iterate_start(List storage self) returns (uint80) { return self.first; }
|
50
|
+
function iterate_valid(List storage self, uint80 _index) returns (bool) { return _index < self.items.length; }
|
51
|
+
function iterate_prev(List storage self, uint80 _index) returns (uint80) { return self.items[_index].prev; }
|
52
|
+
function iterate_next(List storage self, uint80 _index) returns (uint80) { return self.items[_index].next; }
|
53
|
+
function iterate_get(List storage self, uint80 _index) returns (bytes32) { return self.items[_index].data; }
|
54
|
+
}
|