diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/asm/asm.go | 2 | ||||
-rw-r--r-- | core/asm/compiler.go | 2 | ||||
-rw-r--r-- | core/bench_test.go | 2 | ||||
-rw-r--r-- | core/block_validator_test.go | 2 | ||||
-rw-r--r-- | core/blockchain.go | 2 | ||||
-rw-r--r-- | core/blockchain_test.go | 2 | ||||
-rw-r--r-- | core/chain_makers_test.go | 2 | ||||
-rw-r--r-- | core/dao_test.go | 2 | ||||
-rw-r--r-- | core/evm.go | 2 | ||||
-rw-r--r-- | core/genesis.go | 2 | ||||
-rw-r--r-- | core/genesis_test.go | 2 | ||||
-rw-r--r-- | core/governance.go | 2 | ||||
-rw-r--r-- | core/headerchain.go | 6 | ||||
-rw-r--r-- | core/state_processor.go | 2 | ||||
-rw-r--r-- | core/state_transition.go | 17 | ||||
-rw-r--r-- | core/types.go | 2 | ||||
-rw-r--r-- | core/vm/common.go | 12 | ||||
-rw-r--r-- | core/vm/evm/analysis.go (renamed from core/vm/analysis.go) | 2 | ||||
-rw-r--r-- | core/vm/evm/analysis_test.go (renamed from core/vm/analysis_test.go) | 2 | ||||
-rw-r--r-- | core/vm/evm/contract.go (renamed from core/vm/contract.go) | 2 | ||||
-rw-r--r-- | core/vm/evm/contracts.go (renamed from core/vm/contracts.go) | 37 | ||||
-rw-r--r-- | core/vm/evm/contracts_test.go (renamed from core/vm/contracts_test.go) | 2 | ||||
-rw-r--r-- | core/vm/evm/doc.go (renamed from core/vm/doc.go) | 2 | ||||
-rw-r--r-- | core/vm/evm/evm.go (renamed from core/vm/evm.go) | 27 | ||||
-rw-r--r-- | core/vm/evm/evm_test.go (renamed from core/vm/evm_test.go) | 2 | ||||
-rw-r--r-- | core/vm/evm/gas.go (renamed from core/vm/gas.go) | 2 | ||||
-rw-r--r-- | core/vm/evm/gas_table.go (renamed from core/vm/gas_table.go) | 95 | ||||
-rw-r--r-- | core/vm/evm/gas_table_test.go (renamed from core/vm/gas_table_test.go) | 12 | ||||
-rw-r--r-- | core/vm/evm/gen_structlog.go (renamed from core/vm/gen_structlog.go) | 2 | ||||
-rw-r--r-- | core/vm/evm/governance.go | 2198 | ||||
-rw-r--r-- | core/vm/evm/governance_abi.go | 1133 | ||||
-rw-r--r-- | core/vm/evm/governance_test.go | 1060 | ||||
-rw-r--r-- | core/vm/evm/instructions.go (renamed from core/vm/instructions.go) | 517 | ||||
-rw-r--r-- | core/vm/evm/instructions_test.go (renamed from core/vm/instructions_test.go) | 87 | ||||
-rw-r--r-- | core/vm/evm/interface.go (renamed from core/vm/interface.go) | 2 | ||||
-rw-r--r-- | core/vm/evm/interpreter.go (renamed from core/vm/interpreter.go) | 31 | ||||
-rw-r--r-- | core/vm/evm/jump_table.go (renamed from core/vm/jump_table.go) | 292 | ||||
-rw-r--r-- | core/vm/evm/logger.go (renamed from core/vm/logger.go) | 23 | ||||
-rw-r--r-- | core/vm/evm/logger_json.go (renamed from core/vm/logger_json.go) | 9 | ||||
-rw-r--r-- | core/vm/evm/logger_test.go (renamed from core/vm/logger_test.go) | 11 | ||||
-rw-r--r-- | core/vm/evm/memory_table.go | 98 | ||||
-rw-r--r-- | core/vm/evm/opcodes.go (renamed from core/vm/opcodes.go) | 2 | ||||
-rw-r--r-- | core/vm/evm/runtime/doc.go (renamed from core/vm/runtime/doc.go) | 0 | ||||
-rw-r--r-- | core/vm/evm/runtime/env.go (renamed from core/vm/runtime/env.go) | 2 | ||||
-rw-r--r-- | core/vm/evm/runtime/fuzz.go (renamed from core/vm/runtime/fuzz.go) | 0 | ||||
-rw-r--r-- | core/vm/evm/runtime/runtime.go (renamed from core/vm/runtime/runtime.go) | 2 | ||||
-rw-r--r-- | core/vm/evm/runtime/runtime_example_test.go (renamed from core/vm/runtime/runtime_example_test.go) | 2 | ||||
-rw-r--r-- | core/vm/evm/runtime/runtime_test.go (renamed from core/vm/runtime/runtime_test.go) | 2 | ||||
-rw-r--r-- | core/vm/evm/stack.go | 24 | ||||
-rw-r--r-- | core/vm/int_pool_verifier.go | 4 | ||||
-rw-r--r-- | core/vm/int_pool_verifier_empty.go | 4 | ||||
-rw-r--r-- | core/vm/intpool.go | 74 | ||||
-rw-r--r-- | core/vm/intpool_test.go | 26 | ||||
-rw-r--r-- | core/vm/memory.go | 48 | ||||
-rw-r--r-- | core/vm/memory_table.go | 97 | ||||
-rw-r--r-- | core/vm/oracle_contracts.go | 2 | ||||
-rw-r--r-- | core/vm/stack.go | 69 | ||||
-rw-r--r-- | core/vm/stack_table.go | 20 |
58 files changed, 5250 insertions, 839 deletions
diff --git a/core/asm/asm.go b/core/asm/asm.go index 8dbb45ed3..164f3c29e 100644 --- a/core/asm/asm.go +++ b/core/asm/asm.go @@ -21,7 +21,7 @@ import ( "encoding/hex" "fmt" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" ) // Iterator for disassembled EVM instructions diff --git a/core/asm/compiler.go b/core/asm/compiler.go index b1c7c76f0..9a2f4a9aa 100644 --- a/core/asm/compiler.go +++ b/core/asm/compiler.go @@ -23,7 +23,7 @@ import ( "strings" "github.com/dexon-foundation/dexon/common/math" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" ) // Compiler contains information about the parsed source diff --git a/core/bench_test.go b/core/bench_test.go index c9a9bf735..98d46176a 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -28,7 +28,7 @@ import ( "github.com/dexon-foundation/dexon/consensus/ethash" "github.com/dexon-foundation/dexon/core/rawdb" "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" diff --git a/core/block_validator_test.go b/core/block_validator_test.go index f22653aca..5ae85c796 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -23,7 +23,7 @@ import ( "github.com/dexon-foundation/dexon/consensus/ethash" "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" ) diff --git a/core/blockchain.go b/core/blockchain.go index c243c8fc5..8037834c1 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -41,7 +41,7 @@ import ( "github.com/dexon-foundation/dexon/core/rawdb" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/event" diff --git a/core/blockchain_test.go b/core/blockchain_test.go index f8956da46..c760252d8 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -34,7 +34,7 @@ import ( "github.com/dexon-foundation/dexon/core/rawdb" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 97896e87d..78c242df1 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -22,7 +22,7 @@ import ( "github.com/dexon-foundation/dexon/consensus/ethash" "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" diff --git a/core/dao_test.go b/core/dao_test.go index 785aab5f2..7e437c1d9 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -21,7 +21,7 @@ import ( "testing" "github.com/dexon-foundation/dexon/consensus/ethash" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" ) diff --git a/core/evm.go b/core/evm.go index a2b61c535..83a789131 100644 --- a/core/evm.go +++ b/core/evm.go @@ -23,7 +23,7 @@ import ( "github.com/dexon-foundation/dexon/consensus" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" ) // ChainContext supports retrieving headers and consensus parameters from the diff --git a/core/genesis.go b/core/genesis.go index 48e1466e1..8f308d7dd 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -32,7 +32,7 @@ import ( "github.com/dexon-foundation/dexon/core/rawdb" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/log" "github.com/dexon-foundation/dexon/params" diff --git a/core/genesis_test.go b/core/genesis_test.go index 16958eac3..718f65e9d 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -25,7 +25,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/consensus/ethash" "github.com/dexon-foundation/dexon/core/rawdb" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" ) diff --git a/core/governance.go b/core/governance.go index 277b3bb89..5344479ff 100644 --- a/core/governance.go +++ b/core/governance.go @@ -18,7 +18,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/state" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/log" ) diff --git a/core/headerchain.go b/core/headerchain.go index ef77aa28a..07a6f9d55 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -37,7 +37,7 @@ import ( "github.com/dexon-foundation/dexon/consensus/dexcon" "github.com/dexon-foundation/dexon/core/rawdb" "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/log" @@ -421,9 +421,9 @@ func newHeaderVerifierCache( } } -func (c *headerVerifierCache) state(round uint64) *vm.GovernanceState { +func (c *headerVerifierCache) state(round uint64) *evm.GovernanceState { if state, exist := c.stateCache.Get(round); exist { - return state.(*vm.GovernanceState) + return state.(*evm.GovernanceState) } state := c.gov.GetStateForConfigAtRound(round) c.stateCache.Add(round, state) diff --git a/core/state_processor.go b/core/state_processor.go index eaeb36f78..ff2d5fbe4 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -22,7 +22,7 @@ import ( "github.com/dexon-foundation/dexon/consensus/misc" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/params" ) diff --git a/core/state_transition.go b/core/state_transition.go index f5ac9bde6..fddb187af 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -26,6 +26,7 @@ import ( dexCore "github.com/dexon-foundation/dexon-consensus/core" "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/log" "github.com/dexon-foundation/dexon/params" ) @@ -69,8 +70,8 @@ type StateTransition struct { initialGas uint64 value *big.Int data []byte - state vm.StateDB - evm *vm.EVM + state evm.StateDB + evm *evm.EVM } // Message represents a message sent to a contract. @@ -122,7 +123,7 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error) } // NewStateTransition initialises and returns a new state transition object. -func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { +func NewStateTransition(evm *evm.EVM, msg Message, gp *GasPool) *StateTransition { return &StateTransition{ gp: gp, evm: evm, @@ -141,7 +142,7 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition // the gas used (which includes gas refunds) and an error if it failed. An error always // indicates a core error meaning that the message would always fail for that particular // state and would never be accepted within a block. -func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, uint64, bool, error) { +func ApplyMessage(evm *evm.EVM, msg Message, gp *GasPool) ([]byte, uint64, bool, error) { return NewStateTransition(evm, msg, gp).TransitionDb() } @@ -205,7 +206,7 @@ func (st *StateTransition) inExtendedRound() bool { } } - gs := vm.GovernanceState{st.state} + gs := evm.GovernanceState{st.state} round := st.evm.Round.Uint64() if round < dexCore.ConfigRoundShift { @@ -219,7 +220,7 @@ func (st *StateTransition) inExtendedRound() bool { if err != nil { panic(err) } - rgs := vm.GovernanceState{state} + rgs := evm.GovernanceState{state} roundEnd := gs.RoundHeight(st.evm.Round).Uint64() + rgs.RoundLength().Uint64() @@ -245,7 +246,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo return } msg := st.msg - sender := vm.AccountRef(msg.From()) + sender := evm.AccountRef(msg.From()) homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) contractCreation := msg.To() == nil @@ -290,7 +291,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo receiver := st.evm.Coinbase if !*legacyEvm && st.inExtendedRound() { - gs := vm.GovernanceState{st.state} + gs := evm.GovernanceState{st.state} receiver = gs.Owner() } diff --git a/core/types.go b/core/types.go index 04a787b1e..b020a5df7 100644 --- a/core/types.go +++ b/core/types.go @@ -20,7 +20,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" ) // Validator is an interface which defines the standard for block validation. It diff --git a/core/vm/common.go b/core/vm/common.go index 7702b2a86..6b8c4667b 100644 --- a/core/vm/common.go +++ b/core/vm/common.go @@ -24,7 +24,7 @@ import ( ) // calculates the memory size required for a step -func calcMemSize(off, l *big.Int) *big.Int { +func CalcMemSize(off, l *big.Int) *big.Int { if l.Sign() == 0 { return common.Big0 } @@ -34,7 +34,7 @@ func calcMemSize(off, l *big.Int) *big.Int { // getData returns a slice from the data based on the start and size and pads // up to size with zero's. This function is overflow safe. -func getData(data []byte, start uint64, size uint64) []byte { +func GetData(data []byte, start uint64, size uint64) []byte { length := uint64(len(data)) if start > length { start = length @@ -48,7 +48,7 @@ func getData(data []byte, start uint64, size uint64) []byte { // getDataBig returns a slice from the data based on the start and size and pads // up to size with zero's. This function is overflow safe. -func getDataBig(data []byte, start *big.Int, size *big.Int) []byte { +func GetDataBig(data []byte, start *big.Int, size *big.Int) []byte { dlen := big.NewInt(int64(len(data))) s := math.BigMin(start, dlen) @@ -58,12 +58,12 @@ func getDataBig(data []byte, start *big.Int, size *big.Int) []byte { // bigUint64 returns the integer casted to a uint64 and returns whether it // overflowed in the process. -func bigUint64(v *big.Int) (uint64, bool) { +func BigUint64(v *big.Int) (uint64, bool) { return v.Uint64(), v.BitLen() > 64 } // toWordSize returns the ceiled word size required for memory expansion. -func toWordSize(size uint64) uint64 { +func ToWordSize(size uint64) uint64 { if size > math.MaxUint64-31 { return math.MaxUint64/32 + 1 } @@ -71,7 +71,7 @@ func toWordSize(size uint64) uint64 { return (size + 31) / 32 } -func allZero(b []byte) bool { +func AllZero(b []byte) bool { for _, byte := range b { if byte != 0 { return false diff --git a/core/vm/analysis.go b/core/vm/evm/analysis.go index 0ccf47b97..5e430f965 100644 --- a/core/vm/analysis.go +++ b/core/vm/evm/analysis.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm // bitvec is a bit vector which maps bytes in a program. // An unset bit means the byte is an opcode, a set bit means diff --git a/core/vm/analysis_test.go b/core/vm/evm/analysis_test.go index c4fe93474..6805f6076 100644 --- a/core/vm/analysis_test.go +++ b/core/vm/evm/analysis_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "testing" diff --git a/core/vm/contract.go b/core/vm/evm/contract.go index 751da072e..a7ce2ddfd 100644 --- a/core/vm/contract.go +++ b/core/vm/evm/contract.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "math/big" diff --git a/core/vm/contracts.go b/core/vm/evm/contracts.go index ac8fd22df..52bb0a83b 100644 --- a/core/vm/contracts.go +++ b/core/vm/evm/contracts.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "crypto/sha256" @@ -23,6 +23,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/common/math" + "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/crypto/bn256" "github.com/dexon-foundation/dexon/params" @@ -65,7 +66,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contr if contract.UseGas(gas) { return p.Run(input) } - return nil, ErrOutOfGas + return nil, vm.ErrOutOfGas } // ECRECOVER implemented as a native contract. @@ -87,7 +88,7 @@ func (c *ecrecover) Run(input []byte) ([]byte, error) { v := input[63] - 27 // tighter sig s values input homestead only apply to tx sigs - if !allZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) { + if !vm.AllZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) { return nil, nil } // v needs to be at the end for libsecp256k1 @@ -166,9 +167,9 @@ var ( // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bigModExp) RequiredGas(input []byte) uint64 { var ( - baseLen = new(big.Int).SetBytes(getData(input, 0, 32)) - expLen = new(big.Int).SetBytes(getData(input, 32, 32)) - modLen = new(big.Int).SetBytes(getData(input, 64, 32)) + baseLen = new(big.Int).SetBytes(vm.GetData(input, 0, 32)) + expLen = new(big.Int).SetBytes(vm.GetData(input, 32, 32)) + modLen = new(big.Int).SetBytes(vm.GetData(input, 64, 32)) ) if len(input) > 96 { input = input[96:] @@ -181,9 +182,9 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { expHead = new(big.Int) } else { if expLen.Cmp(big32) > 0 { - expHead = new(big.Int).SetBytes(getData(input, baseLen.Uint64(), 32)) + expHead = new(big.Int).SetBytes(vm.GetData(input, baseLen.Uint64(), 32)) } else { - expHead = new(big.Int).SetBytes(getData(input, baseLen.Uint64(), expLen.Uint64())) + expHead = new(big.Int).SetBytes(vm.GetData(input, baseLen.Uint64(), expLen.Uint64())) } } // Calculate the adjusted exponent length @@ -225,9 +226,9 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { func (c *bigModExp) Run(input []byte) ([]byte, error) { var ( - baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() - expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() - modLen = new(big.Int).SetBytes(getData(input, 64, 32)).Uint64() + baseLen = new(big.Int).SetBytes(vm.GetData(input, 0, 32)).Uint64() + expLen = new(big.Int).SetBytes(vm.GetData(input, 32, 32)).Uint64() + modLen = new(big.Int).SetBytes(vm.GetData(input, 64, 32)).Uint64() ) if len(input) > 96 { input = input[96:] @@ -240,9 +241,9 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) { } // Retrieve the operands and execute the exponentiation var ( - base = new(big.Int).SetBytes(getData(input, 0, baseLen)) - exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) - mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) + base = new(big.Int).SetBytes(vm.GetData(input, 0, baseLen)) + exp = new(big.Int).SetBytes(vm.GetData(input, baseLen, expLen)) + mod = new(big.Int).SetBytes(vm.GetData(input, baseLen+expLen, modLen)) ) if mod.BitLen() == 0 { // Modulo 0 is undefined, return zero @@ -280,11 +281,11 @@ func (c *bn256Add) RequiredGas(input []byte) uint64 { } func (c *bn256Add) Run(input []byte) ([]byte, error) { - x, err := newCurvePoint(getData(input, 0, 64)) + x, err := newCurvePoint(vm.GetData(input, 0, 64)) if err != nil { return nil, err } - y, err := newCurvePoint(getData(input, 64, 64)) + y, err := newCurvePoint(vm.GetData(input, 64, 64)) if err != nil { return nil, err } @@ -302,12 +303,12 @@ func (c *bn256ScalarMul) RequiredGas(input []byte) uint64 { } func (c *bn256ScalarMul) Run(input []byte) ([]byte, error) { - p, err := newCurvePoint(getData(input, 0, 64)) + p, err := newCurvePoint(vm.GetData(input, 0, 64)) if err != nil { return nil, err } res := new(bn256.G1) - res.ScalarMult(p, new(big.Int).SetBytes(getData(input, 64, 32))) + res.ScalarMult(p, new(big.Int).SetBytes(vm.GetData(input, 64, 32))) return res.Marshal(), nil } diff --git a/core/vm/contracts_test.go b/core/vm/evm/contracts_test.go index f0090fcce..4b43f777b 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/evm/contracts_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "fmt" diff --git a/core/vm/doc.go b/core/vm/evm/doc.go index 5864d0cfa..27986e0c4 100644 --- a/core/vm/doc.go +++ b/core/vm/evm/doc.go @@ -21,4 +21,4 @@ The vm package implements one EVM, a byte code VM. The BC (Byte Code) VM loops over a set of bytes and executes them according to the set of rules defined in the Ethereum yellow paper. */ -package vm +package evm diff --git a/core/vm/evm.go b/core/vm/evm/evm.go index baf3a0ac9..11d25792e 100644 --- a/core/vm/evm.go +++ b/core/vm/evm/evm.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "math/big" @@ -23,6 +23,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/state" + "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/params" ) @@ -72,7 +73,7 @@ func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, err return interpreter.Run(contract, input, readOnly) } } - return nil, ErrNoCompatibleInterpreter + return nil, vm.ErrNoCompatibleInterpreter } // Context provides the EVM with auxiliary information. Once provided @@ -201,11 +202,11 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { - return nil, gas, ErrDepth + return nil, gas, vm.ErrDepth } // Fail if we're trying to transfer more than the available balance if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { - return nil, gas, ErrInsufficientBalance + return nil, gas, vm.ErrInsufficientBalance } var ( @@ -273,11 +274,11 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { - return nil, gas, ErrDepth + return nil, gas, vm.ErrDepth } // Fail if we're trying to transfer more than the available balance if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { - return nil, gas, ErrInsufficientBalance + return nil, gas, vm.ErrInsufficientBalance } var ( @@ -311,7 +312,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by } // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { - return nil, gas, ErrDepth + return nil, gas, vm.ErrDepth } var ( @@ -343,7 +344,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte } // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { - return nil, gas, ErrDepth + return nil, gas, vm.ErrDepth } var ( @@ -392,10 +393,10 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // Depth check execution. Fail if we're trying to execute above the // limit. if evm.depth > int(params.CallCreateDepth) { - return nil, common.Address{}, gas, ErrDepth + return nil, common.Address{}, gas, vm.ErrDepth } if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { - return nil, common.Address{}, gas, ErrInsufficientBalance + return nil, common.Address{}, gas, vm.ErrInsufficientBalance } nonce := evm.StateDB.GetNonce(caller.Address()) evm.StateDB.SetNonce(caller.Address(), nonce+1) @@ -403,7 +404,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // Ensure there's no existing contract already at the designated address contractHash := evm.StateDB.GetCodeHash(address) if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) { - return nil, common.Address{}, 0, ErrContractAddressCollision + return nil, common.Address{}, 0, vm.ErrContractAddressCollision } // Create a new account on the state snapshot := evm.StateDB.Snapshot() @@ -441,14 +442,14 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if contract.UseGas(createDataGas) { evm.StateDB.SetCode(address, ret) } else { - err = ErrCodeStoreOutOfGas + err = vm.ErrCodeStoreOutOfGas } } // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in homestead this also counts for code storage gas errors. - if maxCodeSizeExceeded || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) { + if maxCodeSizeExceeded || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != vm.ErrCodeStoreOutOfGas)) { evm.StateDB.RevertToSnapshot(snapshot) if err != errExecutionReverted { contract.UseGas(contract.Gas) diff --git a/core/vm/evm_test.go b/core/vm/evm/evm_test.go index 4b2714351..2e382c15f 100644 --- a/core/vm/evm_test.go +++ b/core/vm/evm/evm_test.go @@ -15,7 +15,7 @@ // along with the dexon-consensus library. If not, see // <http://www.gnu.org/licenses/>. -package vm +package evm import ( "fmt" diff --git a/core/vm/gas.go b/core/vm/evm/gas.go index 52c3b02f1..edd772423 100644 --- a/core/vm/gas.go +++ b/core/vm/evm/gas.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "math/big" diff --git a/core/vm/gas_table.go b/core/vm/evm/gas_table.go index 0126e26d4..0087004cf 100644 --- a/core/vm/gas_table.go +++ b/core/vm/evm/gas_table.go @@ -14,17 +14,18 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/common/math" + "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/params" ) // memoryGasCosts calculates the quadratic gas for memory expansion. It does so // only for the memory region that is expanded, not the total memory. -func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { +func memoryGasCost(mem *vm.Memory, newMemSize uint64) (uint64, error) { if newMemSize == 0 { return 0, nil @@ -40,7 +41,7 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { return 0, errGasUintOverflow } - newMemSizeWords := toWordSize(newMemSize) + newMemSizeWords := vm.ToWordSize(newMemSize) newMemSize = newMemSizeWords * 32 if newMemSize > uint64(mem.Len()) { @@ -49,8 +50,8 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { quadCoef := square / params.QuadCoeffDiv newTotalFee := linCoef + quadCoef - fee := newTotalFee - mem.lastGasCost - mem.lastGasCost = newTotalFee + fee := newTotalFee - mem.LastGasCost + mem.LastGasCost = newTotalFee return fee, nil } @@ -58,12 +59,12 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { } func constGasFunc(gas uint64) gasFunc { - return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return func(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return gas, nil } } -func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err @@ -74,12 +75,12 @@ func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *St return 0, errGasUintOverflow } - words, overflow := bigUint64(stack.Back(2)) + words, overflow := vm.BigUint64(stack.Back(2)) if overflow { return 0, errGasUintOverflow } - if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { + if words, overflow = math.SafeMul(vm.ToWordSize(words), params.CopyGas); overflow { return 0, errGasUintOverflow } @@ -89,7 +90,7 @@ func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *St return gas, nil } -func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err @@ -100,12 +101,12 @@ func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack * return 0, errGasUintOverflow } - words, overflow := bigUint64(stack.Back(2)) + words, overflow := vm.BigUint64(stack.Back(2)) if overflow { return 0, errGasUintOverflow } - if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { + if words, overflow = math.SafeMul(vm.ToWordSize(words), params.CopyGas); overflow { return 0, errGasUintOverflow } @@ -115,7 +116,7 @@ func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack * return gas, nil } -func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var ( y, x = stack.Back(1), stack.Back(0) current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x)) @@ -185,8 +186,8 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m } func makeGasLog(n uint64) gasFunc { - return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - requestedSize, overflow := bigUint64(stack.Back(1)) + return func(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { + requestedSize, overflow := vm.BigUint64(stack.Back(1)) if overflow { return 0, errGasUintOverflow } @@ -214,7 +215,7 @@ func makeGasLog(n uint64) gasFunc { } } -func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var overflow bool gas, err := memoryGasCost(mem, memorySize) if err != nil { @@ -225,11 +226,11 @@ func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem return 0, errGasUintOverflow } - wordGas, overflow := bigUint64(stack.Back(1)) + wordGas, overflow := vm.BigUint64(stack.Back(1)) if overflow { return 0, errGasUintOverflow } - if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow { + if wordGas, overflow = math.SafeMul(vm.ToWordSize(wordGas), params.Sha3WordGas); overflow { return 0, errGasUintOverflow } if gas, overflow = math.SafeAdd(gas, wordGas); overflow { @@ -238,7 +239,7 @@ func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem return gas, nil } -func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err @@ -249,11 +250,11 @@ func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, return 0, errGasUintOverflow } - wordGas, overflow := bigUint64(stack.Back(2)) + wordGas, overflow := vm.BigUint64(stack.Back(2)) if overflow { return 0, errGasUintOverflow } - if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow { + if wordGas, overflow = math.SafeMul(vm.ToWordSize(wordGas), params.CopyGas); overflow { return 0, errGasUintOverflow } if gas, overflow = math.SafeAdd(gas, wordGas); overflow { @@ -262,7 +263,7 @@ func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, return gas, nil } -func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err @@ -273,12 +274,12 @@ func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Sta return 0, errGasUintOverflow } - wordGas, overflow := bigUint64(stack.Back(3)) + wordGas, overflow := vm.BigUint64(stack.Back(3)) if overflow { return 0, errGasUintOverflow } - if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow { + if wordGas, overflow = math.SafeMul(vm.ToWordSize(wordGas), params.CopyGas); overflow { return 0, errGasUintOverflow } @@ -288,11 +289,11 @@ func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Sta return gas, nil } -func gasExtCodeHash(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasExtCodeHash(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return gt.ExtcodeHash, nil } -func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var overflow bool gas, err := memoryGasCost(mem, memorySize) if err != nil { @@ -304,7 +305,7 @@ func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, me return gas, nil } -func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var overflow bool gas, err := memoryGasCost(mem, memorySize) if err != nil { @@ -316,7 +317,7 @@ func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, return gas, nil } -func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var overflow bool gas, err := memoryGasCost(mem, memorySize) if err != nil { @@ -328,7 +329,7 @@ func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m return gas, nil } -func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var overflow bool gas, err := memoryGasCost(mem, memorySize) if err != nil { @@ -340,7 +341,7 @@ func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m return gas, nil } -func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var overflow bool gas, err := memoryGasCost(mem, memorySize) if err != nil { @@ -349,11 +350,11 @@ func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, if gas, overflow = math.SafeAdd(gas, params.Create2Gas); overflow { return 0, errGasUintOverflow } - wordGas, overflow := bigUint64(stack.Back(2)) + wordGas, overflow := vm.BigUint64(stack.Back(2)) if overflow { return 0, errGasUintOverflow } - if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow { + if wordGas, overflow = math.SafeMul(vm.ToWordSize(wordGas), params.Sha3WordGas); overflow { return 0, errGasUintOverflow } if gas, overflow = math.SafeAdd(gas, wordGas); overflow { @@ -363,20 +364,20 @@ func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, return gas, nil } -func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return gt.Balance, nil } -func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return gt.ExtcodeSize, nil } -func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return gt.SLoad, nil } -func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) +func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { + expByteLen := uint64((stack.Data[stack.Len()-2].BitLen() + 7) / 8) var ( gas = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas @@ -388,7 +389,7 @@ func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem return gas, nil } -func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var ( gas = gt.Calls transfersValue = stack.Back(2).Sign() != 0 @@ -424,7 +425,7 @@ func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem return gas, nil } -func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { gas := gt.Calls if stack.Back(2).Sign() != 0 { gas += params.CallValueTransferGas @@ -448,15 +449,15 @@ func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, return gas, nil } -func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return memoryGasCost(mem, memorySize) } -func gasRevert(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasRevert(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return memoryGasCost(mem, memorySize) } -func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var gas uint64 // EIP150 homestead gas reprice fork: if evm.ChainConfig().IsEIP150(evm.BlockNumber) { @@ -482,7 +483,7 @@ func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, return gas, nil } -func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err @@ -502,7 +503,7 @@ func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *St return gas, nil } -func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err @@ -522,14 +523,14 @@ func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stac return gas, nil } -func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return GasFastestStep, nil } -func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return GasFastestStep, nil } -func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return GasFastestStep, nil } diff --git a/core/vm/gas_table_test.go b/core/vm/evm/gas_table_test.go index 1b91aee56..35a902c67 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/evm/gas_table_test.go @@ -14,14 +14,18 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm -import "testing" +import ( + "testing" + + "github.com/dexon-foundation/dexon/core/vm" +) func TestMemoryGasCost(t *testing.T) { //size := uint64(math.MaxUint64 - 64) size := uint64(0xffffffffe0) - v, err := memoryGasCost(&Memory{}, size) + v, err := memoryGasCost(&vm.Memory{}, size) if err != nil { t.Error("didn't expect error:", err) } @@ -29,7 +33,7 @@ func TestMemoryGasCost(t *testing.T) { t.Errorf("Expected: 36028899963961341, got %d", v) } - _, err = memoryGasCost(&Memory{}, size+1) + _, err = memoryGasCost(&vm.Memory{}, size+1) if err == nil { t.Error("expected error") } diff --git a/core/vm/gen_structlog.go b/core/vm/evm/gen_structlog.go index a3da8734f..600af4b52 100644 --- a/core/vm/gen_structlog.go +++ b/core/vm/evm/gen_structlog.go @@ -1,6 +1,6 @@ // Code generated by github.com/fjl/gencodec. DO NOT EDIT. -package vm +package evm import ( "encoding/json" diff --git a/core/vm/evm/governance.go b/core/vm/evm/governance.go new file mode 100644 index 000000000..8b31d3a01 --- /dev/null +++ b/core/vm/evm/governance.go @@ -0,0 +1,2198 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus library is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The dexon-consensus library is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the dexon-consensus library. If not, see +// <http://www.gnu.org/licenses/>. + +package evm + +import ( + "bytes" + "errors" + "math/big" + "sort" + "strings" + + "github.com/dexon-foundation/dexon/accounts/abi" + "github.com/dexon-foundation/dexon/common" + "github.com/dexon-foundation/dexon/core/types" + "github.com/dexon-foundation/dexon/crypto" + "github.com/dexon-foundation/dexon/params" + "github.com/dexon-foundation/dexon/rlp" + + coreCommon "github.com/dexon-foundation/dexon-consensus/common" + "github.com/dexon-foundation/dexon-consensus/core" + coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" + coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils" + "github.com/dexon-foundation/dexon/core/vm" + + "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" + coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" + dkgTypes "github.com/dexon-foundation/dexon-consensus/core/types/dkg" +) + +var GovernanceContractAddress = common.HexToAddress("63751838d6485578b23e8b051d40861ecc416794") + +var abiObject abi.ABI +var GovernanceContractName2Method map[string]abi.Method +var sig2Method map[string]abi.Method +var events map[string]abi.Event + +type Bytes32 [32]byte + +type ReportType uint64 + +const ( + ReportTypeInvalidDKG = iota + ReportTypeForkVote + ReportTypeForkBlock +) + +func init() { + var err error + + // Parse governance contract ABI. + abiObject, err = abi.JSON(strings.NewReader(GovernanceABIJSON)) + if err != nil { + panic(err) + } + + sig2Method = make(map[string]abi.Method) + GovernanceContractName2Method = make(map[string]abi.Method) + + // Construct dispatch table. + for _, method := range abiObject.Methods { + sig2Method[string(method.Id())] = method + GovernanceContractName2Method[method.Name] = method + } + + events = make(map[string]abi.Event) + + // Event cache. + for _, event := range abiObject.Events { + events[event.Name] = event + } +} + +// RunGovernanceContract executes governance contract. +func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (ret []byte, err error) { + if len(input) < 4 { + return nil, nil + } + + // Parse input. + method, exists := sig2Method[string(input[:4])] + if !exists { + return nil, errExecutionReverted + } + + // Dispatch method call. + g := newGovernanceContract(evm, contract) + arguments := input[4:] + + switch method.Name { + case "addDKGComplaint": + args := struct { + Round *big.Int + Complaint []byte + }{} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + return g.addDKGComplaint(args.Round, args.Complaint) + case "addDKGMasterPublicKey": + args := struct { + Round *big.Int + PublicKey []byte + }{} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + return g.addDKGMasterPublicKey(args.Round, args.PublicKey) + case "addDKGMPKReady": + args := struct { + Round *big.Int + MPKReady []byte + }{} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + return g.addDKGMPKReady(args.Round, args.MPKReady) + case "addDKGFinalize": + args := struct { + Round *big.Int + Finalize []byte + }{} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + return g.addDKGFinalize(args.Round, args.Finalize) + case "delegate": + address := common.Address{} + if err := method.Inputs.Unpack(&address, arguments); err != nil { + return nil, errExecutionReverted + } + return g.delegate(address) + case "delegatorsLength": + address := common.Address{} + if err := method.Inputs.Unpack(&address, arguments); err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(g.state.LenDelegators(address)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "nodesLength": + res, err := method.Outputs.Pack(g.state.LenNodes()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "payFine": + address := common.Address{} + if err := method.Inputs.Unpack(&address, arguments); err != nil { + return nil, errExecutionReverted + } + return g.payFine(address) + case "proposeCRS": + args := struct { + Round *big.Int + SignedCRS []byte + }{} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + return g.proposeCRS(args.Round, args.SignedCRS) + case "report": + args := struct { + Type *big.Int + Arg1 []byte + Arg2 []byte + }{} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + return g.report(args.Type, args.Arg1, args.Arg2) + case "stake": + args := struct { + PublicKey []byte + Name string + Email string + Location string + Url string + }{} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + return g.stake(args.PublicKey, args.Name, args.Email, args.Location, args.Url) + case "snapshotRound": + args := struct { + Round *big.Int + Height *big.Int + }{} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + return g.snapshotRound(args.Round, args.Height) + case "transferOwnership": + var newOwner common.Address + if err := method.Inputs.Unpack(&newOwner, arguments); err != nil { + return nil, errExecutionReverted + } + return g.transferOwnership(newOwner) + case "undelegate": + address := common.Address{} + if err := method.Inputs.Unpack(&address, arguments); err != nil { + return nil, errExecutionReverted + } + return g.undelegate(address) + case "unstake": + return g.unstake() + case "updateConfiguration": + var cfg rawConfigStruct + if err := method.Inputs.Unpack(&cfg, arguments); err != nil { + return nil, errExecutionReverted + } + return g.updateConfiguration(&cfg) + case "withdraw": + address := common.Address{} + if err := method.Inputs.Unpack(&address, arguments); err != nil { + return nil, errExecutionReverted + } + return g.withdraw(address) + + // -------------------------------- + // Solidity auto generated methods. + // -------------------------------- + + case "blockGasLimit": + res, err := method.Outputs.Pack(g.state.BlockGasLimit()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "crs": + round := new(big.Int) + if err := method.Inputs.Unpack(&round, arguments); err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(g.state.CRS(round)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "delegators": + nodeAddr, index := common.Address{}, new(big.Int) + args := []interface{}{&nodeAddr, &index} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + delegator := g.state.Delegator(nodeAddr, index) + res, err := method.Outputs.Pack(delegator.Owner, delegator.Value, delegator.UndelegatedAt) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "delegatorsOffset": + nodeAddr, delegatorAddr := common.Address{}, common.Address{} + args := []interface{}{&nodeAddr, &delegatorAddr} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(g.state.DelegatorsOffset(nodeAddr, delegatorAddr)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgComplaints": + round, index := new(big.Int), new(big.Int) + args := []interface{}{&round, &index} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + complaints := g.state.DKGComplaints(round) + if int(index.Uint64()) >= len(complaints) { + return nil, errExecutionReverted + } + complaint := complaints[index.Uint64()] + res, err := method.Outputs.Pack(complaint) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgReadys": + round, addr := new(big.Int), common.Address{} + args := []interface{}{&round, &addr} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + ready := g.state.DKGMPKReady(round, addr) + res, err := method.Outputs.Pack(ready) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgReadysCount": + round := new(big.Int) + if err := method.Inputs.Unpack(&round, arguments); err != nil { + return nil, errExecutionReverted + } + count := g.state.DKGMPKReadysCount(round) + res, err := method.Outputs.Pack(count) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + + case "dkgFinalizeds": + round, addr := new(big.Int), common.Address{} + args := []interface{}{&round, &addr} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + finalized := g.state.DKGFinalized(round, addr) + res, err := method.Outputs.Pack(finalized) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgFinalizedsCount": + round := new(big.Int) + if err := method.Inputs.Unpack(&round, arguments); err != nil { + return nil, errExecutionReverted + } + count := g.state.DKGFinalizedsCount(round) + res, err := method.Outputs.Pack(count) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgMasterPublicKeys": + round, index := new(big.Int), new(big.Int) + args := []interface{}{&round, &index} + if err := method.Inputs.Unpack(&args, arguments); err != nil { + return nil, errExecutionReverted + } + mpks := g.state.DKGMasterPublicKeys(round) + if int(index.Uint64()) >= len(mpks) { + return nil, errExecutionReverted + } + mpk := mpks[index.Uint64()] + res, err := method.Outputs.Pack(mpk) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "dkgSetSize": + res, err := method.Outputs.Pack(g.state.DKGSetSize()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "finedRecords": + record := Bytes32{} + if err := method.Inputs.Unpack(&record, arguments); err != nil { + return nil, errExecutionReverted + } + value := g.state.FineRecords(record) + res, err := method.Outputs.Pack(value) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "fineValues": + index := new(big.Int) + if err := method.Inputs.Unpack(&index, arguments); err != nil { + return nil, errExecutionReverted + } + value := g.state.FineValue(index) + res, err := method.Outputs.Pack(value) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "k": + res, err := method.Outputs.Pack(g.state.K()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "lambdaBA": + res, err := method.Outputs.Pack(g.state.LambdaBA()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "lambdaDKG": + res, err := method.Outputs.Pack(g.state.LambdaDKG()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "lastHalvedAmount": + res, err := method.Outputs.Pack(g.state.LastHalvedAmount()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "lockupPeriod": + res, err := method.Outputs.Pack(g.state.LockupPeriod()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "minBlockInterval": + res, err := method.Outputs.Pack(g.state.MinBlockInterval()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "miningVelocity": + res, err := method.Outputs.Pack(g.state.MiningVelocity()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "minStake": + res, err := method.Outputs.Pack(g.state.MinStake()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "nextHalvingSupply": + res, err := method.Outputs.Pack(g.state.NextHalvingSupply()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "numChains": + res, err := method.Outputs.Pack(g.state.NumChains()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "nodes": + index := new(big.Int) + if err := method.Inputs.Unpack(&index, arguments); err != nil { + return nil, errExecutionReverted + } + info := g.state.Node(index) + res, err := method.Outputs.Pack( + info.Owner, info.PublicKey, info.Staked, info.Fined, + info.Name, info.Email, info.Location, info.Url) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "nodesOffsetByAddress": + address := common.Address{} + if err := method.Inputs.Unpack(&address, arguments); err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(g.state.NodesOffsetByAddress(address)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "nodesOffsetByID": + var id Bytes32 + if err := method.Inputs.Unpack(&id, arguments); err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(g.state.NodesOffsetByID(id)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "notarySetSize": + res, err := method.Outputs.Pack(g.state.NotarySetSize()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "owner": + res, err := method.Outputs.Pack(g.state.Owner()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "phiRatio": + res, err := method.Outputs.Pack(g.state.PhiRatio()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "roundHeight": + round := new(big.Int) + if err := method.Inputs.Unpack(&round, arguments); err != nil { + return nil, errExecutionReverted + } + res, err := method.Outputs.Pack(g.state.RoundHeight(round)) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "roundInterval": + res, err := method.Outputs.Pack(g.state.RoundInterval()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "totalStaked": + res, err := method.Outputs.Pack(g.state.TotalStaked()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + case "totalSupply": + res, err := method.Outputs.Pack(g.state.TotalSupply()) + if err != nil { + return nil, errExecutionReverted + } + return res, nil + } + return nil, errExecutionReverted +} + +// Storage position enums. +const ( + roundHeightLoc = iota + totalSupplyLoc + totalStakedLoc + nodesLoc + nodesOffsetByAddressLoc + nodesOffsetByIDLoc + delegatorsLoc + delegatorsOffsetLoc + crsLoc + dkgMasterPublicKeysLoc + dkgComplaintsLoc + dkgReadyLoc + dkgReadysCountLoc + dkgFinalizedLoc + dkgFinalizedsCountLoc + ownerLoc + minStakeLoc + lockupPeriodLoc + miningVelocityLoc + nextHalvingSupplyLoc + lastHalvedAmountLoc + blockGasLimitLoc + numChainsLoc + lambdaBALoc + lambdaDKGLoc + kLoc + phiRatioLoc + notarySetSizeLoc + dkgSetSizeLoc + roundIntervalLoc + minBlockIntervalLoc + fineValuesLoc + finedRecordsLoc +) + +func publicKeyToNodeID(pkBytes []byte) (Bytes32, error) { + pk, err := crypto.UnmarshalPubkey(pkBytes) + if err != nil { + return Bytes32{}, err + } + id := Bytes32(coreTypes.NewNodeID(ecdsa.NewPublicKeyFromECDSA(pk)).Hash) + return id, nil +} + +// State manipulation helper fro the governance contract. +type GovernanceStateHelper struct { + StateDB StateDB +} + +func (s *GovernanceStateHelper) getState(loc common.Hash) common.Hash { + return s.StateDB.GetState(GovernanceContractAddress, loc) +} + +func (s *GovernanceStateHelper) setState(loc common.Hash, val common.Hash) { + s.StateDB.SetState(GovernanceContractAddress, loc, val) +} + +func (s *GovernanceStateHelper) getStateBigInt(loc *big.Int) *big.Int { + res := s.StateDB.GetState(GovernanceContractAddress, common.BigToHash(loc)) + return new(big.Int).SetBytes(res.Bytes()) +} + +func (s *GovernanceStateHelper) setStateBigInt(loc *big.Int, val *big.Int) { + s.setState(common.BigToHash(loc), common.BigToHash(val)) +} + +func (s *GovernanceStateHelper) getSlotLoc(loc *big.Int) *big.Int { + return new(big.Int).SetBytes(crypto.Keccak256(common.BigToHash(loc).Bytes())) +} + +func (s *GovernanceStateHelper) getMapLoc(pos *big.Int, key []byte) *big.Int { + return new(big.Int).SetBytes(crypto.Keccak256(key, common.BigToHash(pos).Bytes())) +} + +func (s *GovernanceStateHelper) readBytes(loc *big.Int) []byte { + // Length of the dynamic array (bytes). + rawLength := s.getStateBigInt(loc) + lengthByte := new(big.Int).Mod(rawLength, big.NewInt(256)) + + // Bytes length <= 31, lengthByte % 2 == 0 + // return the high 31 bytes. + if new(big.Int).Mod(lengthByte, big.NewInt(2)).Cmp(big.NewInt(0)) == 0 { + length := new(big.Int).Div(lengthByte, big.NewInt(2)).Uint64() + return rawLength.Bytes()[:length] + } + + // Actual length = (rawLength - 1) / 2 + length := new(big.Int).Div(new(big.Int).Sub(rawLength, big.NewInt(1)), big.NewInt(2)).Uint64() + + // Data address. + dataLoc := s.getSlotLoc(loc) + + // Read continuously for length bytes. + carry := int64(0) + if length%32 > 0 { + carry = 1 + } + chunks := int64(length/32) + carry + var data []byte + for i := int64(0); i < chunks; i++ { + loc = new(big.Int).Add(dataLoc, big.NewInt(i)) + data = append(data, s.getState(common.BigToHash(loc)).Bytes()...) + } + data = data[:length] + return data +} + +func (s *GovernanceStateHelper) writeBytes(loc *big.Int, data []byte) { + length := int64(len(data)) + + if length == 0 { + s.setState(common.BigToHash(loc), common.Hash{}) + return + } + + // Short bytes (length <= 31). + if length < 32 { + data2 := append([]byte(nil), data...) + // Right pad with zeros + for len(data2) < 31 { + data2 = append(data2, byte(0)) + } + data2 = append(data2, byte(length*2)) + s.setState(common.BigToHash(loc), common.BytesToHash(data2)) + return + } + + // Write 2 * length + 1. + storedLength := new(big.Int).Add(new(big.Int).Mul( + big.NewInt(length), big.NewInt(2)), big.NewInt(1)) + s.setStateBigInt(loc, storedLength) + // Write data chunck. + dataLoc := s.getSlotLoc(loc) + carry := int64(0) + if length%32 > 0 { + carry = 1 + } + chunks := length/32 + carry + for i := int64(0); i < chunks; i++ { + loc = new(big.Int).Add(dataLoc, big.NewInt(i)) + maxLoc := (i + 1) * 32 + if maxLoc > length { + maxLoc = length + } + data2 := data[i*32 : maxLoc] + // Right pad with zeros. + for len(data2) < 32 { + data2 = append(data2, byte(0)) + } + s.setState(common.BigToHash(loc), common.BytesToHash(data2)) + } +} + +func (s *GovernanceStateHelper) read2DByteArray(pos, index *big.Int) [][]byte { + baseLoc := s.getSlotLoc(pos) + loc := new(big.Int).Add(baseLoc, index) + + arrayLength := s.getStateBigInt(loc) + dataLoc := s.getSlotLoc(loc) + + data := [][]byte{} + for i := int64(0); i < int64(arrayLength.Uint64()); i++ { + elementLoc := new(big.Int).Add(dataLoc, big.NewInt(i)) + data = append(data, s.readBytes(elementLoc)) + } + + return data +} +func (s *GovernanceStateHelper) appendTo2DByteArray(pos, index *big.Int, data []byte) { + // Find the loc of the last element. + baseLoc := s.getSlotLoc(pos) + loc := new(big.Int).Add(baseLoc, index) + + // Increase length by 1. + arrayLength := s.getStateBigInt(loc) + s.setStateBigInt(loc, new(big.Int).Add(arrayLength, big.NewInt(1))) + + // Write element. + dataLoc := s.getSlotLoc(loc) + elementLoc := new(big.Int).Add(dataLoc, arrayLength) + s.writeBytes(elementLoc, data) +} + +// uint256[] public roundHeight; +func (s *GovernanceStateHelper) LenRoundHeight() *big.Int { + return s.getStateBigInt(big.NewInt(roundHeightLoc)) +} +func (s *GovernanceStateHelper) RoundHeight(round *big.Int) *big.Int { + baseLoc := s.getSlotLoc(big.NewInt(roundHeightLoc)) + loc := new(big.Int).Add(baseLoc, round) + return s.getStateBigInt(loc) +} +func (s *GovernanceStateHelper) PushRoundHeight(height *big.Int) { + // Increase length by 1. + length := s.getStateBigInt(big.NewInt(roundHeightLoc)) + s.setStateBigInt(big.NewInt(roundHeightLoc), new(big.Int).Add(length, big.NewInt(1))) + + baseLoc := s.getSlotLoc(big.NewInt(roundHeightLoc)) + loc := new(big.Int).Add(baseLoc, length) + + s.setStateBigInt(loc, height) +} + +// uint256 public totalSupply; +func (s *GovernanceStateHelper) TotalSupply() *big.Int { + return s.getStateBigInt(big.NewInt(totalSupplyLoc)) +} +func (s *GovernanceStateHelper) IncTotalSupply(amount *big.Int) { + s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Add(s.TotalSupply(), amount)) +} +func (s *GovernanceStateHelper) DecTotalSupply(amount *big.Int) { + s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Sub(s.TotalSupply(), amount)) +} + +// uint256 public totalStaked; +func (s *GovernanceStateHelper) TotalStaked() *big.Int { + return s.getStateBigInt(big.NewInt(totalStakedLoc)) +} +func (s *GovernanceStateHelper) IncTotalStaked(amount *big.Int) { + s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Add(s.TotalStaked(), amount)) +} +func (s *GovernanceStateHelper) DecTotalStaked(amount *big.Int) { + s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Sub(s.TotalStaked(), amount)) +} + +// struct Node { +// address owner; +// bytes publicKey; +// uint256 staked; +// uint256 fined; +// string name; +// string email; +// string location; +// string url; +// } +// +// Node[] nodes; + +type nodeInfo struct { + Owner common.Address + PublicKey []byte + Staked *big.Int + Fined *big.Int + Name string + Email string + Location string + Url string +} + +const nodeStructSize = 8 + +func (s *GovernanceStateHelper) LenNodes() *big.Int { + return s.getStateBigInt(big.NewInt(nodesLoc)) +} +func (s *GovernanceStateHelper) Node(index *big.Int) *nodeInfo { + node := new(nodeInfo) + + arrayBaseLoc := s.getSlotLoc(big.NewInt(nodesLoc)) + elementBaseLoc := new(big.Int).Add(arrayBaseLoc, + new(big.Int).Mul(index, big.NewInt(nodeStructSize))) + + // Owner. + loc := elementBaseLoc + node.Owner = common.BytesToAddress(s.getState(common.BigToHash(elementBaseLoc)).Bytes()) + + // PublicKey. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1)) + node.PublicKey = s.readBytes(loc) + + // Staked. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2)) + node.Staked = s.getStateBigInt(loc) + + // Fined. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(3)) + node.Fined = s.getStateBigInt(loc) + + // Name. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(4)) + node.Name = string(s.readBytes(loc)) + + // Email. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(5)) + node.Email = string(s.readBytes(loc)) + + // Location. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(6)) + node.Location = string(s.readBytes(loc)) + + // Url. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(7)) + node.Url = string(s.readBytes(loc)) + + return node +} +func (s *GovernanceStateHelper) PushNode(n *nodeInfo) { + // Increase length by 1. + arrayLength := s.LenNodes() + s.setStateBigInt(big.NewInt(nodesLoc), new(big.Int).Add(arrayLength, big.NewInt(1))) + + s.UpdateNode(arrayLength, n) +} +func (s *GovernanceStateHelper) UpdateNode(index *big.Int, n *nodeInfo) { + arrayBaseLoc := s.getSlotLoc(big.NewInt(nodesLoc)) + elementBaseLoc := new(big.Int).Add(arrayBaseLoc, + new(big.Int).Mul(index, big.NewInt(nodeStructSize))) + + // Owner. + loc := elementBaseLoc + s.setState(common.BigToHash(loc), n.Owner.Hash()) + + // PublicKey. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1)) + s.writeBytes(loc, n.PublicKey) + + // Staked. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2)) + s.setStateBigInt(loc, n.Staked) + + // Fined. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(3)) + s.setStateBigInt(loc, n.Fined) + + // Name. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(4)) + s.writeBytes(loc, []byte(n.Name)) + + // Email. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(5)) + s.writeBytes(loc, []byte(n.Email)) + + // Location. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(6)) + s.writeBytes(loc, []byte(n.Location)) + + // Url. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(7)) + s.writeBytes(loc, []byte(n.Url)) +} +func (s *GovernanceStateHelper) PopLastNode() { + // Decrease length by 1. + arrayLength := s.LenNodes() + newArrayLength := new(big.Int).Sub(arrayLength, big.NewInt(1)) + s.setStateBigInt(big.NewInt(nodesLoc), newArrayLength) + + s.UpdateNode(newArrayLength, &nodeInfo{ + Staked: big.NewInt(0), + Fined: big.NewInt(0), + }) +} +func (s *GovernanceStateHelper) Nodes() []*nodeInfo { + var nodes []*nodeInfo + for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ { + nodes = append(nodes, s.Node(big.NewInt(i))) + } + return nodes +} +func (s *GovernanceStateHelper) QualifiedNodes() []*nodeInfo { + var nodes []*nodeInfo + for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ { + node := s.Node(big.NewInt(i)) + if new(big.Int).Sub(node.Staked, node.Fined).Cmp(s.MinStake()) >= 0 { + nodes = append(nodes, node) + } + } + return nodes +} + +// mapping(address => uint256) public nodeOffsetByAddress; +func (s *GovernanceStateHelper) NodesOffsetByAddress(addr common.Address) *big.Int { + loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) + return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) +} +func (s *GovernanceStateHelper) PutNodesOffsetByAddress(addr common.Address, offset *big.Int) { + loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) + s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) +} +func (s *GovernanceStateHelper) DeleteNodesOffsetByAddress(addr common.Address) { + loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) + s.setStateBigInt(loc, big.NewInt(0)) +} + +// mapping(address => uint256) public nodeOffsetByID; +func (s *GovernanceStateHelper) NodesOffsetByID(id Bytes32) *big.Int { + loc := s.getMapLoc(big.NewInt(nodesOffsetByIDLoc), id[:]) + return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) +} +func (s *GovernanceStateHelper) PutNodesOffsetByID(id Bytes32, offset *big.Int) { + loc := s.getMapLoc(big.NewInt(nodesOffsetByIDLoc), id[:]) + s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) +} +func (s *GovernanceStateHelper) DeleteNodesOffsetByID(id Bytes32) { + loc := s.getMapLoc(big.NewInt(nodesOffsetByIDLoc), id[:]) + s.setStateBigInt(loc, big.NewInt(0)) +} + +func (s *GovernanceStateHelper) PutNodeOffsets(n *nodeInfo, offset *big.Int) error { + id, err := publicKeyToNodeID(n.PublicKey) + if err != nil { + return err + } + s.PutNodesOffsetByID(id, offset) + s.PutNodesOffsetByAddress(n.Owner, offset) + return nil +} + +// struct Delegator { +// address node; +// address owner; +// uint256 value; +// uint256 undelegated_at; +// } + +type delegatorInfo struct { + Owner common.Address + Value *big.Int + UndelegatedAt *big.Int +} + +const delegatorStructSize = 3 + +// mapping(address => Delegator[]) public delegators; +func (s *GovernanceStateHelper) LenDelegators(nodeAddr common.Address) *big.Int { + loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) + return s.getStateBigInt(loc) +} +func (s *GovernanceStateHelper) Delegator(nodeAddr common.Address, offset *big.Int) *delegatorInfo { + delegator := new(delegatorInfo) + + loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) + arrayBaseLoc := s.getSlotLoc(loc) + elementBaseLoc := new(big.Int).Add(arrayBaseLoc, new(big.Int).Mul(big.NewInt(delegatorStructSize), offset)) + + // Owner. + loc = elementBaseLoc + delegator.Owner = common.BytesToAddress(s.getState(common.BigToHash(elementBaseLoc)).Bytes()) + + // Value. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1)) + delegator.Value = s.getStateBigInt(loc) + + // UndelegatedAt. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2)) + delegator.UndelegatedAt = s.getStateBigInt(loc) + + return delegator +} +func (s *GovernanceStateHelper) PushDelegator(nodeAddr common.Address, delegator *delegatorInfo) { + // Increase length by 1. + arrayLength := s.LenDelegators(nodeAddr) + loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) + s.setStateBigInt(loc, new(big.Int).Add(arrayLength, big.NewInt(1))) + + s.UpdateDelegator(nodeAddr, arrayLength, delegator) +} +func (s *GovernanceStateHelper) UpdateDelegator(nodeAddr common.Address, offset *big.Int, delegator *delegatorInfo) { + loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) + arrayBaseLoc := s.getSlotLoc(loc) + elementBaseLoc := new(big.Int).Add(arrayBaseLoc, new(big.Int).Mul(big.NewInt(delegatorStructSize), offset)) + + // Owner. + loc = elementBaseLoc + s.setState(common.BigToHash(loc), delegator.Owner.Hash()) + + // Value. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(1)) + s.setStateBigInt(loc, delegator.Value) + + // UndelegatedAt. + loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2)) + s.setStateBigInt(loc, delegator.UndelegatedAt) +} +func (s *GovernanceStateHelper) PopLastDelegator(nodeAddr common.Address) { + // Decrease length by 1. + arrayLength := s.LenDelegators(nodeAddr) + newArrayLength := new(big.Int).Sub(arrayLength, big.NewInt(1)) + loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) + s.setStateBigInt(loc, newArrayLength) + + s.UpdateDelegator(nodeAddr, newArrayLength, &delegatorInfo{ + Value: big.NewInt(0), + UndelegatedAt: big.NewInt(0), + }) +} + +// mapping(address => mapping(address => uint256)) delegatorsOffset; +func (s *GovernanceStateHelper) DelegatorsOffset(nodeAddr, delegatorAddr common.Address) *big.Int { + loc := s.getMapLoc(s.getMapLoc(big.NewInt(delegatorsOffsetLoc), nodeAddr.Bytes()), delegatorAddr.Bytes()) + return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) +} +func (s *GovernanceStateHelper) PutDelegatorOffset(nodeAddr, delegatorAddr common.Address, offset *big.Int) { + loc := s.getMapLoc(s.getMapLoc(big.NewInt(delegatorsOffsetLoc), nodeAddr.Bytes()), delegatorAddr.Bytes()) + s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) +} +func (s *GovernanceStateHelper) DeleteDelegatorsOffset(nodeAddr, delegatorAddr common.Address) { + loc := s.getMapLoc(s.getMapLoc(big.NewInt(delegatorsOffsetLoc), nodeAddr.Bytes()), delegatorAddr.Bytes()) + s.setStateBigInt(loc, big.NewInt(0)) +} + +// bytes32[] public crs; +func (s *GovernanceStateHelper) LenCRS() *big.Int { + return s.getStateBigInt(big.NewInt(crsLoc)) +} +func (s *GovernanceStateHelper) CRS(index *big.Int) common.Hash { + baseLoc := s.getSlotLoc(big.NewInt(crsLoc)) + loc := new(big.Int).Add(baseLoc, index) + return s.getState(common.BigToHash(loc)) +} +func (s *GovernanceStateHelper) CurrentCRS() common.Hash { + return s.CRS(new(big.Int).Sub(s.LenCRS(), big.NewInt(1))) +} +func (s *GovernanceStateHelper) PushCRS(crs common.Hash) { + // increase length by 1. + length := s.getStateBigInt(big.NewInt(crsLoc)) + s.setStateBigInt(big.NewInt(crsLoc), new(big.Int).Add(length, big.NewInt(1))) + + baseLoc := s.getSlotLoc(big.NewInt(crsLoc)) + loc := new(big.Int).Add(baseLoc, length) + + s.setState(common.BigToHash(loc), crs) +} +func (s *GovernanceStateHelper) Round() *big.Int { + return new(big.Int).Sub(s.getStateBigInt(big.NewInt(crsLoc)), big.NewInt(1)) +} + +// bytes[][] public dkgMasterPublicKeys; +func (s *GovernanceStateHelper) DKGMasterPublicKeys(round *big.Int) [][]byte { + return s.read2DByteArray(big.NewInt(dkgMasterPublicKeysLoc), round) +} +func (s *GovernanceStateHelper) PushDKGMasterPublicKey(round *big.Int, mpk []byte) { + s.appendTo2DByteArray(big.NewInt(dkgMasterPublicKeysLoc), round, mpk) +} +func (s *GovernanceStateHelper) UniqueDKGMasterPublicKeys(round *big.Int) []*dkgTypes.MasterPublicKey { + // Prepare DKGMasterPublicKeys. + var dkgMasterPKs []*dkgTypes.MasterPublicKey + existence := make(map[coreTypes.NodeID]struct{}) + for _, mpk := range s.DKGMasterPublicKeys(round) { + x := new(dkgTypes.MasterPublicKey) + if err := rlp.DecodeBytes(mpk, x); err != nil { + panic(err) + } + + // Only the first DKG MPK submission is valid. + if _, exists := existence[x.ProposerID]; exists { + continue + } + existence[x.ProposerID] = struct{}{} + dkgMasterPKs = append(dkgMasterPKs, x) + } + return dkgMasterPKs +} +func (s *GovernanceStateHelper) GetDKGMasterPublicKeyByProposerID( + round *big.Int, proposerID coreTypes.NodeID) (*dkgTypes.MasterPublicKey, error) { + + for _, mpk := range s.DKGMasterPublicKeys(round) { + x := new(dkgTypes.MasterPublicKey) + if err := rlp.DecodeBytes(mpk, x); err != nil { + panic(err) + } + if x.ProposerID.Equal(proposerID) { + return x, nil + } + } + return nil, errors.New("not found") +} + +// bytes[][] public dkgComplaints; +func (s *GovernanceStateHelper) DKGComplaints(round *big.Int) [][]byte { + return s.read2DByteArray(big.NewInt(dkgComplaintsLoc), round) +} +func (s *GovernanceStateHelper) PushDKGComplaint(round *big.Int, complaint []byte) { + s.appendTo2DByteArray(big.NewInt(dkgComplaintsLoc), round, complaint) +} + +// mapping(address => bool)[] public dkgReady; +func (s *GovernanceStateHelper) DKGMPKReady(round *big.Int, addr common.Address) bool { + baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadyLoc)), round) + mapLoc := s.getMapLoc(baseLoc, addr.Bytes()) + return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0 +} +func (s *GovernanceStateHelper) PutDKGMPKReady(round *big.Int, addr common.Address, ready bool) { + baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadyLoc)), round) + mapLoc := s.getMapLoc(baseLoc, addr.Bytes()) + res := big.NewInt(0) + if ready { + res = big.NewInt(1) + } + s.setStateBigInt(mapLoc, res) +} + +// uint256[] public dkgReadysCount; +func (s *GovernanceStateHelper) DKGMPKReadysCount(round *big.Int) *big.Int { + loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadysCountLoc)), round) + return s.getStateBigInt(loc) +} +func (s *GovernanceStateHelper) IncDKGMPKReadysCount(round *big.Int) { + loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadysCountLoc)), round) + count := s.getStateBigInt(loc) + s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1))) +} + +// mapping(address => bool)[] public dkgFinalized; +func (s *GovernanceStateHelper) DKGFinalized(round *big.Int, addr common.Address) bool { + baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedLoc)), round) + mapLoc := s.getMapLoc(baseLoc, addr.Bytes()) + return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0 +} +func (s *GovernanceStateHelper) PutDKGFinalized(round *big.Int, addr common.Address, finalized bool) { + baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedLoc)), round) + mapLoc := s.getMapLoc(baseLoc, addr.Bytes()) + res := big.NewInt(0) + if finalized { + res = big.NewInt(1) + } + s.setStateBigInt(mapLoc, res) +} + +// uint256[] public dkgFinalizedsCount; +func (s *GovernanceStateHelper) DKGFinalizedsCount(round *big.Int) *big.Int { + loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedsCountLoc)), round) + return s.getStateBigInt(loc) +} +func (s *GovernanceStateHelper) IncDKGFinalizedsCount(round *big.Int) { + loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedsCountLoc)), round) + count := s.getStateBigInt(loc) + s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1))) +} + +// address public owner; +func (s *GovernanceStateHelper) Owner() common.Address { + val := s.getState(common.BigToHash(big.NewInt(ownerLoc))) + return common.BytesToAddress(val.Bytes()) +} +func (s *GovernanceStateHelper) SetOwner(newOwner common.Address) { + s.setState(common.BigToHash(big.NewInt(ownerLoc)), newOwner.Hash()) +} + +// uint256 public minStake; +func (s *GovernanceStateHelper) MinStake() *big.Int { + return s.getStateBigInt(big.NewInt(minStakeLoc)) +} + +// uint256 public lockupPeriod; +func (s *GovernanceStateHelper) LockupPeriod() *big.Int { + return s.getStateBigInt(big.NewInt(lockupPeriodLoc)) +} + +// uint256 public miningVelocity; +func (s *GovernanceStateHelper) MiningVelocity() *big.Int { + return s.getStateBigInt(big.NewInt(miningVelocityLoc)) +} +func (s *GovernanceStateHelper) HalfMiningVelocity() { + s.setStateBigInt(big.NewInt(miningVelocityLoc), + new(big.Int).Div(s.MiningVelocity(), big.NewInt(2))) +} + +// uint256 public nextHalvingSupply; +func (s *GovernanceStateHelper) NextHalvingSupply() *big.Int { + return s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc)) +} +func (s *GovernanceStateHelper) IncNextHalvingSupply(amount *big.Int) { + s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc), + new(big.Int).Add(s.NextHalvingSupply(), amount)) +} + +// uint256 public lastHalvedAmount; +func (s *GovernanceStateHelper) LastHalvedAmount() *big.Int { + return s.getStateBigInt(big.NewInt(lastHalvedAmountLoc)) +} +func (s *GovernanceStateHelper) HalfLastHalvedAmount() { + s.setStateBigInt(big.NewInt(lastHalvedAmountLoc), + new(big.Int).Div(s.LastHalvedAmount(), big.NewInt(2))) +} + +func (s *GovernanceStateHelper) MiningHalved() { + s.HalfMiningVelocity() + s.HalfLastHalvedAmount() + s.IncNextHalvingSupply(s.LastHalvedAmount()) +} + +// uint256 public blockGasLimit; +func (s *GovernanceStateHelper) BlockGasLimit() *big.Int { + return s.getStateBigInt(big.NewInt(blockGasLimitLoc)) +} +func (s *GovernanceStateHelper) SetBlockGasLimit(reward *big.Int) { + s.setStateBigInt(big.NewInt(blockGasLimitLoc), reward) +} + +// uint256 public numChains; +func (s *GovernanceStateHelper) NumChains() *big.Int { + return s.getStateBigInt(big.NewInt(numChainsLoc)) +} + +// uint256 public lambdaBA; +func (s *GovernanceStateHelper) LambdaBA() *big.Int { + return s.getStateBigInt(big.NewInt(lambdaBALoc)) +} + +// uint256 public lambdaDKG; +func (s *GovernanceStateHelper) LambdaDKG() *big.Int { + return s.getStateBigInt(big.NewInt(lambdaDKGLoc)) +} + +// uint256 public k; +func (s *GovernanceStateHelper) K() *big.Int { + return s.getStateBigInt(big.NewInt(kLoc)) +} + +// uint256 public phiRatio; // stored as PhiRatio * 10^6 +func (s *GovernanceStateHelper) PhiRatio() *big.Int { + return s.getStateBigInt(big.NewInt(phiRatioLoc)) +} + +// uint256 public notarySetSize; +func (s *GovernanceStateHelper) NotarySetSize() *big.Int { + return s.getStateBigInt(big.NewInt(notarySetSizeLoc)) +} + +// uint256 public dkgSetSize; +func (s *GovernanceStateHelper) DKGSetSize() *big.Int { + return s.getStateBigInt(big.NewInt(dkgSetSizeLoc)) +} + +// uint256 public roundInterval; +func (s *GovernanceStateHelper) RoundInterval() *big.Int { + return s.getStateBigInt(big.NewInt(roundIntervalLoc)) +} + +// uint256 public minBlockInterval; +func (s *GovernanceStateHelper) MinBlockInterval() *big.Int { + return s.getStateBigInt(big.NewInt(minBlockIntervalLoc)) +} + +// uint256[] public fineValues; +func (s *GovernanceStateHelper) FineValue(index *big.Int) *big.Int { + arrayBaseLoc := s.getSlotLoc(big.NewInt(fineValuesLoc)) + return s.getStateBigInt(new(big.Int).Add(arrayBaseLoc, index)) +} +func (s *GovernanceStateHelper) FineValues() []*big.Int { + len := s.getStateBigInt(big.NewInt(fineValuesLoc)) + result := make([]*big.Int, len.Uint64()) + for i := 0; i < int(len.Uint64()); i++ { + result[i] = s.FineValue(big.NewInt(int64(i))) + } + return result +} +func (s *GovernanceStateHelper) SetFineValues(values []*big.Int) { + s.setStateBigInt(big.NewInt(fineValuesLoc), big.NewInt(int64(len(values)))) + + arrayBaseLoc := s.getSlotLoc(big.NewInt(fineValuesLoc)) + for i, v := range values { + s.setStateBigInt(new(big.Int).Add(arrayBaseLoc, big.NewInt(int64(i))), v) + } +} + +// uint256[] public fineRdecords; +func (s *GovernanceStateHelper) FineRecords(recordHash Bytes32) bool { + loc := s.getMapLoc(big.NewInt(finedRecordsLoc), recordHash[:]) + return s.getStateBigInt(loc).Cmp(big.NewInt(0)) > 0 +} +func (s *GovernanceStateHelper) SetFineRecords(recordHash Bytes32, status bool) { + loc := s.getMapLoc(big.NewInt(finedRecordsLoc), recordHash[:]) + value := int64(0) + if status { + value = int64(1) + } + s.setStateBigInt(loc, big.NewInt(value)) +} + +// Stake is a helper function for creating genesis state. +func (s *GovernanceStateHelper) Stake( + addr common.Address, publicKey []byte, staked *big.Int, + name, email, location, url string) { + offset := s.LenNodes() + node := &nodeInfo{ + Owner: addr, + PublicKey: publicKey, + Staked: staked, + Fined: big.NewInt(0), + Name: name, + Email: email, + Location: location, + Url: url, + } + s.PushNode(node) + if err := s.PutNodeOffsets(node, offset); err != nil { + panic(err) + } + + if staked.Cmp(big.NewInt(0)) == 0 { + return + } + + offset = s.LenDelegators(addr) + s.PushDelegator(addr, &delegatorInfo{ + Owner: addr, + Value: staked, + UndelegatedAt: big.NewInt(0), + }) + s.PutDelegatorOffset(addr, addr, offset) + + // Add to network total staked. + s.IncTotalStaked(staked) +} + +const decimalMultiplier = 100000000.0 + +// Configuration returns the current configuration. +func (s *GovernanceStateHelper) Configuration() *params.DexconConfig { + return ¶ms.DexconConfig{ + MinStake: s.getStateBigInt(big.NewInt(minStakeLoc)), + LockupPeriod: s.getStateBigInt(big.NewInt(lockupPeriodLoc)).Uint64(), + MiningVelocity: float32(s.getStateBigInt(big.NewInt(miningVelocityLoc)).Uint64()) / decimalMultiplier, + NextHalvingSupply: s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc)), + LastHalvedAmount: s.getStateBigInt(big.NewInt(lastHalvedAmountLoc)), + BlockGasLimit: s.getStateBigInt(big.NewInt(blockGasLimitLoc)).Uint64(), + NumChains: uint32(s.getStateBigInt(big.NewInt(numChainsLoc)).Uint64()), + LambdaBA: s.getStateBigInt(big.NewInt(lambdaBALoc)).Uint64(), + LambdaDKG: s.getStateBigInt(big.NewInt(lambdaDKGLoc)).Uint64(), + K: uint32(s.getStateBigInt(big.NewInt(kLoc)).Uint64()), + PhiRatio: float32(s.getStateBigInt(big.NewInt(phiRatioLoc)).Uint64()) / decimalMultiplier, + NotarySetSize: uint32(s.getStateBigInt(big.NewInt(notarySetSizeLoc)).Uint64()), + DKGSetSize: uint32(s.getStateBigInt(big.NewInt(dkgSetSizeLoc)).Uint64()), + RoundInterval: s.getStateBigInt(big.NewInt(roundIntervalLoc)).Uint64(), + MinBlockInterval: s.getStateBigInt(big.NewInt(minBlockIntervalLoc)).Uint64(), + FineValues: s.FineValues(), + } +} + +// UpdateConfiguration updates system configuration. +func (s *GovernanceStateHelper) UpdateConfiguration(cfg *params.DexconConfig) { + s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake) + s.setStateBigInt(big.NewInt(lockupPeriodLoc), big.NewInt(int64(cfg.LockupPeriod))) + s.setStateBigInt(big.NewInt(miningVelocityLoc), big.NewInt(int64(cfg.MiningVelocity*decimalMultiplier))) + s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc), cfg.NextHalvingSupply) + s.setStateBigInt(big.NewInt(lastHalvedAmountLoc), cfg.LastHalvedAmount) + s.setStateBigInt(big.NewInt(blockGasLimitLoc), big.NewInt(int64(cfg.BlockGasLimit))) + s.setStateBigInt(big.NewInt(numChainsLoc), big.NewInt(int64(cfg.NumChains))) + s.setStateBigInt(big.NewInt(lambdaBALoc), big.NewInt(int64(cfg.LambdaBA))) + s.setStateBigInt(big.NewInt(lambdaDKGLoc), big.NewInt(int64(cfg.LambdaDKG))) + s.setStateBigInt(big.NewInt(kLoc), big.NewInt(int64(cfg.K))) + s.setStateBigInt(big.NewInt(phiRatioLoc), big.NewInt(int64(cfg.PhiRatio*decimalMultiplier))) + s.setStateBigInt(big.NewInt(notarySetSizeLoc), big.NewInt(int64(cfg.NotarySetSize))) + s.setStateBigInt(big.NewInt(dkgSetSizeLoc), big.NewInt(int64(cfg.DKGSetSize))) + s.setStateBigInt(big.NewInt(roundIntervalLoc), big.NewInt(int64(cfg.RoundInterval))) + s.setStateBigInt(big.NewInt(minBlockIntervalLoc), big.NewInt(int64(cfg.MinBlockInterval))) + s.SetFineValues(cfg.FineValues) +} + +type rawConfigStruct struct { + MinStake *big.Int + LockupPeriod *big.Int + MiningVelocity *big.Int + BlockGasLimit *big.Int + NumChains *big.Int + LambdaBA *big.Int + LambdaDKG *big.Int + K *big.Int + PhiRatio *big.Int + NotarySetSize *big.Int + DKGSetSize *big.Int + RoundInterval *big.Int + MinBlockInterval *big.Int + FineValues []*big.Int +} + +// UpdateConfigurationRaw updates system configuration. +func (s *GovernanceStateHelper) UpdateConfigurationRaw(cfg *rawConfigStruct) { + s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake) + s.setStateBigInt(big.NewInt(lockupPeriodLoc), cfg.LockupPeriod) + s.setStateBigInt(big.NewInt(miningVelocityLoc), cfg.MiningVelocity) + s.setStateBigInt(big.NewInt(blockGasLimitLoc), cfg.BlockGasLimit) + s.setStateBigInt(big.NewInt(numChainsLoc), cfg.NumChains) + s.setStateBigInt(big.NewInt(lambdaBALoc), cfg.LambdaBA) + s.setStateBigInt(big.NewInt(lambdaDKGLoc), cfg.LambdaDKG) + s.setStateBigInt(big.NewInt(kLoc), cfg.K) + s.setStateBigInt(big.NewInt(phiRatioLoc), cfg.PhiRatio) + s.setStateBigInt(big.NewInt(notarySetSizeLoc), cfg.NotarySetSize) + s.setStateBigInt(big.NewInt(dkgSetSizeLoc), cfg.DKGSetSize) + s.setStateBigInt(big.NewInt(roundIntervalLoc), cfg.RoundInterval) + s.setStateBigInt(big.NewInt(minBlockIntervalLoc), cfg.MinBlockInterval) + s.SetFineValues(cfg.FineValues) +} + +// event ConfigurationChanged(); +func (s *GovernanceStateHelper) emitConfigurationChangedEvent() { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{events["ConfigurationChanged"].Id()}, + Data: []byte{}, + }) +} + +// event CRSProposed(uint256 round, bytes32 crs); +func (s *GovernanceStateHelper) emitCRSProposed(round *big.Int, crs common.Hash) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{events["CRSProposed"].Id(), common.BigToHash(round)}, + Data: crs.Bytes(), + }) +} + +// event Staked(address indexed NodeAddress, uint256 Amount); +func (s *GovernanceStateHelper) emitStaked(nodeAddr common.Address) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{events["Staked"].Id(), nodeAddr.Hash()}, + Data: []byte{}, + }) +} + +// event Unstaked(address indexed NodeAddress); +func (s *GovernanceStateHelper) emitUnstaked(nodeAddr common.Address) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{events["Unstaked"].Id(), nodeAddr.Hash()}, + Data: []byte{}, + }) +} + +// event Delegated(address indexed NodeAddress, address indexed DelegatorAddress, uint256 Amount); +func (s *GovernanceStateHelper) emitDelegated(nodeAddr, delegatorAddr common.Address, amount *big.Int) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{events["Delegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, + Data: common.BigToHash(amount).Bytes(), + }) +} + +// event Undelegated(address indexed NodeAddress, address indexed DelegatorAddress); +func (s *GovernanceStateHelper) emitUndelegated(nodeAddr, delegatorAddr common.Address) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{events["Undelegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, + Data: []byte{}, + }) +} + +// event Withdrawn(address indexed NodeAddress, uint256 Amount); +func (s *GovernanceStateHelper) emitWithdrawn(nodeAddr common.Address, amount *big.Int) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{events["Withdrawn"].Id(), nodeAddr.Hash()}, + Data: common.BigToHash(amount).Bytes(), + }) +} + +// event ForkReported(address indexed NodeAddress, address indexed Type, bytes Arg1, bytes Arg2); +func (s *GovernanceStateHelper) emitForkReported(nodeAddr common.Address, reportType *big.Int, arg1, arg2 []byte) { + + t, err := abi.NewType("bytes") + if err != nil { + panic(err) + } + + arg := abi.Arguments{ + abi.Argument{ + Name: "Arg1", + Type: t, + Indexed: false, + }, + abi.Argument{ + Name: "Arg2", + Type: t, + Indexed: false, + }, + } + + data, err := arg.Pack(arg1, arg2) + if err != nil { + panic(err) + } + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{events["ForkReported"].Id(), nodeAddr.Hash()}, + Data: data, + }) +} + +// event Fined(address indexed NodeAddress, uint256 Amount); +func (s *GovernanceStateHelper) emitFined(nodeAddr common.Address, amount *big.Int) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{events["Fined"].Id(), nodeAddr.Hash()}, + Data: common.BigToHash(amount).Bytes(), + }) +} + +// event FinePaid(address indexed NodeAddress, uint256 Amount); +func (s *GovernanceStateHelper) emitFinePaid(nodeAddr common.Address, amount *big.Int) { + s.StateDB.AddLog(&types.Log{ + Address: GovernanceContractAddress, + Topics: []common.Hash{events["FinePaid"].Id(), nodeAddr.Hash()}, + Data: common.BigToHash(amount).Bytes(), + }) +} + +// GovernanceContract represents the governance contract of DEXCON. +type GovernanceContract struct { + evm *EVM + state GovernanceStateHelper + contract *Contract +} + +func newGovernanceContract(evm *EVM, contract *Contract) *GovernanceContract { + return &GovernanceContract{ + evm: evm, + state: GovernanceStateHelper{evm.StateDB}, + contract: contract, + } +} + +func (g *GovernanceContract) Address() common.Address { + return GovernanceContractAddress +} + +func (g *GovernanceContract) transfer(from, to common.Address, amount *big.Int) bool { + // TODO(w): add this to debug trace so it shows up as internal transaction. + if g.evm.CanTransfer(g.evm.StateDB, from, amount) { + g.evm.Transfer(g.evm.StateDB, from, to, amount) + return true + } + return false +} + +func (g *GovernanceContract) useGas(gas uint64) ([]byte, error) { + if !g.contract.UseGas(gas) { + return nil, vm.ErrOutOfGas + } + return nil, nil +} + +func (g *GovernanceContract) penalize() ([]byte, error) { + g.useGas(g.contract.Gas) + return nil, errExecutionReverted +} + +func (g *GovernanceContract) inDKGSet(round *big.Int, nodeID coreTypes.NodeID) bool { + target := coreTypes.NewDKGSetTarget(coreCommon.Hash(g.state.CurrentCRS())) + ns := coreTypes.NewNodeSet() + + configRound := big.NewInt(0) // If round < core.ConfigRoundShift, use 0. + if round.Uint64() >= core.ConfigRoundShift { + configRound = new(big.Int).Sub(round, big.NewInt(int64(core.ConfigRoundShift))) + } + + statedb, err := g.evm.StateAtNumber(g.state.RoundHeight(configRound).Uint64()) + if err != nil { + panic(err) + } + + state := GovernanceStateHelper{statedb} + for _, x := range state.QualifiedNodes() { + mpk, err := ecdsa.NewPublicKeyFromByteSlice(x.PublicKey) + if err != nil { + panic(err) + } + ns.Add(coreTypes.NewNodeID(mpk)) + } + + dkgSet := ns.GetSubSet(int(g.state.DKGSetSize().Uint64()), target) + _, ok := dkgSet[nodeID] + return ok +} + +func (g *GovernanceContract) addDKGComplaint(round *big.Int, comp []byte) ([]byte, error) { + if round.Cmp(g.state.Round()) != 0 { + return g.penalize() + } + + caller := g.contract.Caller() + + // Finalized caller is not allowed to propose complaint. + if g.state.DKGFinalized(round, caller) { + return g.penalize() + } + + // Calculate 2f + threshold := new(big.Int).Mul( + big.NewInt(2), + new(big.Int).Div(g.state.DKGSetSize(), big.NewInt(3))) + + // If 2f + 1 of DKG set is finalized, one can not propose complaint anymore. + if g.state.DKGFinalizedsCount(round).Cmp(threshold) > 0 { + return nil, errExecutionReverted + } + + var dkgComplaint dkgTypes.Complaint + if err := rlp.DecodeBytes(comp, &dkgComplaint); err != nil { + return g.penalize() + } + + // DKGComplaint must belongs to someone in DKG set. + if !g.inDKGSet(round, dkgComplaint.ProposerID) { + return g.penalize() + } + + verified, _ := coreUtils.VerifyDKGComplaintSignature(&dkgComplaint) + if !verified { + return g.penalize() + } + + mpk, err := g.state.GetDKGMasterPublicKeyByProposerID( + round, dkgComplaint.PrivateShare.ProposerID) + if err != nil { + return g.penalize() + } + + // Verify DKG complaint is correct. + ok, err := coreUtils.VerifyDKGComplaint(&dkgComplaint, mpk) + if !ok || err != nil { + return g.penalize() + } + + // Fine the attacker. + need, err := coreUtils.NeedPenaltyDKGPrivateShare(&dkgComplaint, mpk) + if err != nil { + return g.penalize() + } + if need { + fineValue := g.state.FineValue(big.NewInt(ReportTypeInvalidDKG)) + offset := g.state.NodesOffsetByID(Bytes32(dkgComplaint.PrivateShare.ProposerID.Hash)) + node := g.state.Node(offset) + if err := g.fine(node.Owner, fineValue, comp, nil); err != nil { + return g.penalize() + } + } + + g.state.PushDKGComplaint(round, comp) + + // Set this to relatively high to prevent spamming + return g.useGas(5000000) +} + +func (g *GovernanceContract) addDKGMasterPublicKey(round *big.Int, mpk []byte) ([]byte, error) { + // Can only add DKG master public key of current and next round. + if round.Cmp(new(big.Int).Add(g.state.Round(), big.NewInt(1))) > 0 { + return g.penalize() + } + + caller := g.contract.Caller() + offset := g.state.NodesOffsetByAddress(caller) + + // Can not add dkg mpk if not staked. + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + // MPKReady caller is not allowed to propose mpk. + if g.state.DKGMPKReady(round, caller) { + return g.penalize() + } + + // Calculate 2f + threshold := new(big.Int).Mul( + big.NewInt(2), + new(big.Int).Div(g.state.DKGSetSize(), big.NewInt(3))) + + // If 2f + 1 of DKG set is mpk ready, one can not propose mpk anymore. + if g.state.DKGMPKReadysCount(round).Cmp(threshold) > 0 { + return nil, errExecutionReverted + } + + var dkgMasterPK dkgTypes.MasterPublicKey + if err := rlp.DecodeBytes(mpk, &dkgMasterPK); err != nil { + return g.penalize() + } + + // DKGMasterPublicKey must belongs to someone in DKG set. + if !g.inDKGSet(round, dkgMasterPK.ProposerID) { + return g.penalize() + } + + verified, _ := coreUtils.VerifyDKGMasterPublicKeySignature(&dkgMasterPK) + if !verified { + return g.penalize() + } + + g.state.PushDKGMasterPublicKey(round, mpk) + + return g.useGas(100000) +} + +func (g *GovernanceContract) addDKGMPKReady(round *big.Int, ready []byte) ([]byte, error) { + if round.Cmp(g.state.Round()) != 0 { + return g.penalize() + } + + caller := g.contract.Caller() + + var dkgReady dkgTypes.MPKReady + if err := rlp.DecodeBytes(ready, &dkgReady); err != nil { + return g.penalize() + } + + // DKGFInalize must belongs to someone in DKG set. + if !g.inDKGSet(round, dkgReady.ProposerID) { + return g.penalize() + } + + verified, _ := coreUtils.VerifyDKGMPKReadySignature(&dkgReady) + if !verified { + return g.penalize() + } + + if !g.state.DKGMPKReady(round, caller) { + g.state.PutDKGMPKReady(round, caller, true) + g.state.IncDKGMPKReadysCount(round) + } + + return g.useGas(100000) +} +func (g *GovernanceContract) addDKGFinalize(round *big.Int, finalize []byte) ([]byte, error) { + if round.Cmp(g.state.Round()) != 0 { + return g.penalize() + } + + caller := g.contract.Caller() + + var dkgFinalize dkgTypes.Finalize + if err := rlp.DecodeBytes(finalize, &dkgFinalize); err != nil { + return g.penalize() + } + + // DKGFInalize must belongs to someone in DKG set. + if !g.inDKGSet(round, dkgFinalize.ProposerID) { + return g.penalize() + } + + verified, _ := coreUtils.VerifyDKGFinalizeSignature(&dkgFinalize) + if !verified { + return g.penalize() + } + + if !g.state.DKGFinalized(round, caller) { + g.state.PutDKGFinalized(round, caller, true) + g.state.IncDKGFinalizedsCount(round) + } + + return g.useGas(100000) +} + +func (g *GovernanceContract) delegate(nodeAddr common.Address) ([]byte, error) { + offset := g.state.NodesOffsetByAddress(nodeAddr) + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + caller := g.contract.Caller() + value := g.contract.Value() + + // Can not delegate if no fund was sent. + if value.Cmp(big.NewInt(0)) == 0 { + return nil, errExecutionReverted + } + + // Can not delegate if already delegated. + delegatorOffset := g.state.DelegatorsOffset(nodeAddr, caller) + if delegatorOffset.Cmp(big.NewInt(0)) >= 0 { + return nil, errExecutionReverted + } + + // Add to the total staked of node. + node := g.state.Node(offset) + node.Staked = new(big.Int).Add(node.Staked, g.contract.Value()) + g.state.UpdateNode(offset, node) + + // Add to network total staked. + g.state.IncTotalStaked(g.contract.Value()) + + // Push delegator record. + offset = g.state.LenDelegators(nodeAddr) + g.state.PushDelegator(nodeAddr, &delegatorInfo{ + Owner: caller, + Value: value, + UndelegatedAt: big.NewInt(0), + }) + g.state.PutDelegatorOffset(nodeAddr, caller, offset) + g.state.emitDelegated(nodeAddr, caller, value) + + return g.useGas(200000) +} + +func (g *GovernanceContract) updateConfiguration(cfg *rawConfigStruct) ([]byte, error) { + // Only owner can update configuration. + if g.contract.Caller() != g.state.Owner() { + return nil, errExecutionReverted + } + + g.state.UpdateConfigurationRaw(cfg) + g.state.emitConfigurationChangedEvent() + return nil, nil +} + +func (g *GovernanceContract) stake( + publicKey []byte, name, email, location, url string) ([]byte, error) { + + // Reject invalid inputs. + if len(name) >= 32 || len(email) >= 32 || len(location) >= 32 || len(url) >= 128 { + return g.penalize() + } + + caller := g.contract.Caller() + offset := g.state.NodesOffsetByAddress(caller) + + // Can not stake if already staked. + if offset.Cmp(big.NewInt(0)) >= 0 { + return nil, errExecutionReverted + } + + offset = g.state.LenNodes() + node := &nodeInfo{ + Owner: caller, + PublicKey: publicKey, + Staked: big.NewInt(0), + Fined: big.NewInt(0), + Name: name, + Email: email, + Location: location, + Url: url, + } + g.state.PushNode(node) + if err := g.state.PutNodeOffsets(node, offset); err != nil { + return g.penalize() + } + + // Delegate fund to itself. + if g.contract.Value().Cmp(big.NewInt(0)) > 0 { + if ret, err := g.delegate(caller); err != nil { + return ret, err + } + } + + g.state.emitStaked(caller) + return g.useGas(100000) +} + +func (g *GovernanceContract) undelegateHelper(nodeAddr, caller common.Address) ([]byte, error) { + nodeOffset := g.state.NodesOffsetByAddress(nodeAddr) + if nodeOffset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + offset := g.state.DelegatorsOffset(nodeAddr, caller) + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + node := g.state.Node(nodeOffset) + if node.Fined.Cmp(big.NewInt(0)) > 0 { + return nil, errExecutionReverted + } + + delegator := g.state.Delegator(nodeAddr, offset) + + if delegator.UndelegatedAt.Cmp(big.NewInt(0)) != 0 { + return nil, errExecutionReverted + } + + // Set undelegate time. + delegator.UndelegatedAt = g.evm.Time + g.state.UpdateDelegator(nodeAddr, offset, delegator) + + // Subtract from the total staked of node. + node.Staked = new(big.Int).Sub(node.Staked, delegator.Value) + g.state.UpdateNode(nodeOffset, node) + + // Subtract to network total staked. + g.state.DecTotalStaked(delegator.Value) + + g.state.emitUndelegated(nodeAddr, caller) + + return g.useGas(100000) +} + +func (g *GovernanceContract) undelegate(nodeAddr common.Address) ([]byte, error) { + return g.undelegateHelper(nodeAddr, g.contract.Caller()) +} + +func (g *GovernanceContract) withdraw(nodeAddr common.Address) ([]byte, error) { + caller := g.contract.Caller() + + nodeOffset := g.state.NodesOffsetByAddress(nodeAddr) + if nodeOffset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + offset := g.state.DelegatorsOffset(nodeAddr, caller) + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + delegator := g.state.Delegator(nodeAddr, offset) + + // Not yet undelegated. + if delegator.UndelegatedAt.Cmp(big.NewInt(0)) == 0 { + return g.penalize() + } + + unlockTime := new(big.Int).Add(delegator.UndelegatedAt, g.state.LockupPeriod()) + if g.evm.Time.Cmp(unlockTime) <= 0 { + return g.penalize() + } + + length := g.state.LenDelegators(nodeAddr) + lastIndex := new(big.Int).Sub(length, big.NewInt(1)) + + // Delete the delegator. + if offset.Cmp(lastIndex) != 0 { + lastNode := g.state.Delegator(nodeAddr, lastIndex) + g.state.UpdateDelegator(nodeAddr, offset, lastNode) + g.state.PutDelegatorOffset(nodeAddr, lastNode.Owner, offset) + } + g.state.DeleteDelegatorsOffset(nodeAddr, caller) + g.state.PopLastDelegator(nodeAddr) + + // Return the staked fund. + if !g.transfer(GovernanceContractAddress, delegator.Owner, delegator.Value) { + return nil, errExecutionReverted + } + + g.state.emitWithdrawn(nodeAddr, delegator.Value) + + // We are the last delegator to withdraw the fund, remove the node info. + if g.state.LenDelegators(nodeAddr).Cmp(big.NewInt(0)) == 0 { + length := g.state.LenNodes() + lastIndex := new(big.Int).Sub(length, big.NewInt(1)) + + // Delete the node. + if offset.Cmp(lastIndex) != 0 { + lastNode := g.state.Node(lastIndex) + g.state.UpdateNode(offset, lastNode) + if err := g.state.PutNodeOffsets(lastNode, offset); err != nil { + panic(err) + } + } + g.state.DeleteNodesOffsetByAddress(nodeAddr) + g.state.PopLastNode() + } + + return g.useGas(100000) +} + +func (g *GovernanceContract) unstake() ([]byte, error) { + caller := g.contract.Caller() + offset := g.state.NodesOffsetByAddress(caller) + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + node := g.state.Node(offset) + if node.Fined.Cmp(big.NewInt(0)) > 0 { + return nil, errExecutionReverted + } + + // Undelegate all delegators. + lenDelegators := g.state.LenDelegators(caller) + i := new(big.Int).Sub(lenDelegators, big.NewInt(1)) + for i.Cmp(big.NewInt(0)) >= 0 { + delegator := g.state.Delegator(caller, i) + if ret, err := g.undelegateHelper(caller, delegator.Owner); err != nil { + return ret, err + } + i = i.Sub(i, big.NewInt(1)) + } + + g.state.emitUnstaked(caller) + + return g.useGas(100000) +} + +func (g *GovernanceContract) payFine(nodeAddr common.Address) ([]byte, error) { + caller := g.contract.Caller() + + nodeOffset := g.state.NodesOffsetByAddress(nodeAddr) + if nodeOffset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + offset := g.state.DelegatorsOffset(nodeAddr, caller) + if offset.Cmp(big.NewInt(0)) < 0 { + return nil, errExecutionReverted + } + + node := g.state.Node(nodeOffset) + if node.Fined.Cmp(big.NewInt(0)) <= 0 || node.Fined.Cmp(g.contract.Value()) < 0 { + return nil, errExecutionReverted + } + + node.Fined = new(big.Int).Sub(node.Fined, g.contract.Value()) + g.state.UpdateNode(nodeOffset, node) + + // TODO: paid fine should be added to award pool. + + g.state.emitFinePaid(nodeAddr, g.contract.Value()) + + return g.useGas(100000) +} + +func (g *GovernanceContract) proposeCRS(nextRound *big.Int, signedCRS []byte) ([]byte, error) { + round := g.state.Round() + + if nextRound.Cmp(round) <= 0 { + return nil, errExecutionReverted + } + + prevCRS := g.state.CRS(round) + + // Prepare DKGMasterPublicKeys. + dkgMasterPKs := g.state.UniqueDKGMasterPublicKeys(round) + + // Prepare DKGComplaints. + var dkgComplaints []*dkgTypes.Complaint + for _, comp := range g.state.DKGComplaints(round) { + x := new(dkgTypes.Complaint) + if err := rlp.DecodeBytes(comp, x); err != nil { + panic(err) + } + dkgComplaints = append(dkgComplaints, x) + } + + threshold := int(g.state.DKGSetSize().Uint64()/3 + 1) + + dkgGPK, err := core.NewDKGGroupPublicKey( + round.Uint64(), dkgMasterPKs, dkgComplaints, threshold) + if err != nil { + return nil, errExecutionReverted + } + signature := coreCrypto.Signature{ + Type: "bls", + Signature: signedCRS, + } + if !dkgGPK.VerifySignature(coreCommon.Hash(prevCRS), signature) { + return g.penalize() + } + + // Save new CRS into state and increase round. + newCRS := crypto.Keccak256(signedCRS) + crs := common.BytesToHash(newCRS) + + g.state.PushCRS(crs) + g.state.emitCRSProposed(nextRound, crs) + + // To encourage DKG set to propose the correct value, correctly submitting + // this should cause nothing. + return g.useGas(0) +} + +type sortBytes [][]byte + +func (s sortBytes) Less(i, j int) bool { + return bytes.Compare(s[i], s[j]) < 0 +} + +func (s sortBytes) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s sortBytes) Len() int { + return len(s) +} + +func (g *GovernanceContract) fine(nodeAddr common.Address, amount *big.Int, payloads ...[]byte) error { + sort.Sort(sortBytes(payloads)) + + hash := Bytes32(crypto.Keccak256Hash(payloads...)) + if g.state.FineRecords(hash) { + return errors.New("already fined") + } + g.state.SetFineRecords(hash, true) + + nodeOffset := g.state.NodesOffsetByAddress(nodeAddr) + if nodeOffset.Cmp(big.NewInt(0)) < 0 { + return errExecutionReverted + } + + // Set fined value. + node := g.state.Node(nodeOffset) + node.Fined = new(big.Int).Add(node.Fined, amount) + g.state.UpdateNode(nodeOffset, node) + + g.state.emitFined(nodeAddr, amount) + + return nil +} + +func (g *GovernanceContract) report(reportType *big.Int, arg1, arg2 []byte) ([]byte, error) { + typeEnum := ReportType(reportType.Uint64()) + var reportedNodeID coreTypes.NodeID + + switch typeEnum { + case ReportTypeForkVote: + vote1 := new(coreTypes.Vote) + if err := rlp.DecodeBytes(arg1, vote1); err != nil { + return g.penalize() + } + vote2 := new(coreTypes.Vote) + if err := rlp.DecodeBytes(arg2, vote2); err != nil { + return g.penalize() + } + need, err := coreUtils.NeedPenaltyForkVote(vote1, vote2) + if !need || err != nil { + return g.penalize() + } + reportedNodeID = vote1.ProposerID + case ReportTypeForkBlock: + block1 := new(coreTypes.Block) + if err := rlp.DecodeBytes(arg1, block1); err != nil { + return g.penalize() + } + block2 := new(coreTypes.Block) + if err := rlp.DecodeBytes(arg2, block2); err != nil { + return g.penalize() + } + need, err := coreUtils.NeedPenaltyForkBlock(block1, block2) + if !need || err != nil { + return g.penalize() + } + reportedNodeID = block1.ProposerID + default: + return g.penalize() + } + + offset := g.state.NodesOffsetByID(Bytes32(reportedNodeID.Hash)) + node := g.state.Node(offset) + + g.state.emitForkReported(node.Owner, reportType, arg1, arg2) + + fineValue := g.state.FineValue(reportType) + if err := g.fine(node.Owner, fineValue, arg1, arg2); err != nil { + return nil, errExecutionReverted + } + return nil, nil +} + +func (g *GovernanceContract) transferOwnership(newOwner common.Address) ([]byte, error) { + // Only owner can update configuration. + if g.contract.Caller() != g.state.Owner() { + return nil, errExecutionReverted + } + g.state.SetOwner(newOwner) + return nil, nil +} + +func (g *GovernanceContract) snapshotRound(round, height *big.Int) ([]byte, error) { + // Validate if this mapping is correct. Only block proposer need to verify this. + if g.evm.IsBlockProposer() { + realHeight, ok := g.evm.GetRoundHeight(round.Uint64()) + if !ok { + return g.penalize() + } + + if height.Cmp(new(big.Int).SetUint64(realHeight)) != 0 { + return g.penalize() + } + } + + // Only allow updating the next round. + nextRound := g.state.LenRoundHeight() + if round.Cmp(nextRound) != 0 { + // No need to penalize, since the only possibility at this point is the + // round height is already snapshoted. + return nil, errExecutionReverted + } + + g.state.PushRoundHeight(height) + return nil, nil +} diff --git a/core/vm/evm/governance_abi.go b/core/vm/evm/governance_abi.go new file mode 100644 index 000000000..966c4c4f3 --- /dev/null +++ b/core/vm/evm/governance_abi.go @@ -0,0 +1,1133 @@ +// Copyright 2019 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus library is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The dexon-consensus library is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the dexon-consensus library. If not, see +// <http://www.gnu.org/licenses/>. + +package evm + +// The governance ABI is generated from: +// https://github.com/dexon-foundation/governance-abi + +const GovernanceABIJSON = ` +[ + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "address" + } + ], + "name": "delegatorsOffset", + "outputs": [ + { + "name": "", + "type": "int256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "dkgComplaints", + "outputs": [ + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "notarySetSize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "dkgSetSize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "nodes", + "outputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "publicKey", + "type": "bytes" + }, + { + "name": "staked", + "type": "uint256" + }, + { + "name": "fined", + "type": "uint256" + }, + { + "name": "name", + "type": "string" + }, + { + "name": "email", + "type": "string" + }, + { + "name": "location", + "type": "string" + }, + { + "name": "url", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "miningVelocity", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "lambdaBA", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "minStake", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "crs", + "outputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "phiRatio", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "dkgMPKReadysCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "address" + } + ], + "name": "dkgMPKReadys", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "delegators", + "outputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + }, + { + "name": "undelegated_at", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "blockGasLimit", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "name": "nodesOffsetByID", + "outputs": [ + { + "name": "", + "type": "int256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalStaked", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "roundInterval", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "nodesOffsetByAddress", + "outputs": [ + { + "name": "", + "type": "int256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "nextHalvingSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "lastHalvedAmount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "name": "finedRecords", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "lambdaDKG", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "fineValues", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "roundHeight", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "minBlockInterval", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "k", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "dkgMasterPublicKeys", + "outputs": [ + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "address" + } + ], + "name": "dkgFinalizeds", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "numChains", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "lockupPeriod", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "dkgFinalizedsCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [], + "name": "ConfigurationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "Round", + "type": "uint256" + }, + { + "indexed": false, + "name": "CRS", + "type": "bytes32" + } + ], + "name": "CRSProposed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + } + ], + "name": "Staked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + } + ], + "name": "Unstaked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": true, + "name": "DelegatorAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" + } + ], + "name": "Delegated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": true, + "name": "DelegatorAddress", + "type": "address" + } + ], + "name": "Undelegated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" + } + ], + "name": "Withdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Type", + "type": "uint256" + }, + { + "indexed": false, + "name": "Arg1", + "type": "bytes" + }, + { + "indexed": false, + "name": "Arg2", + "type": "bytes" + } + ], + "name": "ForkReported", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" + } + ], + "name": "Fined", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "NodeAddress", + "type": "address" + }, + { + "indexed": false, + "name": "Amount", + "type": "uint256" + } + ], + "name": "FinePaid", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "MinStake", + "type": "uint256" + }, + { + "name": "LockupPeriod", + "type": "uint256" + }, + { + "name": "MiningVelocity", + "type": "uint256" + }, + { + "name": "NextHalvingSupply", + "type": "uint256" + }, + { + "name": "LastHalvingAmount", + "type": "uint256" + }, + { + "name": "BlockGasLimit", + "type": "uint256" + }, + { + "name": "NumChains", + "type": "uint256" + }, + { + "name": "LambdaBA", + "type": "uint256" + }, + { + "name": "LambdaDKG", + "type": "uint256" + }, + { + "name": "K", + "type": "uint256" + }, + { + "name": "PhiRatio", + "type": "uint256" + }, + { + "name": "NotarySetSize", + "type": "uint256" + }, + { + "name": "DKGSetSize", + "type": "uint256" + }, + { + "name": "RoundInterval", + "type": "uint256" + }, + { + "name": "MinBlockInterval", + "type": "uint256" + }, + { + "name": "FineValues", + "type": "uint256[]" + } + ], + "name": "updateConfiguration", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "nodesLength", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "NodeAddress", + "type": "address" + } + ], + "name": "delegatorsLength", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "Round", + "type": "uint256" + }, + { + "name": "Height", + "type": "uint256" + } + ], + "name": "snapshotRound", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "Round", + "type": "uint256" + }, + { + "name": "SignedCRS", + "type": "bytes" + } + ], + "name": "proposeCRS", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "Round", + "type": "uint256" + }, + { + "name": "Complaint", + "type": "bytes" + } + ], + "name": "addDKGComplaint", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "Round", + "type": "uint256" + }, + { + "name": "PublicKey", + "type": "bytes" + } + ], + "name": "addDKGMasterPublicKey", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "Round", + "type": "uint256" + }, + { + "name": "MPKReady", + "type": "bytes" + } + ], + "name": "addDKGMPKReady", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "Round", + "type": "uint256" + }, + { + "name": "Finalize", + "type": "bytes" + } + ], + "name": "addDKGFinalize", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "PublicKey", + "type": "bytes" + }, + { + "name": "Name", + "type": "string" + }, + { + "name": "Email", + "type": "string" + }, + { + "name": "Location", + "type": "string" + }, + { + "name": "Url", + "type": "string" + } + ], + "name": "stake", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "unstake", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "NodeAddress", + "type": "address" + } + ], + "name": "delegate", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "NodeAddress", + "type": "address" + } + ], + "name": "undelegate", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "NodeAddress", + "type": "address" + } + ], + "name": "withdraw", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "NodeAddress", + "type": "address" + } + ], + "name": "payFine", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "Type", + "type": "uint256" + }, + { + "name": "Arg1", + "type": "bytes" + }, + { + "name": "Arg2", + "type": "bytes" + } + ], + "name": "report", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] +` diff --git a/core/vm/evm/governance_test.go b/core/vm/evm/governance_test.go new file mode 100644 index 000000000..1a67516ec --- /dev/null +++ b/core/vm/evm/governance_test.go @@ -0,0 +1,1060 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus library is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The dexon-consensus library is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the dexon-consensus library. If not, see +// <http://www.gnu.org/licenses/>. + +package evm + +import ( + "bytes" + "crypto/ecdsa" + "math/big" + "math/rand" + "sort" + "testing" + "time" + + coreCommon "github.com/dexon-foundation/dexon-consensus/common" + coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" + coreEcdsa "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" + coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" + coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils" + + "github.com/dexon-foundation/dexon/common" + "github.com/dexon-foundation/dexon/core/state" + "github.com/dexon-foundation/dexon/crypto" + "github.com/dexon-foundation/dexon/ethdb" + "github.com/dexon-foundation/dexon/params" + "github.com/dexon-foundation/dexon/rlp" + "github.com/stretchr/testify/suite" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +func randomBytes(minLength, maxLength int32) []byte { + length := rand.Int31()%(maxLength-minLength) + minLength + b := make([]byte, length) + for i := range b { + b[i] = byte(65 + rand.Int31()%60) + } + return b +} + +type GovernanceStateHelperTestSuite struct { + suite.Suite + + s *GovernanceStateHelper +} + +func (g *GovernanceStateHelperTestSuite) SetupTest() { + db := state.NewDatabase(ethdb.NewMemDatabase()) + statedb, err := state.New(common.Hash{}, db) + if err != nil { + panic(err) + } + g.s = &GovernanceStateHelper{statedb} +} + +func (g *GovernanceStateHelperTestSuite) TestReadWriteBytes() { + for i := 0; i < 100; i++ { + // Short bytes. + loc := big.NewInt(rand.Int63()) + data := randomBytes(3, 32) + g.s.writeBytes(loc, data) + read := g.s.readBytes(loc) + g.Require().Equal(0, bytes.Compare(data, read)) + + // long bytes. + loc = big.NewInt(rand.Int63()) + data = randomBytes(33, 2560) + g.s.writeBytes(loc, data) + read = g.s.readBytes(loc) + g.Require().Equal(0, bytes.Compare(data, read)) + } +} + +func TestGovernanceStateHelper(t *testing.T) { + suite.Run(t, new(GovernanceStateHelperTestSuite)) +} + +type GovernanceContractTestSuite struct { + suite.Suite + + config *params.DexconConfig + memDB *ethdb.MemDatabase + stateDB *state.StateDB + s *GovernanceStateHelper +} + +func (g *GovernanceContractTestSuite) SetupTest() { + memDB := ethdb.NewMemDatabase() + stateDB, err := state.New(common.Hash{}, state.NewDatabase(memDB)) + if err != nil { + panic(err) + } + g.memDB = memDB + g.stateDB = stateDB + g.s = &GovernanceStateHelper{stateDB} + + config := params.TestnetChainConfig.Dexcon + config.LockupPeriod = 1000 + config.NextHalvingSupply = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2.5e9)) + config.LastHalvedAmount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1.5e9)) + config.MiningVelocity = 0.1875 + + g.config = config + + // Give governance contract balance so it will not be deleted because of being an empty state object. + stateDB.AddBalance(GovernanceContractAddress, big.NewInt(1)) + + // Genesis CRS. + crs := crypto.Keccak256Hash([]byte(config.GenesisCRSText)) + g.s.PushCRS(crs) + + // Round 0 height. + g.s.PushRoundHeight(big.NewInt(0)) + + // Owner. + g.s.SetOwner(g.config.Owner) + + // Governance configuration. + g.s.UpdateConfiguration(config) + + g.stateDB.Commit(true) +} + +func (g *GovernanceContractTestSuite) newPrefundAccount() (*ecdsa.PrivateKey, common.Address) { + privKey, err := crypto.GenerateKey() + if err != nil { + panic(err) + } + address := crypto.PubkeyToAddress(privKey.PublicKey) + + g.stateDB.AddBalance(address, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2e6))) + return privKey, address +} + +func (g *GovernanceContractTestSuite) call(caller common.Address, input []byte, value *big.Int) ([]byte, error) { + context := Context{ + CanTransfer: func(db StateDB, addr common.Address, amount *big.Int) bool { + return db.GetBalance(addr).Cmp(amount) >= 0 + }, + Transfer: func(db StateDB, sender common.Address, recipient common.Address, amount *big.Int) { + db.SubBalance(sender, amount) + db.AddBalance(recipient, amount) + }, + GetRoundHeight: func(round uint64) (uint64, bool) { + switch round { + case 0: + return 0, true + case 1: + return 1000, true + case 2: + return 2000, true + } + return 0, false + }, + Time: big.NewInt(time.Now().UnixNano() / 1000000), + BlockNumber: big.NewInt(0), + } + + evm := NewEVM(context, g.stateDB, params.TestChainConfig, Config{IsBlockProposer: true}) + ret, _, err := evm.Call(AccountRef(caller), GovernanceContractAddress, input, 10000000, value) + return ret, err +} + +func (g *GovernanceContractTestSuite) TestTransferOwnership() { + _, addr := g.newPrefundAccount() + + input, err := abiObject.Pack("transferOwnership", addr) + g.Require().NoError(err) + + // Call with non-owner. + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NotNil(err) + + // Call with owner. + _, err = g.call(g.config.Owner, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(addr, g.s.Owner()) +} + +func (g *GovernanceContractTestSuite) TestStakeUnstakeWithoutExtraDelegators() { + privKey, addr := g.newPrefundAccount() + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) + balanceBeforeStake := g.stateDB.GetBalance(addr) + input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(addr, input, amount) + g.Require().NoError(err) + + g.Require().Equal(1, int(g.s.LenNodes().Uint64())) + g.Require().Equal(1, len(g.s.QualifiedNodes())) + g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name) + g.Require().Equal(amount.String(), g.s.TotalStaked().String()) + + // Check balance. + g.Require().Equal(new(big.Int).Sub(balanceBeforeStake, amount), g.stateDB.GetBalance(addr)) + g.Require().Equal(new(big.Int).Add(big.NewInt(1), amount), g.stateDB.GetBalance(GovernanceContractAddress)) + + // Staking again should fail. + _, err = g.call(addr, input, amount) + g.Require().NotNil(err) + + // Unstake. + input, err = abiObject.Pack("unstake") + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) + g.Require().Equal(1, int(g.s.LenNodes().Uint64())) + + node := g.s.Node(big.NewInt(0)) + g.Require().Equal(big.NewInt(0).String(), node.Staked.String()) + g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) + + // Wait for lockup time than withdraw. + time.Sleep(time.Second * 2) + input, err = abiObject.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) + g.Require().Equal(0, int(g.s.LenNodes().Uint64())) + + // Stake 2 nodes, and unstake the first then the second. + + // 2nd node Stake. + privKey2, addr2 := g.newPrefundAccount() + pk2 := crypto.FromECDSAPub(&privKey2.PublicKey) + input, err = abiObject.Pack("stake", pk2, "Test2", "test2@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(addr2, input, amount) + g.Require().NoError(err) + g.Require().Equal("Test2", g.s.Node(big.NewInt(0)).Name) + g.Require().Equal(0, int(g.s.NodesOffsetByAddress(addr2).Int64())) + + // 1st node Stake. + input, err = abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(addr, input, amount) + g.Require().NoError(err) + + g.Require().Equal(2, len(g.s.QualifiedNodes())) + g.Require().Equal(new(big.Int).Mul(amount, big.NewInt(2)).String(), g.s.TotalStaked().String()) + + // 2nd node Unstake. + input, err = abiObject.Pack("unstake") + g.Require().NoError(err) + _, err = g.call(addr2, input, big.NewInt(0)) + g.Require().NoError(err) + node = g.s.Node(big.NewInt(0)) + g.Require().Equal("Test2", node.Name) + g.Require().Equal(big.NewInt(0).String(), node.Staked.String()) + g.Require().Equal(1, len(g.s.QualifiedNodes())) + g.Require().Equal(amount.String(), g.s.TotalStaked().String()) + + time.Sleep(time.Second * 2) + input, err = abiObject.Pack("withdraw", addr2) + g.Require().NoError(err) + _, err = g.call(addr2, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(1, len(g.s.QualifiedNodes())) + + g.Require().Equal(1, int(g.s.LenNodes().Uint64())) + g.Require().Equal("Test1", g.s.Node(big.NewInt(0)).Name) + g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr2).Int64())) + + // 1st node Unstake. + input, err = abiObject.Pack("unstake") + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) + + time.Sleep(time.Second * 2) + input, err = abiObject.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(0, int(g.s.LenNodes().Uint64())) + g.Require().Equal(-1, int(g.s.NodesOffsetByAddress(addr).Int64())) + g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addr).Int64())) + + // Check balance. + g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr)) + g.Require().Equal(balanceBeforeStake, g.stateDB.GetBalance(addr2)) + g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress)) +} + +func (g *GovernanceContractTestSuite) TestDelegateUndelegate() { + privKey, addr := g.newPrefundAccount() + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + // Stake. + input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + ownerStaked := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + _, err = g.call(addr, input, ownerStaked) + g.Require().NoError(err) + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal(addr, g.s.Delegator(addr, big.NewInt(0)).Owner) + g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) + + // 1st delegator delegate to 1st node. + _, addrDelegator := g.newPrefundAccount() + + balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) + input, err = abiObject.Pack("delegate", addr) + g.Require().NoError(err) + + _, err = g.call(addrDelegator, input, amount) + g.Require().NoError(err) + g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) + g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) + g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) + g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) + g.Require().Equal(1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) + + // Same person delegate the 2nd time should fail. + _, err = g.call(addrDelegator, input, big.NewInt(1e18)) + g.Require().NotNil(err) + + // Not yet qualified. + g.Require().Equal(0, len(g.s.QualifiedNodes())) + + // 2nd delegator delegate to 1st node. + _, addrDelegator2 := g.newPrefundAccount() + _, err = g.call(addrDelegator2, input, amount) + g.Require().NoError(err) + g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) + g.Require().Equal(addrDelegator2, g.s.Delegator(addr, big.NewInt(2)).Owner) + g.Require().Equal(new(big.Int).Add(ownerStaked, new(big.Int).Mul(amount, big.NewInt(2))), + g.s.Node(big.NewInt(0)).Staked) + g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) + g.Require().Equal(2, int(g.s.DelegatorsOffset(addr, addrDelegator2).Int64())) + + // Qualified. + g.Require().Equal(1, len(g.s.QualifiedNodes())) + + // Undelegate addrDelegator. + balanceBeforeUnDelegate := g.stateDB.GetBalance(addrDelegator) + input, err = abiObject.Pack("undelegate", addr) + g.Require().NoError(err) + _, err = g.call(addrDelegator, input, big.NewInt(0)) + g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) + g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) + g.Require().NoError(err) + + // Undelegate the second time should fail. + _, err = g.call(addrDelegator, input, big.NewInt(0)) + g.Require().Error(err) + + // Withdraw within lockup time should fail. + input, err = abiObject.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(addrDelegator, input, big.NewInt(0)) + g.Require().NotNil(err) + + g.Require().Equal(3, int(g.s.LenDelegators(addr).Uint64())) + g.Require().Equal(balanceBeforeUnDelegate, g.stateDB.GetBalance(addrDelegator)) + g.Require().NotEqual(-1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) + + // Wait for lockup time than withdraw. + time.Sleep(time.Second * 2) + input, err = abiObject.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(addrDelegator, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(2, int(g.s.LenDelegators(addr).Uint64())) + g.Require().Equal(new(big.Int).Add(balanceBeforeUnDelegate, amount), g.stateDB.GetBalance(addrDelegator)) + g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) + + // Withdraw when their is no delegation should fail. + time.Sleep(time.Second) + input, err = abiObject.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(addrDelegator, input, big.NewInt(0)) + g.Require().Error(err) + + // Undelegate addrDelegator2. + balanceBeforeUnDelegate = g.stateDB.GetBalance(addrDelegator2) + input, err = abiObject.Pack("undelegate", addr) + g.Require().NoError(err) + _, err = g.call(addrDelegator2, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) + g.Require().Equal(g.s.Node(big.NewInt(0)).Staked.String(), g.s.TotalStaked().String()) + + // Wait for lockup time than withdraw. + time.Sleep(time.Second * 2) + input, err = abiObject.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(addrDelegator2, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) + g.Require().Equal(new(big.Int).Add(balanceBeforeUnDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) + g.Require().Equal(-1, int(g.s.DelegatorsOffset(addr, addrDelegator2).Int64())) + + // Unqualified + g.Require().Equal(0, len(g.s.QualifiedNodes())) + + // Owner undelegate itself. + g.Require().Equal(1, int(g.s.LenNodes().Uint64())) + g.Require().Equal(1, int(g.s.LenDelegators(addr).Uint64())) + + input, err = abiObject.Pack("undelegate", addr) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + g.Require().Equal(big.NewInt(0).String(), g.s.Node(big.NewInt(0)).Staked.String()) + g.Require().Equal(big.NewInt(0).String(), g.s.TotalStaked().String()) + + time.Sleep(time.Second * 2) + input, err = abiObject.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + + g.Require().Equal(0, int(g.s.LenNodes().Uint64())) + g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) +} + +func (g *GovernanceContractTestSuite) TestFine() { + privKey, addr := g.newPrefundAccount() + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + // Stake. + input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + ownerStaked := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + _, err = g.call(addr, input, ownerStaked) + g.Require().NoError(err) + g.Require().Equal(0, len(g.s.QualifiedNodes())) + g.Require().Equal(addr, g.s.Delegator(addr, big.NewInt(0)).Owner) + g.Require().Equal(ownerStaked, g.s.Node(big.NewInt(0)).Staked) + + // 1st delegator delegate to 1st node. + _, addrDelegator := g.newPrefundAccount() + + balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + input, err = abiObject.Pack("delegate", addr) + g.Require().NoError(err) + + _, err = g.call(addrDelegator, input, amount) + g.Require().NoError(err) + g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) + g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) + g.Require().Equal(new(big.Int).Add(amount, ownerStaked), g.s.Node(big.NewInt(0)).Staked) + g.Require().Equal(1, int(g.s.DelegatorsOffset(addr, addrDelegator).Int64())) + + // Qualified. + g.Require().Equal(1, len(g.s.QualifiedNodes())) + + // Paying to node without fine should fail. + input, err = abiObject.Pack("payFine", addr) + g.Require().NoError(err) + _, err = g.call(addrDelegator, input, amount) + g.Require().NotNil(err) + + // Fined. + offset := g.s.NodesOffsetByAddress(addr) + g.Require().True(offset.Cmp(big.NewInt(0)) >= 0) + node := g.s.Node(offset) + node.Fined = new(big.Int).Set(amount) + g.s.UpdateNode(offset, node) + node = g.s.Node(offset) + g.Require().Equal(0, node.Fined.Cmp(amount)) + + // Not qualified after fined. + g.Require().Equal(0, len(g.s.QualifiedNodes())) + + // Cannot undelegate before fines are paied. + input, err = abiObject.Pack("undelegate", addr) + g.Require().NoError(err) + _, err = g.call(addrDelegator, input, big.NewInt(0)) + g.Require().NotNil(err) + + // Only delegators can pay fine. + _, addrDelegator2 := g.newPrefundAccount() + input, err = abiObject.Pack("payFine", addr) + g.Require().NoError(err) + _, err = g.call(addrDelegator2, input, big.NewInt(5e5)) + g.Require().NotNil(err) + + // Paying more than fine should fail. + payAmount := new(big.Int).Add(amount, amount) + input, err = abiObject.Pack("payFine", addr) + g.Require().NoError(err) + _, err = g.call(addrDelegator, input, payAmount) + g.Require().NotNil(err) + + // Pay the fine. + input, err = abiObject.Pack("payFine", addr) + g.Require().NoError(err) + _, err = g.call(addrDelegator, input, amount) + g.Require().NoError(err) + + // Qualified. + g.Require().Equal(1, len(g.s.QualifiedNodes())) + + // Can undelegate after all fines are paied. + input, err = abiObject.Pack("undelegate", addr) + g.Require().NoError(err) + _, err = g.call(addrDelegator, input, big.NewInt(0)) + g.Require().NoError(err) +} + +func (g *GovernanceContractTestSuite) TestUnstakeWithExtraDelegators() { + privKey, addr := g.newPrefundAccount() + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + input, err := abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(addr, input, amount) + g.Require().NoError(err) + + // 1st delegator delegate to 1st node. + _, addrDelegator := g.newPrefundAccount() + + balanceBeforeDelegate := g.stateDB.GetBalance(addrDelegator) + amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) + input, err = abiObject.Pack("delegate", addr) + g.Require().NoError(err) + + _, err = g.call(addrDelegator, input, amount) + g.Require().NoError(err) + g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator)) + g.Require().Equal(addrDelegator, g.s.Delegator(addr, big.NewInt(1)).Owner) + g.Require().Equal(0, len(g.s.QualifiedNodes())) + + // 2st delegator delegate to 1st node. + _, addrDelegator2 := g.newPrefundAccount() + + balanceBeforeDelegate = g.stateDB.GetBalance(addrDelegator2) + input, err = abiObject.Pack("delegate", addr) + g.Require().NoError(err) + + _, err = g.call(addrDelegator2, input, amount) + g.Require().NoError(err) + g.Require().Equal(new(big.Int).Sub(balanceBeforeDelegate, amount), g.stateDB.GetBalance(addrDelegator2)) + g.Require().Equal(addrDelegator2, g.s.Delegator(addr, big.NewInt(2)).Owner) + + // Node is now qualified. + g.Require().Equal(1, len(g.s.QualifiedNodes())) + + // Unstake. + input, err = abiObject.Pack("unstake") + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + + time.Sleep(time.Second * 2) + input, err = abiObject.Pack("withdraw", addr) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + _, err = g.call(addrDelegator, input, big.NewInt(0)) + g.Require().NoError(err) + _, err = g.call(addrDelegator2, input, big.NewInt(0)) + g.Require().NoError(err) + + g.Require().Equal(0, int(g.s.LenDelegators(addr).Uint64())) + g.Require().Equal(0, int(g.s.LenNodes().Uint64())) + + // Check balance. + g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addr)) + g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addrDelegator)) + g.Require().Equal(balanceBeforeDelegate, g.stateDB.GetBalance(addrDelegator2)) + g.Require().Equal(big.NewInt(1), g.stateDB.GetBalance(GovernanceContractAddress)) +} + +func (g *GovernanceContractTestSuite) TestUpdateConfiguration() { + _, addr := g.newPrefundAccount() + + input, err := abiObject.Pack("updateConfiguration", + new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)), + big.NewInt(1000), + big.NewInt(0.1875*decimalMultiplier), + big.NewInt(1e18), + big.NewInt(1e18), + big.NewInt(8000000), + big.NewInt(6), + big.NewInt(250), + big.NewInt(2500), + big.NewInt(0), + big.NewInt(667000), + big.NewInt(4), + big.NewInt(4), + big.NewInt(600000), + big.NewInt(900), + []*big.Int{big.NewInt(1), big.NewInt(1), big.NewInt(1)}) + g.Require().NoError(err) + + // Call with non-owner. + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NotNil(err) + + // Call with owner. + _, err = g.call(g.config.Owner, input, big.NewInt(0)) + g.Require().NoError(err) +} + +func (g *GovernanceContractTestSuite) TestSnapshotRound() { + _, addr := g.newPrefundAccount() + + // Wrong height. + input, err := abiObject.Pack("snapshotRound", big.NewInt(1), big.NewInt(666)) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NotNil(err) + + // Invalid round. + input, err = abiObject.Pack("snapshotRound", big.NewInt(2), big.NewInt(2000)) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NotNil(err) + + // Correct. + input, err = abiObject.Pack("snapshotRound", big.NewInt(1), big.NewInt(1000)) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + + // Duplicate round. + input, err = abiObject.Pack("snapshotRound", big.NewInt(1), big.NewInt(1000)) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NotNil(err) + + // Invalid round. + input, err = abiObject.Pack("snapshotRound", big.NewInt(3), big.NewInt(3000)) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NotNil(err) + + // Correct. + input, err = abiObject.Pack("snapshotRound", big.NewInt(2), big.NewInt(2000)) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) +} + +func (g *GovernanceContractTestSuite) TestConfigurationReading() { + _, addr := g.newPrefundAccount() + + // CRS. + input, err := abiObject.Pack("crs", big.NewInt(0)) + g.Require().NoError(err) + res, err := g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + var crs0 [32]byte + err = abiObject.Unpack(&crs0, "crs", res) + g.Require().NoError(err) + g.Require().Equal(crypto.Keccak256Hash([]byte(g.config.GenesisCRSText)), common.BytesToHash(crs0[:])) + + // Owner. + input, err = abiObject.Pack("owner") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + var owner common.Address + err = abiObject.Unpack(&owner, "owner", res) + g.Require().NoError(err) + g.Require().Equal(g.config.Owner, owner) + + // MinStake. + input, err = abiObject.Pack("minStake") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + var value *big.Int + err = abiObject.Unpack(&value, "minStake", res) + g.Require().NoError(err) + g.Require().Equal(g.config.MinStake.String(), value.String()) + + // BlockReward. + input, err = abiObject.Pack("miningVelocity") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "miningVelocity", res) + g.Require().NoError(err) + g.Require().Equal(g.config.MiningVelocity, float32(value.Uint64())/decimalMultiplier) + + // BlockGasLimit. + input, err = abiObject.Pack("blockGasLimit") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "blockGasLimit", res) + g.Require().NoError(err) + g.Require().Equal(g.config.BlockGasLimit, value.Uint64()) + + // NumChains. + input, err = abiObject.Pack("numChains") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "numChains", res) + g.Require().NoError(err) + g.Require().Equal(g.config.NumChains, uint32(value.Uint64())) + + // LambdaBA. + input, err = abiObject.Pack("lambdaBA") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "lambdaBA", res) + g.Require().NoError(err) + g.Require().Equal(g.config.LambdaBA, value.Uint64()) + + // LambdaDKG. + input, err = abiObject.Pack("lambdaDKG") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "lambdaDKG", res) + g.Require().NoError(err) + g.Require().Equal(g.config.LambdaDKG, value.Uint64()) + + // K. + input, err = abiObject.Pack("k") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "k", res) + g.Require().NoError(err) + g.Require().Equal(g.config.K, uint32(value.Uint64())) + + // PhiRatio. + input, err = abiObject.Pack("phiRatio") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "phiRatio", res) + g.Require().NoError(err) + g.Require().Equal(g.config.PhiRatio, float32(value.Uint64())/decimalMultiplier) + + // NotarySetSize. + input, err = abiObject.Pack("notarySetSize") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "notarySetSize", res) + g.Require().NoError(err) + g.Require().Equal(g.config.NotarySetSize, uint32(value.Uint64())) + + // DKGSetSize. + input, err = abiObject.Pack("dkgSetSize") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "dkgSetSize", res) + g.Require().NoError(err) + g.Require().Equal(g.config.DKGSetSize, uint32(value.Uint64())) + + // RoundInterval. + input, err = abiObject.Pack("roundInterval") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "roundInterval", res) + g.Require().NoError(err) + g.Require().Equal(g.config.RoundInterval, value.Uint64()) + + // MinBlockInterval. + input, err = abiObject.Pack("minBlockInterval") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "minBlockInterval", res) + g.Require().NoError(err) + g.Require().Equal(g.config.MinBlockInterval, value.Uint64()) +} + +func (g *GovernanceContractTestSuite) TestReportForkVote() { + key, addr := g.newPrefundAccount() + pkBytes := crypto.FromECDSAPub(&key.PublicKey) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + input, err := abiObject.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(addr, input, amount) + g.Require().NoError(err) + + pubKey := coreEcdsa.NewPublicKeyFromECDSA(&key.PublicKey) + privKey := coreEcdsa.NewPrivateKeyFromECDSA(key) + vote1 := coreTypes.NewVote(coreTypes.VoteCom, coreCommon.NewRandomHash(), uint64(0)) + vote1.ProposerID = coreTypes.NewNodeID(pubKey) + + vote2 := vote1.Clone() + for vote2.BlockHash == vote1.BlockHash { + vote2.BlockHash = coreCommon.NewRandomHash() + } + vote1.Signature, err = privKey.Sign(coreUtils.HashVote(vote1)) + g.Require().NoError(err) + vote2.Signature, err = privKey.Sign(coreUtils.HashVote(vote2)) + g.Require().NoError(err) + + vote1Bytes, err := rlp.EncodeToBytes(vote1) + g.Require().NoError(err) + vote2Bytes, err := rlp.EncodeToBytes(vote2) + g.Require().NoError(err) + + // Report wrong type (fork block) + input, err = abiObject.Pack("report", big.NewInt(2), vote1Bytes, vote2Bytes) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().Error(err) + + input, err = abiObject.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + + node := g.s.Node(big.NewInt(0)) + g.Require().Equal(node.Fined, g.s.FineValue(big.NewInt(1))) + + // Duplicate report should fail. + input, err = abiObject.Pack("report", big.NewInt(1), vote1Bytes, vote2Bytes) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().Error(err) + + // Check if finedRecords is set. + payloads := [][]byte{vote1Bytes, vote2Bytes} + sort.Sort(sortBytes(payloads)) + + hash := Bytes32(crypto.Keccak256Hash(payloads...)) + input, err = abiObject.Pack("finedRecords", hash) + g.Require().NoError(err) + res, err := g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + + var value bool + err = abiObject.Unpack(&value, "finedRecords", res) + g.Require().NoError(err) + g.Require().True(value) +} + +func (g *GovernanceContractTestSuite) TestReportForkBlock() { + key, addr := g.newPrefundAccount() + pkBytes := crypto.FromECDSAPub(&key.PublicKey) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + input, err := abiObject.Pack("stake", pkBytes, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(addr, input, amount) + g.Require().NoError(err) + + privKey := coreEcdsa.NewPrivateKeyFromECDSA(key) + block1 := &coreTypes.Block{ + ProposerID: coreTypes.NewNodeID(privKey.PublicKey()), + ParentHash: coreCommon.NewRandomHash(), + Timestamp: time.Now(), + } + + block2 := block1.Clone() + for block2.ParentHash == block1.ParentHash { + block2.ParentHash = coreCommon.NewRandomHash() + } + + hashBlock := func(block *coreTypes.Block) coreCommon.Hash { + block.PayloadHash = coreCrypto.Keccak256Hash(block.Payload) + var err error + block.Hash, err = coreUtils.HashBlock(block) + g.Require().NoError(err) + return block.Hash + } + + block1.Signature, err = privKey.Sign(hashBlock(block1)) + g.Require().NoError(err) + block2.Signature, err = privKey.Sign(hashBlock(block2)) + g.Require().NoError(err) + + block1Bytes, err := rlp.EncodeToBytes(block1) + g.Require().NoError(err) + block2Bytes, err := rlp.EncodeToBytes(block2) + g.Require().NoError(err) + + // Report wrong type (fork vote) + input, err = abiObject.Pack("report", big.NewInt(1), block1Bytes, block2Bytes) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().Error(err) + + input, err = abiObject.Pack("report", big.NewInt(2), block1Bytes, block2Bytes) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + + node := g.s.Node(big.NewInt(0)) + g.Require().Equal(node.Fined, g.s.FineValue(big.NewInt(2))) + + // Duplicate report should fail. + input, err = abiObject.Pack("report", big.NewInt(2), block1Bytes, block2Bytes) + g.Require().NoError(err) + _, err = g.call(addr, input, big.NewInt(0)) + g.Require().Error(err) + + // Check if finedRecords is set. + payloads := [][]byte{block1Bytes, block2Bytes} + sort.Sort(sortBytes(payloads)) + + hash := Bytes32(crypto.Keccak256Hash(payloads...)) + input, err = abiObject.Pack("finedRecords", hash) + g.Require().NoError(err) + res, err := g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + + var value bool + err = abiObject.Unpack(&value, "finedRecords", res) + g.Require().NoError(err) + g.Require().True(value) +} + +func (g *GovernanceContractTestSuite) TestMiscVariableReading() { + privKey, addr := g.newPrefundAccount() + pk := crypto.FromECDSAPub(&privKey.PublicKey) + + input, err := abiObject.Pack("totalSupply") + g.Require().NoError(err) + res, err := g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + + input, err = abiObject.Pack("totalStaked") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + + // Stake. + amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(5e5)) + input, err = abiObject.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + g.Require().NoError(err) + _, err = g.call(addr, input, amount) + g.Require().NoError(err) + + // 1st delegator delegate to 1st node. + _, addrDelegator := g.newPrefundAccount() + amount = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3e5)) + input, err = abiObject.Pack("delegate", addr) + g.Require().NoError(err) + _, err = g.call(addrDelegator, input, amount) + g.Require().NoError(err) + + // 2st delegator delegate to 1st node. + _, addrDelegator2 := g.newPrefundAccount() + input, err = abiObject.Pack("delegate", addr) + g.Require().NoError(err) + _, err = g.call(addrDelegator2, input, amount) + g.Require().NoError(err) + + input, err = abiObject.Pack("nodes", big.NewInt(0)) + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + + input, err = abiObject.Pack("nodesLength") + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + var value *big.Int + err = abiObject.Unpack(&value, "nodesLength", res) + g.Require().NoError(err) + g.Require().Equal(1, int(value.Uint64())) + + input, err = abiObject.Pack("nodesOffsetByAddress", addr) + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "nodesOffsetByAddress", res) + g.Require().NoError(err) + g.Require().Equal(0, int(value.Uint64())) + + id, err := publicKeyToNodeID(pk) + g.Require().NoError(err) + input, err = abiObject.Pack("nodesOffsetByID", id) + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "nodesOffsetByID", res) + g.Require().NoError(err) + g.Require().Equal(0, int(value.Uint64())) + + input, err = abiObject.Pack("delegators", addr, big.NewInt(0)) + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + + input, err = abiObject.Pack("delegatorsLength", addr) + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "delegatorsLength", res) + g.Require().NoError(err) + g.Require().Equal(3, int(value.Uint64())) + + input, err = abiObject.Pack("delegatorsOffset", addr, addrDelegator2) + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) + err = abiObject.Unpack(&value, "delegatorsOffset", res) + g.Require().NoError(err) + g.Require().Equal(2, int(value.Uint64())) + + input, err = abiObject.Pack("fineValues", big.NewInt(0)) + g.Require().NoError(err) + res, err = g.call(addr, input, big.NewInt(0)) + g.Require().NoError(err) +} + +func (g *GovernanceContractTestSuite) TestHalvingCondition() { + // TotalSupply 2.5B reached + g.s.MiningHalved() + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3.25e9)).String(), + g.s.NextHalvingSupply().String()) + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(0.75e9)).String(), + g.s.LastHalvedAmount().String()) + + // TotalSupply 3.25B reached + g.s.MiningHalved() + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(3.625e9)).String(), + g.s.NextHalvingSupply().String()) + g.Require().Equal(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(0.375e9)).String(), + g.s.LastHalvedAmount().String()) +} + +func TestGovernanceContract(t *testing.T) { + suite.Run(t, new(GovernanceContractTestSuite)) +} diff --git a/core/vm/instructions.go b/core/vm/evm/instructions.go index cb1f1bbaa..d37ab5e43 100644 --- a/core/vm/instructions.go +++ b/core/vm/evm/instructions.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "encoding/binary" @@ -25,6 +25,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/common/math" "github.com/dexon-foundation/dexon/core/types" + "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/params" "golang.org/x/crypto/sha3" @@ -50,48 +51,48 @@ func init() { } } -func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := stack.Pop(), stack.Peek() math.U256(y.Add(x, y)) - interpreter.intPool.put(x) + interpreter.intPool.Put(x) return nil, nil } -func opSub(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opSub(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := stack.Pop(), stack.Peek() math.U256(y.Sub(x, y)) - interpreter.intPool.put(x) + interpreter.intPool.Put(x) return nil, nil } -func opMul(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() - stack.push(math.U256(x.Mul(x, y))) +func opMul(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := stack.Pop(), stack.Pop() + stack.Push(math.U256(x.Mul(x, y))) - interpreter.intPool.put(y) + interpreter.intPool.Put(y) return nil, nil } -func opDiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opDiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := stack.Pop(), stack.Peek() if y.Sign() != 0 { math.U256(y.Div(x, y)) } else { y.SetUint64(0) } - interpreter.intPool.put(x) + interpreter.intPool.Put(x) return nil, nil } -func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := math.S256(stack.pop()), math.S256(stack.pop()) - res := interpreter.intPool.getZero() +func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := math.S256(stack.Pop()), math.S256(stack.Pop()) + res := interpreter.intPool.GetZero() if y.Sign() == 0 || x.Sign() == 0 { - stack.push(res) + stack.Push(res) } else { if x.Sign() != y.Sign() { res.Div(x.Abs(x), y.Abs(y)) @@ -99,29 +100,29 @@ func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory } else { res.Div(x.Abs(x), y.Abs(y)) } - stack.push(math.U256(res)) + stack.Push(math.U256(res)) } - interpreter.intPool.put(x, y) + interpreter.intPool.Put(x, y) return nil, nil } -func opMod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() +func opMod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := stack.Pop(), stack.Pop() if y.Sign() == 0 { - stack.push(x.SetUint64(0)) + stack.Push(x.SetUint64(0)) } else { - stack.push(math.U256(x.Mod(x, y))) + stack.Push(math.U256(x.Mod(x, y))) } - interpreter.intPool.put(y) + interpreter.intPool.Put(y) return nil, nil } -func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := math.S256(stack.pop()), math.S256(stack.pop()) - res := interpreter.intPool.getZero() +func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := math.S256(stack.Pop()), math.S256(stack.Pop()) + res := interpreter.intPool.GetZero() if y.Sign() == 0 { - stack.push(res) + stack.Push(res) } else { if x.Sign() < 0 { res.Mod(x.Abs(x), y.Abs(y)) @@ -129,31 +130,31 @@ func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory } else { res.Mod(x.Abs(x), y.Abs(y)) } - stack.push(math.U256(res)) + stack.Push(math.U256(res)) } - interpreter.intPool.put(x, y) + interpreter.intPool.Put(x, y) return nil, nil } -func opExp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - base, exponent := stack.pop(), stack.pop() +func opExp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + base, exponent := stack.Pop(), stack.Pop() if base.Cmp(big2) == 0 && exponent.Cmp(big256) == -1 { exp := exponent.Int64() - stack.push(interpreter.intPool.get().Set(power2[exp])) + stack.Push(interpreter.intPool.Get().Set(power2[exp])) } else { - stack.push(math.Exp(base, exponent)) + stack.Push(math.Exp(base, exponent)) } - interpreter.intPool.put(base, exponent) + interpreter.intPool.Put(base, exponent) return nil, nil } -func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - back := stack.pop() +func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + back := stack.Pop() if back.Cmp(big.NewInt(31)) < 0 { bit := uint(back.Uint64()*8 + 7) - num := stack.pop() + num := stack.Pop() mask := back.Lsh(common.Big1, bit) mask.Sub(mask, common.Big1) if num.Bit(int(bit)) > 0 { @@ -162,43 +163,43 @@ func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, m num.And(num, mask) } - stack.push(math.U256(num)) + stack.Push(math.U256(num)) } - interpreter.intPool.put(back) + interpreter.intPool.Put(back) return nil, nil } -func opNot(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x := stack.peek() +func opNot(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x := stack.Peek() math.U256(x.Not(x)) return nil, nil } -func opLt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opLt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := stack.Pop(), stack.Peek() if x.Cmp(y) < 0 { y.SetUint64(1) } else { y.SetUint64(0) } - interpreter.intPool.put(x) + interpreter.intPool.Put(x) return nil, nil } -func opGt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opGt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := stack.Pop(), stack.Peek() if x.Cmp(y) > 0 { y.SetUint64(1) } else { y.SetUint64(0) } - interpreter.intPool.put(x) + interpreter.intPool.Put(x) return nil, nil } -func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := stack.Pop(), stack.Peek() xSign := x.Cmp(tt255) ySign := y.Cmp(tt255) @@ -217,12 +218,12 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * y.SetUint64(0) } } - interpreter.intPool.put(x) + interpreter.intPool.Put(x) return nil, nil } -func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := stack.Pop(), stack.Peek() xSign := x.Cmp(tt255) ySign := y.Cmp(tt255) @@ -241,23 +242,23 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * y.SetUint64(0) } } - interpreter.intPool.put(x) + interpreter.intPool.Put(x) return nil, nil } -func opEq(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opEq(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := stack.Pop(), stack.Peek() if x.Cmp(y) == 0 { y.SetUint64(1) } else { y.SetUint64(0) } - interpreter.intPool.put(x) + interpreter.intPool.Put(x) return nil, nil } -func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x := stack.peek() +func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x := stack.Peek() if x.Sign() > 0 { x.SetUint64(0) } else { @@ -266,75 +267,75 @@ func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor return nil, nil } -func opAnd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() - stack.push(x.And(x, y)) +func opAnd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := stack.Pop(), stack.Pop() + stack.Push(x.And(x, y)) - interpreter.intPool.put(y) + interpreter.intPool.Put(y) return nil, nil } -func opOr(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opOr(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := stack.Pop(), stack.Peek() y.Or(x, y) - interpreter.intPool.put(x) + interpreter.intPool.Put(x) return nil, nil } -func opXor(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opXor(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y := stack.Pop(), stack.Peek() y.Xor(x, y) - interpreter.intPool.put(x) + interpreter.intPool.Put(x) return nil, nil } -func opByte(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - th, val := stack.pop(), stack.peek() +func opByte(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + th, val := stack.Pop(), stack.Peek() if th.Cmp(common.Big32) < 0 { b := math.Byte(val, 32, int(th.Int64())) val.SetUint64(uint64(b)) } else { val.SetUint64(0) } - interpreter.intPool.put(th) + interpreter.intPool.Put(th) return nil, nil } -func opAddmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y, z := stack.pop(), stack.pop(), stack.pop() +func opAddmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y, z := stack.Pop(), stack.Pop(), stack.Pop() if z.Cmp(bigZero) > 0 { x.Add(x, y) x.Mod(x, z) - stack.push(math.U256(x)) + stack.Push(math.U256(x)) } else { - stack.push(x.SetUint64(0)) + stack.Push(x.SetUint64(0)) } - interpreter.intPool.put(y, z) + interpreter.intPool.Put(y, z) return nil, nil } -func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y, z := stack.pop(), stack.pop(), stack.pop() +func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + x, y, z := stack.Pop(), stack.Pop(), stack.Pop() if z.Cmp(bigZero) > 0 { x.Mul(x, y) x.Mod(x, z) - stack.push(math.U256(x)) + stack.Push(math.U256(x)) } else { - stack.push(x.SetUint64(0)) + stack.Push(x.SetUint64(0)) } - interpreter.intPool.put(y, z) + interpreter.intPool.Put(y, z) return nil, nil } // opSHL implements Shift Left // The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the left by arg1 number of bits. -func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards - shift, value := math.U256(stack.pop()), math.U256(stack.peek()) - defer interpreter.intPool.put(shift) // First operand back into the pool + shift, value := math.U256(stack.Pop()), math.U256(stack.Peek()) + defer interpreter.intPool.Put(shift) // First operand back into the pool if shift.Cmp(common.Big256) >= 0 { value.SetUint64(0) @@ -349,10 +350,10 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * // opSHR implements Logical Shift Right // The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill. -func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards - shift, value := math.U256(stack.pop()), math.U256(stack.peek()) - defer interpreter.intPool.put(shift) // First operand back into the pool + shift, value := math.U256(stack.Pop()), math.U256(stack.Peek()) + defer interpreter.intPool.Put(shift) // First operand back into the pool if shift.Cmp(common.Big256) >= 0 { value.SetUint64(0) @@ -367,10 +368,10 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * // opSAR implements Arithmetic Shift Right // The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension. -func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Note, S256 returns (potentially) a new bigint, so we're popping, not peeking this one - shift, value := math.U256(stack.pop()), math.S256(stack.pop()) - defer interpreter.intPool.put(shift) // First operand back into the pool + shift, value := math.U256(stack.Pop()), math.S256(stack.Pop()) + defer interpreter.intPool.Put(shift) // First operand back into the pool if shift.Cmp(common.Big256) >= 0 { if value.Sign() >= 0 { @@ -378,18 +379,18 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * } else { value.SetInt64(-1) } - stack.push(math.U256(value)) + stack.Push(math.U256(value)) return nil, nil } n := uint(shift.Uint64()) value.Rsh(value, n) - stack.push(math.U256(value)) + stack.Push(math.U256(value)) return nil, nil } -func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - offset, size := stack.pop(), stack.pop() +func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + offset, size := stack.Pop(), stack.Pop() data := memory.Get(offset.Int64(), size.Int64()) if interpreter.hasher == nil { @@ -404,13 +405,13 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory if evm.vmConfig.EnablePreimageRecording { evm.StateDB.AddPreimage(interpreter.hasherBuf, data) } - stack.push(interpreter.intPool.get().SetBytes(interpreter.hasherBuf[:])) + stack.Push(interpreter.intPool.Get().SetBytes(interpreter.hasherBuf[:])) - interpreter.intPool.put(offset, size) + interpreter.intPool.Put(offset, size) return nil, nil } -func opRand(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opRand(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { evm := interpreter.evm nonce := evm.StateDB.GetNonce(evm.Origin) @@ -428,72 +429,72 @@ func opRand(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory binaryOriginNonce, binaryUsedIndex) - stack.push(interpreter.intPool.get().SetBytes(hash)) + stack.Push(interpreter.intPool.Get().SetBytes(hash)) return nil, nil } -func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(contract.Address().Big()) +func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(contract.Address().Big()) return nil, nil } -func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - slot := stack.peek() +func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + slot := stack.Peek() slot.Set(interpreter.evm.StateDB.GetBalance(common.BigToAddress(slot))) return nil, nil } -func opOrigin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.evm.Origin.Big()) +func opOrigin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(interpreter.evm.Origin.Big()) return nil, nil } -func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(contract.Caller().Big()) +func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(contract.Caller().Big()) return nil, nil } -func opCallValue(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().Set(contract.value)) +func opCallValue(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(interpreter.intPool.Get().Set(contract.value)) return nil, nil } -func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetBytes(getDataBig(contract.Input, stack.pop(), big32))) +func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(interpreter.intPool.Get().SetBytes(vm.GetDataBig(contract.Input, stack.Pop(), big32))) return nil, nil } -func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetInt64(int64(len(contract.Input)))) +func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(interpreter.intPool.Get().SetInt64(int64(len(contract.Input)))) return nil, nil } -func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { var ( - memOffset = stack.pop() - dataOffset = stack.pop() - length = stack.pop() + memOffset = stack.Pop() + dataOffset = stack.Pop() + length = stack.Pop() ) - memory.Set(memOffset.Uint64(), length.Uint64(), getDataBig(contract.Input, dataOffset, length)) + memory.Set(memOffset.Uint64(), length.Uint64(), vm.GetDataBig(contract.Input, dataOffset, length)) - interpreter.intPool.put(memOffset, dataOffset, length) + interpreter.intPool.Put(memOffset, dataOffset, length) return nil, nil } -func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetUint64(uint64(len(interpreter.returnData)))) +func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(interpreter.intPool.Get().SetUint64(uint64(len(interpreter.returnData)))) return nil, nil } -func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { var ( - memOffset = stack.pop() - dataOffset = stack.pop() - length = stack.pop() + memOffset = stack.Pop() + dataOffset = stack.Pop() + length = stack.Pop() - end = interpreter.intPool.get().Add(dataOffset, length) + end = interpreter.intPool.Get().Add(dataOffset, length) ) - defer interpreter.intPool.put(memOffset, dataOffset, length, end) + defer interpreter.intPool.Put(memOffset, dataOffset, length, end) if end.BitLen() > 64 || uint64(len(interpreter.returnData)) < end.Uint64() { return nil, errReturnDataOutOfBounds @@ -503,44 +504,44 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contrac return nil, nil } -func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - slot := stack.peek() +func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + slot := stack.Peek() slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.BigToAddress(slot)))) return nil, nil } -func opCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - l := interpreter.intPool.get().SetInt64(int64(len(contract.Code))) - stack.push(l) +func opCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + l := interpreter.intPool.Get().SetInt64(int64(len(contract.Code))) + stack.Push(l) return nil, nil } -func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { var ( - memOffset = stack.pop() - codeOffset = stack.pop() - length = stack.pop() + memOffset = stack.Pop() + codeOffset = stack.Pop() + length = stack.Pop() ) - codeCopy := getDataBig(contract.Code, codeOffset, length) + codeCopy := vm.GetDataBig(contract.Code, codeOffset, length) memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) - interpreter.intPool.put(memOffset, codeOffset, length) + interpreter.intPool.Put(memOffset, codeOffset, length) return nil, nil } -func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { var ( - addr = common.BigToAddress(stack.pop()) - memOffset = stack.pop() - codeOffset = stack.pop() - length = stack.pop() + addr = common.BigToAddress(stack.Pop()) + memOffset = stack.Pop() + codeOffset = stack.Pop() + length = stack.Pop() ) - codeCopy := getDataBig(interpreter.evm.StateDB.GetCode(addr), codeOffset, length) + codeCopy := vm.GetDataBig(interpreter.evm.StateDB.GetCode(addr), codeOffset, length) memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) - interpreter.intPool.put(memOffset, codeOffset, length) + interpreter.intPool.Put(memOffset, codeOffset, length) return nil, nil } @@ -570,8 +571,8 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, // // (6) Caller tries to get the code hash for an account which is marked as deleted, // this account should be regarded as a non-existent account and zero should be returned. -func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - slot := stack.peek() +func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + slot := stack.Peek() address := common.BigToAddress(slot) if interpreter.evm.StateDB.Empty(address) { slot.SetUint64(0) @@ -581,109 +582,109 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, return nil, nil } -func opGasprice(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().Set(interpreter.evm.GasPrice)) +func opGasprice(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(interpreter.intPool.Get().Set(interpreter.evm.GasPrice)) return nil, nil } -func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - num := stack.pop() +func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + num := stack.Pop() - n := interpreter.intPool.get().Sub(interpreter.evm.BlockNumber, common.Big257) + n := interpreter.intPool.Get().Sub(interpreter.evm.BlockNumber, common.Big257) if num.Cmp(n) > 0 && num.Cmp(interpreter.evm.BlockNumber) < 0 { - stack.push(interpreter.evm.GetHash(num.Uint64()).Big()) + stack.Push(interpreter.evm.GetHash(num.Uint64()).Big()) } else { - stack.push(interpreter.intPool.getZero()) + stack.Push(interpreter.intPool.GetZero()) } - interpreter.intPool.put(num, n) + interpreter.intPool.Put(num, n) return nil, nil } -func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.evm.Coinbase.Big()) +func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(interpreter.evm.Coinbase.Big()) return nil, nil } -func opTimestamp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Time))) +func opTimestamp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(math.U256(interpreter.intPool.Get().Set(interpreter.evm.Time))) return nil, nil } -func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockNumber))) +func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(math.U256(interpreter.intPool.Get().Set(interpreter.evm.BlockNumber))) return nil, nil } -func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Difficulty))) +func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(math.U256(interpreter.intPool.Get().Set(interpreter.evm.Difficulty))) return nil, nil } -func opGasLimit(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(interpreter.intPool.get().SetUint64(interpreter.evm.GasLimit))) +func opGasLimit(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(math.U256(interpreter.intPool.Get().SetUint64(interpreter.evm.GasLimit))) return nil, nil } -func opPop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - interpreter.intPool.put(stack.pop()) +func opPop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + interpreter.intPool.Put(stack.Pop()) return nil, nil } -func opMload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - offset := stack.pop() - val := interpreter.intPool.get().SetBytes(memory.Get(offset.Int64(), 32)) - stack.push(val) +func opMload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + offset := stack.Pop() + val := interpreter.intPool.Get().SetBytes(memory.Get(offset.Int64(), 32)) + stack.Push(val) - interpreter.intPool.put(offset) + interpreter.intPool.Put(offset) return nil, nil } -func opMstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opMstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // pop value of the stack - mStart, val := stack.pop(), stack.pop() + mStart, val := stack.Pop(), stack.Pop() memory.Set32(mStart.Uint64(), val) - interpreter.intPool.put(mStart, val) + interpreter.intPool.Put(mStart, val) return nil, nil } -func opMstore8(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - off, val := stack.pop().Int64(), stack.pop().Int64() - memory.store[off] = byte(val & 0xff) +func opMstore8(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + off, val := stack.Pop().Int64(), stack.Pop().Int64() + memory.Store[off] = byte(val & 0xff) return nil, nil } -func opSload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - loc := stack.peek() +func opSload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + loc := stack.Peek() val := interpreter.evm.StateDB.GetState(contract.Address(), common.BigToHash(loc)) loc.SetBytes(val.Bytes()) return nil, nil } -func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - loc := common.BigToHash(stack.pop()) - val := stack.pop() +func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + loc := common.BigToHash(stack.Pop()) + val := stack.Pop() interpreter.evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val)) - interpreter.intPool.put(val) + interpreter.intPool.Put(val) return nil, nil } -func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - pos := stack.pop() +func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + pos := stack.Pop() if !contract.validJumpdest(pos) { nop := contract.GetOp(pos.Uint64()) return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos) } *pc = pos.Uint64() - interpreter.intPool.put(pos) + interpreter.intPool.Put(pos) return nil, nil } -func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - pos, cond := stack.pop(), stack.pop() +func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + pos, cond := stack.Pop(), stack.Pop() if cond.Sign() != 0 { if !contract.validJumpdest(pos) { nop := contract.GetOp(pos.Uint64()) @@ -694,33 +695,33 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *pc++ } - interpreter.intPool.put(pos, cond) + interpreter.intPool.Put(pos, cond) return nil, nil } -func opJumpdest(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opJumpdest(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { return nil, nil } -func opPc(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetUint64(*pc)) +func opPc(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(interpreter.intPool.Get().SetUint64(*pc)) return nil, nil } -func opMsize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetInt64(int64(memory.Len()))) +func opMsize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(interpreter.intPool.Get().SetInt64(int64(memory.Len()))) return nil, nil } -func opGas(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetUint64(contract.Gas)) +func opGas(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(interpreter.intPool.Get().SetUint64(contract.Gas)) return nil, nil } -func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { var ( - value = stack.pop() - offset, size = stack.pop(), stack.pop() + value = stack.Pop() + offset, size = stack.Pop(), stack.Pop() input = memory.Get(offset.Int64(), size.Int64()) gas = contract.Gas ) @@ -734,15 +735,15 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must // ignore this error and pretend the operation was successful. - if interpreter.evm.ChainConfig().IsHomestead(interpreter.evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas { - stack.push(interpreter.intPool.getZero()) - } else if suberr != nil && suberr != ErrCodeStoreOutOfGas { - stack.push(interpreter.intPool.getZero()) + if interpreter.evm.ChainConfig().IsHomestead(interpreter.evm.BlockNumber) && suberr == vm.ErrCodeStoreOutOfGas { + stack.Push(interpreter.intPool.GetZero()) + } else if suberr != nil && suberr != vm.ErrCodeStoreOutOfGas { + stack.Push(interpreter.intPool.GetZero()) } else { - stack.push(addr.Big()) + stack.Push(addr.Big()) } contract.Gas += returnGas - interpreter.intPool.put(value, offset, size) + interpreter.intPool.Put(value, offset, size) if suberr == errExecutionReverted { return res, nil @@ -750,11 +751,11 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor return nil, nil } -func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { var ( - endowment = stack.pop() - offset, size = stack.pop(), stack.pop() - salt = stack.pop() + endowment = stack.Pop() + offset, size = stack.Pop(), stack.Pop() + salt = stack.Pop() input = memory.Get(offset.Int64(), size.Int64()) gas = contract.Gas ) @@ -765,12 +766,12 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo res, addr, returnGas, suberr := interpreter.evm.Create2(contract, input, gas, endowment, salt) // Push item on the stack based on the returned error. if suberr != nil { - stack.push(interpreter.intPool.getZero()) + stack.Push(interpreter.intPool.GetZero()) } else { - stack.push(addr.Big()) + stack.Push(addr.Big()) } contract.Gas += returnGas - interpreter.intPool.put(endowment, offset, size, salt) + interpreter.intPool.Put(endowment, offset, size, salt) if suberr == errExecutionReverted { return res, nil @@ -778,12 +779,12 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo return nil, nil } -func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Pop gas. The actual gas in interpreter.evm.callGasTemp. - interpreter.intPool.put(stack.pop()) + interpreter.intPool.Put(stack.Pop()) gas := interpreter.evm.callGasTemp // Pop other call parameters. - addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + addr, value, inOffset, inSize, retOffset, retSize := stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop() toAddr := common.BigToAddress(addr) value = math.U256(value) // Get the arguments from the memory. @@ -794,25 +795,25 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory } ret, returnGas, err := interpreter.evm.Call(contract, toAddr, args, gas, value) if err != nil { - stack.push(interpreter.intPool.getZero()) + stack.Push(interpreter.intPool.GetZero()) } else { - stack.push(interpreter.intPool.get().SetUint64(1)) + stack.Push(interpreter.intPool.Get().SetUint64(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas - interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) + interpreter.intPool.Put(addr, value, inOffset, inSize, retOffset, retSize) return ret, nil } -func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Pop gas. The actual gas is in interpreter.evm.callGasTemp. - interpreter.intPool.put(stack.pop()) + interpreter.intPool.Put(stack.Pop()) gas := interpreter.evm.callGasTemp // Pop other call parameters. - addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + addr, value, inOffset, inSize, retOffset, retSize := stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop() toAddr := common.BigToAddress(addr) value = math.U256(value) // Get arguments from the memory. @@ -823,92 +824,92 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, mem } ret, returnGas, err := interpreter.evm.CallCode(contract, toAddr, args, gas, value) if err != nil { - stack.push(interpreter.intPool.getZero()) + stack.Push(interpreter.intPool.GetZero()) } else { - stack.push(interpreter.intPool.get().SetUint64(1)) + stack.Push(interpreter.intPool.Get().SetUint64(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas - interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) + interpreter.intPool.Put(addr, value, inOffset, inSize, retOffset, retSize) return ret, nil } -func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Pop gas. The actual gas is in interpreter.evm.callGasTemp. - interpreter.intPool.put(stack.pop()) + interpreter.intPool.Put(stack.Pop()) gas := interpreter.evm.callGasTemp // Pop other call parameters. - addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + addr, inOffset, inSize, retOffset, retSize := stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop() toAddr := common.BigToAddress(addr) // Get arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) ret, returnGas, err := interpreter.evm.DelegateCall(contract, toAddr, args, gas) if err != nil { - stack.push(interpreter.intPool.getZero()) + stack.Push(interpreter.intPool.GetZero()) } else { - stack.push(interpreter.intPool.get().SetUint64(1)) + stack.Push(interpreter.intPool.Get().SetUint64(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas - interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) + interpreter.intPool.Put(addr, inOffset, inSize, retOffset, retSize) return ret, nil } -func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Pop gas. The actual gas is in interpreter.evm.callGasTemp. - interpreter.intPool.put(stack.pop()) + interpreter.intPool.Put(stack.Pop()) gas := interpreter.evm.callGasTemp // Pop other call parameters. - addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + addr, inOffset, inSize, retOffset, retSize := stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop() toAddr := common.BigToAddress(addr) // Get arguments from the memory. args := memory.Get(inOffset.Int64(), inSize.Int64()) ret, returnGas, err := interpreter.evm.StaticCall(contract, toAddr, args, gas) if err != nil { - stack.push(interpreter.intPool.getZero()) + stack.Push(interpreter.intPool.GetZero()) } else { - stack.push(interpreter.intPool.get().SetUint64(1)) + stack.Push(interpreter.intPool.Get().SetUint64(1)) } if err == nil || err == errExecutionReverted { memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } contract.Gas += returnGas - interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) + interpreter.intPool.Put(addr, inOffset, inSize, retOffset, retSize) return ret, nil } -func opReturn(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - offset, size := stack.pop(), stack.pop() +func opReturn(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + offset, size := stack.Pop(), stack.Pop() ret := memory.GetPtr(offset.Int64(), size.Int64()) - interpreter.intPool.put(offset, size) + interpreter.intPool.Put(offset, size) return ret, nil } -func opRevert(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - offset, size := stack.pop(), stack.pop() +func opRevert(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + offset, size := stack.Pop(), stack.Pop() ret := memory.GetPtr(offset.Int64(), size.Int64()) - interpreter.intPool.put(offset, size) + interpreter.intPool.Put(offset, size) return ret, nil } -func opStop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opStop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { return nil, nil } -func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { balance := interpreter.evm.StateDB.GetBalance(contract.Address()) - interpreter.evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance) + interpreter.evm.StateDB.AddBalance(common.BigToAddress(stack.Pop()), balance) interpreter.evm.StateDB.Suicide(contract.Address()) return nil, nil @@ -918,11 +919,11 @@ func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo // make log instruction function func makeLog(size int) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { topics := make([]common.Hash, size) - mStart, mSize := stack.pop(), stack.pop() + mStart, mSize := stack.Pop(), stack.Pop() for i := 0; i < size; i++ { - topics[i] = common.BigToHash(stack.pop()) + topics[i] = common.BigToHash(stack.Pop()) } d := memory.Get(mStart.Int64(), mSize.Int64()) @@ -935,14 +936,14 @@ func makeLog(size int) executionFunc { BlockNumber: interpreter.evm.BlockNumber.Uint64(), }) - interpreter.intPool.put(mStart, mSize) + interpreter.intPool.Put(mStart, mSize) return nil, nil } } // make push instruction function func makePush(size uint64, pushByteSize int) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { codeLen := len(contract.Code) startMin := codeLen @@ -955,8 +956,8 @@ func makePush(size uint64, pushByteSize int) executionFunc { endMin = startMin + pushByteSize } - integer := interpreter.intPool.get() - stack.push(integer.SetBytes(common.RightPadBytes(contract.Code[startMin:endMin], pushByteSize))) + integer := interpreter.intPool.Get() + stack.Push(integer.SetBytes(common.RightPadBytes(contract.Code[startMin:endMin], pushByteSize))) *pc += size return nil, nil @@ -965,8 +966,8 @@ func makePush(size uint64, pushByteSize int) executionFunc { // make dup instruction function func makeDup(size int64) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.dup(interpreter.intPool, int(size)) + return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Dup(interpreter.intPool, int(size)) return nil, nil } } @@ -975,8 +976,8 @@ func makeDup(size int64) executionFunc { func makeSwap(size int64) executionFunc { // switch n + 1 otherwise n would be swapped with n size++ - return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.swap(int(size)) + return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Swap(int(size)) return nil, nil } } diff --git a/core/vm/instructions_test.go b/core/vm/evm/instructions_test.go index 04c03e1a6..9e677dde3 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/evm/instructions_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "bytes" @@ -22,6 +22,7 @@ import ( "testing" "github.com/dexon-foundation/dexon/common" + "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/params" ) @@ -32,37 +33,37 @@ type twoOperandTest struct { expected string } -func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)) { +func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error)) { var ( env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) - stack = newstack() + stack = NewStack() pc = uint64(0) evmInterpreter = NewEVMInterpreter(env, env.vmConfig) ) env.interpreter = evmInterpreter - evmInterpreter.intPool = poolOfIntPools.get() + evmInterpreter.intPool = vm.PoolOfIntPools.Get() for i, test := range tests { x := new(big.Int).SetBytes(common.Hex2Bytes(test.x)) shift := new(big.Int).SetBytes(common.Hex2Bytes(test.y)) expected := new(big.Int).SetBytes(common.Hex2Bytes(test.expected)) - stack.push(x) - stack.push(shift) + stack.Push(x) + stack.Push(shift) opFn(&pc, evmInterpreter, nil, nil, stack) - actual := stack.pop() + actual := stack.Pop() if actual.Cmp(expected) != 0 { t.Errorf("Testcase %d, expected %v, got %v", i, expected, actual) } // Check pool usage // 1.pool is not allowed to contain anything on the stack // 2.pool is not allowed to contain the same pointers twice - if evmInterpreter.intPool.pool.len() > 0 { + if evmInterpreter.intPool.Pool.Len() > 0 { poolvals := make(map[*big.Int]struct{}) poolvals[actual] = struct{}{} - for evmInterpreter.intPool.pool.len() > 0 { - key := evmInterpreter.intPool.get() + for evmInterpreter.intPool.Pool.Len() > 0 { + key := evmInterpreter.intPool.Get() if _, exist := poolvals[key]; exist { t.Errorf("Testcase %d, pool contains double-entry", i) } @@ -70,18 +71,18 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64 } } } - poolOfIntPools.put(evmInterpreter.intPool) + vm.PoolOfIntPools.Put(evmInterpreter.intPool) } func TestByteOp(t *testing.T) { var ( env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) - stack = newstack() + stack = NewStack() evmInterpreter = NewEVMInterpreter(env, env.vmConfig) ) env.interpreter = evmInterpreter - evmInterpreter.intPool = poolOfIntPools.get() + evmInterpreter.intPool = vm.PoolOfIntPools.Get() tests := []struct { v string th uint64 @@ -100,15 +101,15 @@ func TestByteOp(t *testing.T) { for _, test := range tests { val := new(big.Int).SetBytes(common.Hex2Bytes(test.v)) th := new(big.Int).SetUint64(test.th) - stack.push(val) - stack.push(th) + stack.Push(val) + stack.Push(th) opByte(&pc, evmInterpreter, nil, nil, stack) - actual := stack.pop() + actual := stack.Pop() if actual.Cmp(test.expected) != 0 { t.Fatalf("Expected [%v] %v:th byte to be %v, was %v.", test.v, test.th, test.expected, actual) } } - poolOfIntPools.put(evmInterpreter.intPool) + vm.PoolOfIntPools.Put(evmInterpreter.intPool) } func TestSHL(t *testing.T) { @@ -208,15 +209,15 @@ func TestSLT(t *testing.T) { testTwoOperandOp(t, tests, opSlt) } -func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) { +func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error), args ...string) { var ( env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) - stack = newstack() + stack = NewStack() evmInterpreter = NewEVMInterpreter(env, env.vmConfig) ) env.interpreter = evmInterpreter - evmInterpreter.intPool = poolOfIntPools.get() + evmInterpreter.intPool = vm.PoolOfIntPools.Get() // convert args byteArgs := make([][]byte, len(args)) for i, arg := range args { @@ -227,12 +228,12 @@ func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpret for i := 0; i < bench.N; i++ { for _, arg := range byteArgs { a := new(big.Int).SetBytes(arg) - stack.push(a) + stack.Push(a) } op(&pc, evmInterpreter, nil, nil, stack) - stack.pop() + stack.Pop() } - poolOfIntPools.put(evmInterpreter.intPool) + vm.PoolOfIntPools.Put(evmInterpreter.intPool) } func BenchmarkOpAdd64(b *testing.B) { @@ -446,39 +447,39 @@ func BenchmarkOpIsZero(b *testing.B) { func TestOpMstore(t *testing.T) { var ( env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) - stack = newstack() - mem = NewMemory() + stack = NewStack() + mem = vm.NewMemory() evmInterpreter = NewEVMInterpreter(env, env.vmConfig) ) env.interpreter = evmInterpreter - evmInterpreter.intPool = poolOfIntPools.get() + evmInterpreter.intPool = vm.PoolOfIntPools.Get() mem.Resize(64) pc := uint64(0) v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700" - stack.pushN(new(big.Int).SetBytes(common.Hex2Bytes(v)), big.NewInt(0)) + stack.PushN(new(big.Int).SetBytes(common.Hex2Bytes(v)), big.NewInt(0)) opMstore(&pc, evmInterpreter, nil, mem, stack) if got := common.Bytes2Hex(mem.Get(0, 32)); got != v { t.Fatalf("Mstore fail, got %v, expected %v", got, v) } - stack.pushN(big.NewInt(0x1), big.NewInt(0)) + stack.PushN(big.NewInt(0x1), big.NewInt(0)) opMstore(&pc, evmInterpreter, nil, mem, stack) if common.Bytes2Hex(mem.Get(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" { t.Fatalf("Mstore failed to overwrite previous value") } - poolOfIntPools.put(evmInterpreter.intPool) + vm.PoolOfIntPools.Put(evmInterpreter.intPool) } func BenchmarkOpMstore(bench *testing.B) { var ( env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) - stack = newstack() - mem = NewMemory() + stack = NewStack() + mem = vm.NewMemory() evmInterpreter = NewEVMInterpreter(env, env.vmConfig) ) env.interpreter = evmInterpreter - evmInterpreter.intPool = poolOfIntPools.get() + evmInterpreter.intPool = vm.PoolOfIntPools.Get() mem.Resize(64) pc := uint64(0) memStart := big.NewInt(0) @@ -486,31 +487,31 @@ func BenchmarkOpMstore(bench *testing.B) { bench.ResetTimer() for i := 0; i < bench.N; i++ { - stack.pushN(value, memStart) + stack.PushN(value, memStart) opMstore(&pc, evmInterpreter, nil, mem, stack) } - poolOfIntPools.put(evmInterpreter.intPool) + vm.PoolOfIntPools.Put(evmInterpreter.intPool) } func BenchmarkOpSHA3(bench *testing.B) { var ( env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) - stack = newstack() - mem = NewMemory() + stack = NewStack() + mem = vm.NewMemory() evmInterpreter = NewEVMInterpreter(env, env.vmConfig) ) env.interpreter = evmInterpreter - evmInterpreter.intPool = poolOfIntPools.get() + evmInterpreter.intPool = vm.PoolOfIntPools.Get() mem.Resize(32) pc := uint64(0) start := big.NewInt(0) bench.ResetTimer() for i := 0; i < bench.N; i++ { - stack.pushN(big.NewInt(32), start) + stack.PushN(big.NewInt(32), start) opSha3(&pc, evmInterpreter, nil, mem, stack) } - poolOfIntPools.put(evmInterpreter.intPool) + vm.PoolOfIntPools.Put(evmInterpreter.intPool) } func TestCreate2Addreses(t *testing.T) { @@ -572,11 +573,11 @@ func TestCreate2Addreses(t *testing.T) { codeHash := crypto.Keccak256(code) address := crypto.CreateAddress2(origin, salt, codeHash) /* - stack := newstack() + stack := NewStack() // salt, but we don't need that for this test - stack.push(big.NewInt(int64(len(code)))) //size - stack.push(big.NewInt(0)) // memstart - stack.push(big.NewInt(0)) // value + stack.Push(big.NewInt(int64(len(code)))) //size + stack.Push(big.NewInt(0)) // memstart + stack.Push(big.NewInt(0)) // value gas, _ := gasCreate2(params.GasTable{}, nil, nil, stack, nil, 0) fmt.Printf("Example %d\n* address `0x%x`\n* salt `0x%x`\n* init_code `0x%x`\n* gas (assuming no mem expansion): `%v`\n* result: `%s`\n\n", i,origin, salt, code, gas, address.String()) */ diff --git a/core/vm/interface.go b/core/vm/evm/interface.go index 3e86a4ff2..20e5f34a9 100644 --- a/core/vm/interface.go +++ b/core/vm/evm/interface.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "math/big" diff --git a/core/vm/interpreter.go b/core/vm/evm/interpreter.go index ffe5ff626..ca3ddd05a 100644 --- a/core/vm/interpreter.go +++ b/core/vm/evm/interpreter.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "fmt" @@ -23,6 +23,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/common/math" + "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/params" ) @@ -87,7 +88,7 @@ type EVMInterpreter struct { cfg Config gasTable params.GasTable - intPool *intPool + intPool *vm.IntPool hasher keccakState // Keccak256 hasher instance shared across opcodes hasherBuf common.Hash // Keccak256 hasher result array shared aross opcodes @@ -121,7 +122,7 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { } } -func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error { +func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, stack *vm.Stack) error { if in.evm.chainRules.IsByzantium { if in.readOnly { // If the interpreter is operating in readonly mode, make sure no @@ -145,9 +146,9 @@ func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, st // errExecutionReverted which means revert-and-keep-gas-left. func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) { if in.intPool == nil { - in.intPool = poolOfIntPools.get() + in.intPool = vm.PoolOfIntPools.Get() defer func() { - poolOfIntPools.put(in.intPool) + vm.PoolOfIntPools.Put(in.intPool) in.intPool = nil }() } @@ -173,9 +174,9 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } var ( - op OpCode // current opcode - mem = NewMemory() // bound memory - stack = newstack() // local stack + op OpCode // current opcode + mem = vm.NewMemory() // bound memory + stack = NewStack() // local stack // For optimisation reason we're using uint64 as the program counter. // It's theoretically possible to go above 2^64. The YP defines the PC // to be uint256. Practically much less so feasible. @@ -190,8 +191,8 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // Reclaim the stack as an int pool when the execution stops defer func() { - in.intPool.put(stack.data...) - recyclestack(stack) + in.intPool.Put(stack.Data...) + Recyclestack(stack) }() if in.cfg.Debug { @@ -234,13 +235,13 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // calculate the new memory size and expand the memory to fit // the operation if operation.memorySize != nil { - memSize, overflow := bigUint64(operation.memorySize(stack)) + memSize, overflow := vm.BigUint64(operation.memorySize(stack)) if overflow { return nil, errGasUintOverflow } // memory is expanded in words of 32 bytes. Gas // is also calculated in words. - if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow { + if memorySize, overflow = math.SafeMul(vm.ToWordSize(memSize), 32); overflow { return nil, errGasUintOverflow } } @@ -248,7 +249,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // cost is explicitly set so that the capture state defer method can get the proper cost cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize) if err != nil || !contract.UseGas(cost) { - return nil, ErrOutOfGas + return nil, vm.ErrOutOfGas } if memorySize > 0 { mem.Resize(memorySize) @@ -263,8 +264,8 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( res, err := operation.execute(&pc, in, contract, mem, stack) // verifyPool is a build flag. Pool verification makes sure the integrity // of the integer pool by comparing values to a default value. - if verifyPool { - verifyIntegerPool(in.intPool) + if vm.VerifyPool { + vm.VerifyIntegerPool(in.intPool) } // if the operation clears the return data (e.g. it has returning data) // set the last return to the result of the operation. diff --git a/core/vm/jump_table.go b/core/vm/evm/jump_table.go index 608e34419..da2f50c5a 100644 --- a/core/vm/jump_table.go +++ b/core/vm/evm/jump_table.go @@ -14,20 +14,20 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "errors" "math/big" + "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/params" ) type ( - executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) - gasFunc func(params.GasTable, *EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64 - stackValidationFunc func(*Stack) error - memorySizeFunc func(*Stack) *big.Int + executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) + gasFunc func(params.GasTable, *EVM, *Contract, *vm.Stack, *vm.Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64 + memorySizeFunc func(*vm.Stack) *big.Int ) var errGasUintOverflow = errors.New("gas uint64 overflow") @@ -38,7 +38,7 @@ type operation struct { // gasCost is the gas function and returns the gas required for execution gasCost gasFunc // validateStack validates the stack (size) for the operation - validateStack stackValidationFunc + validateStack vm.StackValidationFunc // memorySize returns the memory size required for the operation memorySize memorySizeFunc @@ -65,31 +65,31 @@ func newConstantinopleInstructionSet() [256]operation { instructionSet[SHL] = operation{ execute: opSHL, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, } instructionSet[SHR] = operation{ execute: opSHR, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, } instructionSet[SAR] = operation{ execute: opSAR, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, } instructionSet[EXTCODEHASH] = operation{ execute: opExtCodeHash, gasCost: gasExtCodeHash, - validateStack: makeStackFunc(1, 1), + validateStack: vm.MakeStackFunc(1, 1), valid: true, } instructionSet[CREATE2] = operation{ execute: opCreate2, gasCost: gasCreate2, - validateStack: makeStackFunc(4, 1), + validateStack: vm.MakeStackFunc(4, 1), memorySize: memoryCreate2, valid: true, writes: true, @@ -106,7 +106,7 @@ func newByzantiumInstructionSet() [256]operation { instructionSet[STATICCALL] = operation{ execute: opStaticCall, gasCost: gasStaticCall, - validateStack: makeStackFunc(6, 1), + validateStack: vm.MakeStackFunc(6, 1), memorySize: memoryStaticCall, valid: true, returns: true, @@ -114,20 +114,20 @@ func newByzantiumInstructionSet() [256]operation { instructionSet[RETURNDATASIZE] = operation{ execute: opReturnDataSize, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, } instructionSet[RETURNDATACOPY] = operation{ execute: opReturnDataCopy, gasCost: gasReturnDataCopy, - validateStack: makeStackFunc(3, 0), + validateStack: vm.MakeStackFunc(3, 0), memorySize: memoryReturnDataCopy, valid: true, } instructionSet[REVERT] = operation{ execute: opRevert, gasCost: gasRevert, - validateStack: makeStackFunc(2, 0), + validateStack: vm.MakeStackFunc(2, 0), memorySize: memoryRevert, valid: true, reverts: true, @@ -143,7 +143,7 @@ func newHomesteadInstructionSet() [256]operation { instructionSet[DELEGATECALL] = operation{ execute: opDelegateCall, gasCost: gasDelegateCall, - validateStack: makeStackFunc(6, 1), + validateStack: vm.MakeStackFunc(6, 1), memorySize: memoryDelegateCall, valid: true, returns: true, @@ -158,289 +158,289 @@ func newFrontierInstructionSet() [256]operation { STOP: { execute: opStop, gasCost: constGasFunc(0), - validateStack: makeStackFunc(0, 0), + validateStack: vm.MakeStackFunc(0, 0), halts: true, valid: true, }, ADD: { execute: opAdd, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, MUL: { execute: opMul, gasCost: constGasFunc(GasFastStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, SUB: { execute: opSub, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, DIV: { execute: opDiv, gasCost: constGasFunc(GasFastStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, SDIV: { execute: opSdiv, gasCost: constGasFunc(GasFastStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, MOD: { execute: opMod, gasCost: constGasFunc(GasFastStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, SMOD: { execute: opSmod, gasCost: constGasFunc(GasFastStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, ADDMOD: { execute: opAddmod, gasCost: constGasFunc(GasMidStep), - validateStack: makeStackFunc(3, 1), + validateStack: vm.MakeStackFunc(3, 1), valid: true, }, MULMOD: { execute: opMulmod, gasCost: constGasFunc(GasMidStep), - validateStack: makeStackFunc(3, 1), + validateStack: vm.MakeStackFunc(3, 1), valid: true, }, EXP: { execute: opExp, gasCost: gasExp, - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, SIGNEXTEND: { execute: opSignExtend, gasCost: constGasFunc(GasFastStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, LT: { execute: opLt, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, GT: { execute: opGt, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, SLT: { execute: opSlt, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, SGT: { execute: opSgt, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, EQ: { execute: opEq, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, ISZERO: { execute: opIszero, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(1, 1), + validateStack: vm.MakeStackFunc(1, 1), valid: true, }, AND: { execute: opAnd, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, XOR: { execute: opXor, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, OR: { execute: opOr, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, NOT: { execute: opNot, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(1, 1), + validateStack: vm.MakeStackFunc(1, 1), valid: true, }, BYTE: { execute: opByte, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), valid: true, }, SHA3: { execute: opSha3, gasCost: gasSha3, - validateStack: makeStackFunc(2, 1), + validateStack: vm.MakeStackFunc(2, 1), memorySize: memorySha3, valid: true, }, RAND: { execute: opRand, gasCost: constGasFunc(params.RandGas), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, ADDRESS: { execute: opAddress, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, BALANCE: { execute: opBalance, gasCost: gasBalance, - validateStack: makeStackFunc(1, 1), + validateStack: vm.MakeStackFunc(1, 1), valid: true, }, ORIGIN: { execute: opOrigin, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, CALLER: { execute: opCaller, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, CALLVALUE: { execute: opCallValue, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, CALLDATALOAD: { execute: opCallDataLoad, gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(1, 1), + validateStack: vm.MakeStackFunc(1, 1), valid: true, }, CALLDATASIZE: { execute: opCallDataSize, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, CALLDATACOPY: { execute: opCallDataCopy, gasCost: gasCallDataCopy, - validateStack: makeStackFunc(3, 0), + validateStack: vm.MakeStackFunc(3, 0), memorySize: memoryCallDataCopy, valid: true, }, CODESIZE: { execute: opCodeSize, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, CODECOPY: { execute: opCodeCopy, gasCost: gasCodeCopy, - validateStack: makeStackFunc(3, 0), + validateStack: vm.MakeStackFunc(3, 0), memorySize: memoryCodeCopy, valid: true, }, GASPRICE: { execute: opGasprice, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, EXTCODESIZE: { execute: opExtCodeSize, gasCost: gasExtCodeSize, - validateStack: makeStackFunc(1, 1), + validateStack: vm.MakeStackFunc(1, 1), valid: true, }, EXTCODECOPY: { execute: opExtCodeCopy, gasCost: gasExtCodeCopy, - validateStack: makeStackFunc(4, 0), + validateStack: vm.MakeStackFunc(4, 0), memorySize: memoryExtCodeCopy, valid: true, }, BLOCKHASH: { execute: opBlockhash, gasCost: constGasFunc(GasExtStep), - validateStack: makeStackFunc(1, 1), + validateStack: vm.MakeStackFunc(1, 1), valid: true, }, COINBASE: { execute: opCoinbase, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, TIMESTAMP: { execute: opTimestamp, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, NUMBER: { execute: opNumber, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, DIFFICULTY: { execute: opDifficulty, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, GASLIMIT: { execute: opGasLimit, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, POP: { execute: opPop, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(1, 0), + validateStack: vm.MakeStackFunc(1, 0), valid: true, }, MLOAD: { execute: opMload, gasCost: gasMLoad, - validateStack: makeStackFunc(1, 1), + validateStack: vm.MakeStackFunc(1, 1), memorySize: memoryMLoad, valid: true, }, MSTORE: { execute: opMstore, gasCost: gasMStore, - validateStack: makeStackFunc(2, 0), + validateStack: vm.MakeStackFunc(2, 0), memorySize: memoryMStore, valid: true, }, @@ -448,449 +448,449 @@ func newFrontierInstructionSet() [256]operation { execute: opMstore8, gasCost: gasMStore8, memorySize: memoryMStore8, - validateStack: makeStackFunc(2, 0), + validateStack: vm.MakeStackFunc(2, 0), valid: true, }, SLOAD: { execute: opSload, gasCost: gasSLoad, - validateStack: makeStackFunc(1, 1), + validateStack: vm.MakeStackFunc(1, 1), valid: true, }, SSTORE: { execute: opSstore, gasCost: gasSStore, - validateStack: makeStackFunc(2, 0), + validateStack: vm.MakeStackFunc(2, 0), valid: true, writes: true, }, JUMP: { execute: opJump, gasCost: constGasFunc(GasMidStep), - validateStack: makeStackFunc(1, 0), + validateStack: vm.MakeStackFunc(1, 0), jumps: true, valid: true, }, JUMPI: { execute: opJumpi, gasCost: constGasFunc(GasSlowStep), - validateStack: makeStackFunc(2, 0), + validateStack: vm.MakeStackFunc(2, 0), jumps: true, valid: true, }, PC: { execute: opPc, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, MSIZE: { execute: opMsize, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, GAS: { execute: opGas, gasCost: constGasFunc(GasQuickStep), - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, JUMPDEST: { execute: opJumpdest, gasCost: constGasFunc(params.JumpdestGas), - validateStack: makeStackFunc(0, 0), + validateStack: vm.MakeStackFunc(0, 0), valid: true, }, PUSH1: { execute: makePush(1, 1), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH2: { execute: makePush(2, 2), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH3: { execute: makePush(3, 3), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH4: { execute: makePush(4, 4), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH5: { execute: makePush(5, 5), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH6: { execute: makePush(6, 6), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH7: { execute: makePush(7, 7), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH8: { execute: makePush(8, 8), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH9: { execute: makePush(9, 9), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH10: { execute: makePush(10, 10), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH11: { execute: makePush(11, 11), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH12: { execute: makePush(12, 12), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH13: { execute: makePush(13, 13), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH14: { execute: makePush(14, 14), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH15: { execute: makePush(15, 15), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH16: { execute: makePush(16, 16), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH17: { execute: makePush(17, 17), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH18: { execute: makePush(18, 18), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH19: { execute: makePush(19, 19), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH20: { execute: makePush(20, 20), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH21: { execute: makePush(21, 21), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH22: { execute: makePush(22, 22), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH23: { execute: makePush(23, 23), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH24: { execute: makePush(24, 24), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH25: { execute: makePush(25, 25), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH26: { execute: makePush(26, 26), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH27: { execute: makePush(27, 27), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH28: { execute: makePush(28, 28), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH29: { execute: makePush(29, 29), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH30: { execute: makePush(30, 30), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH31: { execute: makePush(31, 31), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, PUSH32: { execute: makePush(32, 32), gasCost: gasPush, - validateStack: makeStackFunc(0, 1), + validateStack: vm.MakeStackFunc(0, 1), valid: true, }, DUP1: { execute: makeDup(1), gasCost: gasDup, - validateStack: makeDupStackFunc(1), + validateStack: vm.MakeDupStackFunc(1), valid: true, }, DUP2: { execute: makeDup(2), gasCost: gasDup, - validateStack: makeDupStackFunc(2), + validateStack: vm.MakeDupStackFunc(2), valid: true, }, DUP3: { execute: makeDup(3), gasCost: gasDup, - validateStack: makeDupStackFunc(3), + validateStack: vm.MakeDupStackFunc(3), valid: true, }, DUP4: { execute: makeDup(4), gasCost: gasDup, - validateStack: makeDupStackFunc(4), + validateStack: vm.MakeDupStackFunc(4), valid: true, }, DUP5: { execute: makeDup(5), gasCost: gasDup, - validateStack: makeDupStackFunc(5), + validateStack: vm.MakeDupStackFunc(5), valid: true, }, DUP6: { execute: makeDup(6), gasCost: gasDup, - validateStack: makeDupStackFunc(6), + validateStack: vm.MakeDupStackFunc(6), valid: true, }, DUP7: { execute: makeDup(7), gasCost: gasDup, - validateStack: makeDupStackFunc(7), + validateStack: vm.MakeDupStackFunc(7), valid: true, }, DUP8: { execute: makeDup(8), gasCost: gasDup, - validateStack: makeDupStackFunc(8), + validateStack: vm.MakeDupStackFunc(8), valid: true, }, DUP9: { execute: makeDup(9), gasCost: gasDup, - validateStack: makeDupStackFunc(9), + validateStack: vm.MakeDupStackFunc(9), valid: true, }, DUP10: { execute: makeDup(10), gasCost: gasDup, - validateStack: makeDupStackFunc(10), + validateStack: vm.MakeDupStackFunc(10), valid: true, }, DUP11: { execute: makeDup(11), gasCost: gasDup, - validateStack: makeDupStackFunc(11), + validateStack: vm.MakeDupStackFunc(11), valid: true, }, DUP12: { execute: makeDup(12), gasCost: gasDup, - validateStack: makeDupStackFunc(12), + validateStack: vm.MakeDupStackFunc(12), valid: true, }, DUP13: { execute: makeDup(13), gasCost: gasDup, - validateStack: makeDupStackFunc(13), + validateStack: vm.MakeDupStackFunc(13), valid: true, }, DUP14: { execute: makeDup(14), gasCost: gasDup, - validateStack: makeDupStackFunc(14), + validateStack: vm.MakeDupStackFunc(14), valid: true, }, DUP15: { execute: makeDup(15), gasCost: gasDup, - validateStack: makeDupStackFunc(15), + validateStack: vm.MakeDupStackFunc(15), valid: true, }, DUP16: { execute: makeDup(16), gasCost: gasDup, - validateStack: makeDupStackFunc(16), + validateStack: vm.MakeDupStackFunc(16), valid: true, }, SWAP1: { execute: makeSwap(1), gasCost: gasSwap, - validateStack: makeSwapStackFunc(2), + validateStack: vm.MakeSwapStackFunc(2), valid: true, }, SWAP2: { execute: makeSwap(2), gasCost: gasSwap, - validateStack: makeSwapStackFunc(3), + validateStack: vm.MakeSwapStackFunc(3), valid: true, }, SWAP3: { execute: makeSwap(3), gasCost: gasSwap, - validateStack: makeSwapStackFunc(4), + validateStack: vm.MakeSwapStackFunc(4), valid: true, }, SWAP4: { execute: makeSwap(4), gasCost: gasSwap, - validateStack: makeSwapStackFunc(5), + validateStack: vm.MakeSwapStackFunc(5), valid: true, }, SWAP5: { execute: makeSwap(5), gasCost: gasSwap, - validateStack: makeSwapStackFunc(6), + validateStack: vm.MakeSwapStackFunc(6), valid: true, }, SWAP6: { execute: makeSwap(6), gasCost: gasSwap, - validateStack: makeSwapStackFunc(7), + validateStack: vm.MakeSwapStackFunc(7), valid: true, }, SWAP7: { execute: makeSwap(7), gasCost: gasSwap, - validateStack: makeSwapStackFunc(8), + validateStack: vm.MakeSwapStackFunc(8), valid: true, }, SWAP8: { execute: makeSwap(8), gasCost: gasSwap, - validateStack: makeSwapStackFunc(9), + validateStack: vm.MakeSwapStackFunc(9), valid: true, }, SWAP9: { execute: makeSwap(9), gasCost: gasSwap, - validateStack: makeSwapStackFunc(10), + validateStack: vm.MakeSwapStackFunc(10), valid: true, }, SWAP10: { execute: makeSwap(10), gasCost: gasSwap, - validateStack: makeSwapStackFunc(11), + validateStack: vm.MakeSwapStackFunc(11), valid: true, }, SWAP11: { execute: makeSwap(11), gasCost: gasSwap, - validateStack: makeSwapStackFunc(12), + validateStack: vm.MakeSwapStackFunc(12), valid: true, }, SWAP12: { execute: makeSwap(12), gasCost: gasSwap, - validateStack: makeSwapStackFunc(13), + validateStack: vm.MakeSwapStackFunc(13), valid: true, }, SWAP13: { execute: makeSwap(13), gasCost: gasSwap, - validateStack: makeSwapStackFunc(14), + validateStack: vm.MakeSwapStackFunc(14), valid: true, }, SWAP14: { execute: makeSwap(14), gasCost: gasSwap, - validateStack: makeSwapStackFunc(15), + validateStack: vm.MakeSwapStackFunc(15), valid: true, }, SWAP15: { execute: makeSwap(15), gasCost: gasSwap, - validateStack: makeSwapStackFunc(16), + validateStack: vm.MakeSwapStackFunc(16), valid: true, }, SWAP16: { execute: makeSwap(16), gasCost: gasSwap, - validateStack: makeSwapStackFunc(17), + validateStack: vm.MakeSwapStackFunc(17), valid: true, }, LOG0: { execute: makeLog(0), gasCost: makeGasLog(0), - validateStack: makeStackFunc(2, 0), + validateStack: vm.MakeStackFunc(2, 0), memorySize: memoryLog, valid: true, writes: true, @@ -898,7 +898,7 @@ func newFrontierInstructionSet() [256]operation { LOG1: { execute: makeLog(1), gasCost: makeGasLog(1), - validateStack: makeStackFunc(3, 0), + validateStack: vm.MakeStackFunc(3, 0), memorySize: memoryLog, valid: true, writes: true, @@ -906,7 +906,7 @@ func newFrontierInstructionSet() [256]operation { LOG2: { execute: makeLog(2), gasCost: makeGasLog(2), - validateStack: makeStackFunc(4, 0), + validateStack: vm.MakeStackFunc(4, 0), memorySize: memoryLog, valid: true, writes: true, @@ -914,7 +914,7 @@ func newFrontierInstructionSet() [256]operation { LOG3: { execute: makeLog(3), gasCost: makeGasLog(3), - validateStack: makeStackFunc(5, 0), + validateStack: vm.MakeStackFunc(5, 0), memorySize: memoryLog, valid: true, writes: true, @@ -922,7 +922,7 @@ func newFrontierInstructionSet() [256]operation { LOG4: { execute: makeLog(4), gasCost: makeGasLog(4), - validateStack: makeStackFunc(6, 0), + validateStack: vm.MakeStackFunc(6, 0), memorySize: memoryLog, valid: true, writes: true, @@ -930,7 +930,7 @@ func newFrontierInstructionSet() [256]operation { CREATE: { execute: opCreate, gasCost: gasCreate, - validateStack: makeStackFunc(3, 1), + validateStack: vm.MakeStackFunc(3, 1), memorySize: memoryCreate, valid: true, writes: true, @@ -939,7 +939,7 @@ func newFrontierInstructionSet() [256]operation { CALL: { execute: opCall, gasCost: gasCall, - validateStack: makeStackFunc(7, 1), + validateStack: vm.MakeStackFunc(7, 1), memorySize: memoryCall, valid: true, returns: true, @@ -947,7 +947,7 @@ func newFrontierInstructionSet() [256]operation { CALLCODE: { execute: opCallCode, gasCost: gasCallCode, - validateStack: makeStackFunc(7, 1), + validateStack: vm.MakeStackFunc(7, 1), memorySize: memoryCall, valid: true, returns: true, @@ -955,7 +955,7 @@ func newFrontierInstructionSet() [256]operation { RETURN: { execute: opReturn, gasCost: gasReturn, - validateStack: makeStackFunc(2, 0), + validateStack: vm.MakeStackFunc(2, 0), memorySize: memoryReturn, halts: true, valid: true, @@ -963,7 +963,7 @@ func newFrontierInstructionSet() [256]operation { SELFDESTRUCT: { execute: opSuicide, gasCost: gasSuicide, - validateStack: makeStackFunc(1, 0), + validateStack: vm.MakeStackFunc(1, 0), halts: true, valid: true, writes: true, diff --git a/core/vm/logger.go b/core/vm/evm/logger.go index fd36c26d5..f51943b14 100644 --- a/core/vm/logger.go +++ b/core/vm/evm/logger.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "encoding/hex" @@ -27,6 +27,7 @@ import ( "github.com/dexon-foundation/dexon/common/hexutil" "github.com/dexon-foundation/dexon/common/math" "github.com/dexon-foundation/dexon/core/types" + "github.com/dexon-foundation/dexon/core/vm" ) // Storage represents a contract's storage. @@ -99,8 +100,8 @@ func (s *StructLog) ErrorString() string { // if you need to retain them beyond the current call. type Tracer interface { CaptureStart(from common.Address, to common.Address, call bool, input []byte, gas uint64, value *big.Int) error - CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error - CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error + CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *Contract, depth int, err error) error + CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *Contract, depth int, err error) error CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error } @@ -137,10 +138,10 @@ func (l *StructLogger) CaptureStart(from common.Address, to common.Address, crea // CaptureState logs a new structured log message and pushes it out to the environment // // CaptureState also tracks SSTORE ops to track dirty values. -func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { +func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *Contract, depth int, err error) error { // check if already accumulated the specified number of logs if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) { - return ErrTraceLimitReached + return vm.ErrTraceLimitReached } // initialise new changed values storage container for this contract @@ -151,10 +152,10 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui // capture SSTORE opcodes and determine the changed value and store // it in the local storage container. - if op == SSTORE && stack.len() >= 2 { + if op == SSTORE && stack.Len() >= 2 { var ( - value = common.BigToHash(stack.data[stack.len()-2]) - address = common.BigToHash(stack.data[stack.len()-1]) + value = common.BigToHash(stack.Data[stack.Len()-2]) + address = common.BigToHash(stack.Data[stack.Len()-1]) ) l.changedValues[contract.Address()][address] = value } @@ -167,8 +168,8 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui // Copy a snapshot of the current stack state to a new buffer var stck []*big.Int if !l.cfg.DisableStack { - stck = make([]*big.Int, len(stack.Data())) - for i, item := range stack.Data() { + stck = make([]*big.Int, len(stack.Data)) + for i, item := range stack.Data { stck[i] = new(big.Int).Set(item) } } @@ -186,7 +187,7 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui // CaptureFault implements the Tracer interface to trace an execution fault // while running an opcode. -func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { +func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *Contract, depth int, err error) error { return nil } diff --git a/core/vm/logger_json.go b/core/vm/evm/logger_json.go index 9b7555194..e96e435b3 100644 --- a/core/vm/logger_json.go +++ b/core/vm/evm/logger_json.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "encoding/json" @@ -24,6 +24,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/common/math" + "github.com/dexon-foundation/dexon/core/vm" ) type JSONLogger struct { @@ -46,7 +47,7 @@ func (l *JSONLogger) CaptureStart(from common.Address, to common.Address, create } // CaptureState outputs state information on the logger. -func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { +func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *Contract, depth int, err error) error { log := StructLog{ Pc: pc, Op: op, @@ -62,13 +63,13 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint log.Memory = memory.Data() } if !l.cfg.DisableStack { - log.Stack = stack.Data() + log.Stack = stack.Data } return l.encoder.Encode(log) } // CaptureFault outputs state information on the logger. -func (l *JSONLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { +func (l *JSONLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *Contract, depth int, err error) error { return nil } diff --git a/core/vm/logger_test.go b/core/vm/evm/logger_test.go index 560893c50..a8e0e9044 100644 --- a/core/vm/logger_test.go +++ b/core/vm/evm/logger_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "math/big" @@ -22,6 +22,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/state" + "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/params" ) @@ -52,12 +53,12 @@ func TestStoreCapture(t *testing.T) { var ( env = NewEVM(Context{}, &dummyStatedb{}, params.TestChainConfig, Config{}) logger = NewStructLogger(nil) - mem = NewMemory() - stack = newstack() + mem = vm.NewMemory() + stack = NewStack() contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0) ) - stack.push(big.NewInt(1)) - stack.push(big.NewInt(0)) + stack.Push(big.NewInt(1)) + stack.Push(big.NewInt(0)) var index common.Hash logger.CaptureState(env, 0, SSTORE, 0, 0, mem, stack, contract, 0, nil) if len(logger.changedValues[contract.Address()]) == 0 { diff --git a/core/vm/evm/memory_table.go b/core/vm/evm/memory_table.go new file mode 100644 index 000000000..c27e95a4a --- /dev/null +++ b/core/vm/evm/memory_table.go @@ -0,0 +1,98 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package evm + +import ( + "math/big" + + "github.com/dexon-foundation/dexon/common/math" + "github.com/dexon-foundation/dexon/core/vm" +) + +func memorySha3(stack *vm.Stack) *big.Int { + return vm.CalcMemSize(stack.Back(0), stack.Back(1)) +} + +func memoryCallDataCopy(stack *vm.Stack) *big.Int { + return vm.CalcMemSize(stack.Back(0), stack.Back(2)) +} + +func memoryReturnDataCopy(stack *vm.Stack) *big.Int { + return vm.CalcMemSize(stack.Back(0), stack.Back(2)) +} + +func memoryCodeCopy(stack *vm.Stack) *big.Int { + return vm.CalcMemSize(stack.Back(0), stack.Back(2)) +} + +func memoryExtCodeCopy(stack *vm.Stack) *big.Int { + return vm.CalcMemSize(stack.Back(1), stack.Back(3)) +} + +func memoryMLoad(stack *vm.Stack) *big.Int { + return vm.CalcMemSize(stack.Back(0), big32) +} + +func memoryMStore8(stack *vm.Stack) *big.Int { + return vm.CalcMemSize(stack.Back(0), big1) +} + +func memoryMStore(stack *vm.Stack) *big.Int { + return vm.CalcMemSize(stack.Back(0), big32) +} + +func memoryCreate(stack *vm.Stack) *big.Int { + return vm.CalcMemSize(stack.Back(1), stack.Back(2)) +} + +func memoryCreate2(stack *vm.Stack) *big.Int { + return vm.CalcMemSize(stack.Back(1), stack.Back(2)) +} + +func memoryCall(stack *vm.Stack) *big.Int { + x := vm.CalcMemSize(stack.Back(5), stack.Back(6)) + y := vm.CalcMemSize(stack.Back(3), stack.Back(4)) + + return math.BigMax(x, y) +} + +func memoryDelegateCall(stack *vm.Stack) *big.Int { + x := vm.CalcMemSize(stack.Back(4), stack.Back(5)) + y := vm.CalcMemSize(stack.Back(2), stack.Back(3)) + + return math.BigMax(x, y) +} + +func memoryStaticCall(stack *vm.Stack) *big.Int { + x := vm.CalcMemSize(stack.Back(4), stack.Back(5)) + y := vm.CalcMemSize(stack.Back(2), stack.Back(3)) + + return math.BigMax(x, y) +} + +func memoryReturn(stack *vm.Stack) *big.Int { + return vm.CalcMemSize(stack.Back(0), stack.Back(1)) +} + +func memoryRevert(stack *vm.Stack) *big.Int { + return vm.CalcMemSize(stack.Back(0), stack.Back(1)) +} + +func memoryLog(stack *vm.Stack) *big.Int { + mSize, mStart := stack.Back(1), stack.Back(0) + return vm.CalcMemSize(mStart, mSize) +} diff --git a/core/vm/opcodes.go b/core/vm/evm/opcodes.go index 8762d4b43..22ff00c7d 100644 --- a/core/vm/opcodes.go +++ b/core/vm/evm/opcodes.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package vm +package evm import ( "fmt" diff --git a/core/vm/runtime/doc.go b/core/vm/evm/runtime/doc.go index a3b464a7d..a3b464a7d 100644 --- a/core/vm/runtime/doc.go +++ b/core/vm/evm/runtime/doc.go diff --git a/core/vm/runtime/env.go b/core/vm/evm/runtime/env.go index 6f241a329..c46580140 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/evm/runtime/env.go @@ -19,7 +19,7 @@ package runtime import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" ) func NewEnv(cfg *Config) *vm.EVM { diff --git a/core/vm/runtime/fuzz.go b/core/vm/evm/runtime/fuzz.go index cb9ff08b5..cb9ff08b5 100644 --- a/core/vm/runtime/fuzz.go +++ b/core/vm/evm/runtime/fuzz.go diff --git a/core/vm/runtime/runtime.go b/core/vm/evm/runtime/runtime.go index 5656f661a..93e6322f4 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/evm/runtime/runtime.go @@ -23,7 +23,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/state" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" diff --git a/core/vm/runtime/runtime_example_test.go b/core/vm/evm/runtime/runtime_example_test.go index 036cfe558..c6050a771 100644 --- a/core/vm/runtime/runtime_example_test.go +++ b/core/vm/evm/runtime/runtime_example_test.go @@ -20,7 +20,7 @@ import ( "fmt" "github.com/dexon-foundation/dexon/common" - "github.com/dexon-foundation/dexon/core/vm/runtime" + "github.com/dexon-foundation/dexon/core/vm/evm/runtime" ) func ExampleExecute() { diff --git a/core/vm/runtime/runtime_test.go b/core/vm/evm/runtime/runtime_test.go index fe03bd43f..43b8da325 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/evm/runtime/runtime_test.go @@ -24,7 +24,7 @@ import ( "github.com/dexon-foundation/dexon/accounts/abi" "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/state" - "github.com/dexon-foundation/dexon/core/vm" + vm "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" ) diff --git a/core/vm/evm/stack.go b/core/vm/evm/stack.go new file mode 100644 index 000000000..4545201ce --- /dev/null +++ b/core/vm/evm/stack.go @@ -0,0 +1,24 @@ +package evm + +import ( + "math/big" + "sync" + + "github.com/dexon-foundation/dexon/core/vm" +) + +var stackPool = sync.Pool{ + New: func() interface{} { + return &vm.Stack{Data: make([]*big.Int, 0, 1024)} + }, +} + +func NewStack() *vm.Stack { + stack := stackPool.Get().(*vm.Stack) + stack.Data = stack.Data[:0] + return stack +} + +func Recyclestack(stack *vm.Stack) { + stackPool.Put(stack) +} diff --git a/core/vm/int_pool_verifier.go b/core/vm/int_pool_verifier.go index 82fbfed69..c03408b5f 100644 --- a/core/vm/int_pool_verifier.go +++ b/core/vm/int_pool_verifier.go @@ -20,9 +20,9 @@ package vm import "fmt" -const verifyPool = true +const VerifyPool = true -func verifyIntegerPool(ip *intPool) { +func VerifyIntegerPool(ip *IntPool) { for i, item := range ip.pool.data { if item.Cmp(checkVal) != 0 { panic(fmt.Sprintf("%d'th item failed aggressive pool check. Value was modified", i)) diff --git a/core/vm/int_pool_verifier_empty.go b/core/vm/int_pool_verifier_empty.go index a5f1dc02b..66d99f16f 100644 --- a/core/vm/int_pool_verifier_empty.go +++ b/core/vm/int_pool_verifier_empty.go @@ -18,6 +18,6 @@ package vm -const verifyPool = false +const VerifyPool = false -func verifyIntegerPool(ip *intPool) {} +func VerifyIntegerPool(ip *IntPool) {} diff --git a/core/vm/intpool.go b/core/vm/intpool.go index 917a78d56..9e73b8b71 100644 --- a/core/vm/intpool.go +++ b/core/vm/intpool.go @@ -23,84 +23,84 @@ import ( var checkVal = big.NewInt(-42) -const poolLimit = 256 +const PoolLimit = 256 -// intPool is a pool of big integers that +// IntPool is a Pool of big integers that // can be reused for all big.Int operations. -type intPool struct { - pool *Stack +type IntPool struct { + Pool *Stack } -func newIntPool() *intPool { - return &intPool{pool: newstack()} +func newIntPool() *IntPool { + return &IntPool{Pool: &Stack{Data: make([]*big.Int, 0, 1024)}} } -// get retrieves a big int from the pool, allocating one if the pool is empty. +// get retrieves a big int from the Pool, allocating one if the Pool is empty. // Note, the returned int's value is arbitrary and will not be zeroed! -func (p *intPool) get() *big.Int { - if p.pool.len() > 0 { - return p.pool.pop() +func (p *IntPool) Get() *big.Int { + if p.Pool.Len() > 0 { + return p.Pool.Pop() } return new(big.Int) } -// getZero retrieves a big int from the pool, setting it to zero or allocating -// a new one if the pool is empty. -func (p *intPool) getZero() *big.Int { - if p.pool.len() > 0 { - return p.pool.pop().SetUint64(0) +// getZero retrieves a big int from the Pool, setting it to zero or allocating +// a new one if the Pool is empty. +func (p *IntPool) GetZero() *big.Int { + if p.Pool.Len() > 0 { + return p.Pool.Pop().SetUint64(0) } return new(big.Int) } -// put returns an allocated big int to the pool to be later reused by get calls. +// put returns an allocated big int to the Pool to be later reused by get calls. // Note, the values as saved as is; neither put nor get zeroes the ints out! -func (p *intPool) put(is ...*big.Int) { - if len(p.pool.data) > poolLimit { +func (p *IntPool) Put(is ...*big.Int) { + if len(p.Pool.Data) > PoolLimit { return } for _, i := range is { // verifyPool is a build flag. Pool verification makes sure the integrity - // of the integer pool by comparing values to a default value. - if verifyPool { + // of the integer Pool by comparing values to a default value. + if VerifyPool { i.Set(checkVal) } - p.pool.push(i) + p.Pool.Push(i) } } -// The intPool pool's default capacity -const poolDefaultCap = 25 +// The IntPool Pool's default capacity +const PoolDefaultCap = 25 -// intPoolPool manages a pool of intPools. -type intPoolPool struct { - pools []*intPool +// IntPoolPool manages a Pool of IntPools. +type IntPoolPool struct { + Pools []*IntPool lock sync.Mutex } -var poolOfIntPools = &intPoolPool{ - pools: make([]*intPool, 0, poolDefaultCap), +var PoolOfIntPools = &IntPoolPool{ + Pools: make([]*IntPool, 0, PoolDefaultCap), } -// get is looking for an available pool to return. -func (ipp *intPoolPool) get() *intPool { +// get is looking for an available Pool to return. +func (ipp *IntPoolPool) Get() *IntPool { ipp.lock.Lock() defer ipp.lock.Unlock() - if len(poolOfIntPools.pools) > 0 { - ip := ipp.pools[len(ipp.pools)-1] - ipp.pools = ipp.pools[:len(ipp.pools)-1] + if len(PoolOfIntPools.Pools) > 0 { + ip := ipp.Pools[len(ipp.Pools)-1] + ipp.Pools = ipp.Pools[:len(ipp.Pools)-1] return ip } return newIntPool() } -// put a pool that has been allocated with get. -func (ipp *intPoolPool) put(ip *intPool) { +// put a Pool that has been allocated with get. +func (ipp *IntPoolPool) Put(ip *IntPool) { ipp.lock.Lock() defer ipp.lock.Unlock() - if len(ipp.pools) < cap(ipp.pools) { - ipp.pools = append(ipp.pools, ip) + if len(ipp.Pools) < cap(ipp.Pools) { + ipp.Pools = append(ipp.Pools, ip) } } diff --git a/core/vm/intpool_test.go b/core/vm/intpool_test.go index 6c0d00f3c..120d9a682 100644 --- a/core/vm/intpool_test.go +++ b/core/vm/intpool_test.go @@ -21,35 +21,35 @@ import ( ) func TestIntPoolPoolGet(t *testing.T) { - poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap) + PoolOfIntPools.Pools = make([]*IntPool, 0, PoolDefaultCap) - nip := poolOfIntPools.get() + nip := PoolOfIntPools.Get() if nip == nil { t.Fatalf("Invalid pool allocation") } } func TestIntPoolPoolPut(t *testing.T) { - poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap) + PoolOfIntPools.Pools = make([]*IntPool, 0, PoolDefaultCap) - nip := poolOfIntPools.get() - if len(poolOfIntPools.pools) != 0 { + nip := PoolOfIntPools.Get() + if len(PoolOfIntPools.Pools) != 0 { t.Fatalf("Pool got added to list when none should have been") } - poolOfIntPools.put(nip) - if len(poolOfIntPools.pools) == 0 { + PoolOfIntPools.Put(nip) + if len(PoolOfIntPools.Pools) == 0 { t.Fatalf("Pool did not get added to list when one should have been") } } func TestIntPoolPoolReUse(t *testing.T) { - poolOfIntPools.pools = make([]*intPool, 0, poolDefaultCap) - nip := poolOfIntPools.get() - poolOfIntPools.put(nip) - poolOfIntPools.get() + PoolOfIntPools.Pools = make([]*IntPool, 0, PoolDefaultCap) + nip := PoolOfIntPools.Get() + PoolOfIntPools.Put(nip) + PoolOfIntPools.Get() - if len(poolOfIntPools.pools) != 0 { - t.Fatalf("Invalid number of pools. Got %d, expected %d", len(poolOfIntPools.pools), 0) + if len(PoolOfIntPools.Pools) != 0 { + t.Fatalf("Invalid number of pools. Got %d, expected %d", len(PoolOfIntPools.Pools), 0) } } diff --git a/core/vm/memory.go b/core/vm/memory.go index 65ffe26c7..bbfa4cc2a 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -25,8 +25,8 @@ import ( // Memory implements a simple memory model for the ethereum virtual machine. type Memory struct { - store []byte - lastGasCost uint64 + Store []byte + LastGasCost uint64 } // NewMemory returns a new memory model. @@ -39,33 +39,33 @@ func (m *Memory) Set(offset, size uint64, value []byte) { // It's possible the offset is greater than 0 and size equals 0. This is because // the calcMemSize (common.go) could potentially return 0 when size is zero (NO-OP) if size > 0 { - // length of store may never be less than offset + size. - // The store should be resized PRIOR to setting the memory - if offset+size > uint64(len(m.store)) { - panic("invalid memory: store empty") + // length of.Store may never be less than offset + size. + // The.Store should be resized PRIOR to setting the memory + if offset+size > uint64(len(m.Store)) { + panic("invalid memory:.Store empty") } - copy(m.store[offset:offset+size], value) + copy(m.Store[offset:offset+size], value) } } // Set32 sets the 32 bytes starting at offset to the value of val, left-padded with zeroes to // 32 bytes. func (m *Memory) Set32(offset uint64, val *big.Int) { - // length of store may never be less than offset + size. - // The store should be resized PRIOR to setting the memory - if offset+32 > uint64(len(m.store)) { - panic("invalid memory: store empty") + // length of.Store may never be less than offset + size. + // The.Store should be resized PRIOR to setting the memory + if offset+32 > uint64(len(m.Store)) { + panic("invalid memory:.Store empty") } // Zero the memory area - copy(m.store[offset:offset+32], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) + copy(m.Store[offset:offset+32], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) // Fill in relevant bits - math.ReadBits(val, m.store[offset:offset+32]) + math.ReadBits(val, m.Store[offset:offset+32]) } // Resize resizes the memory to size func (m *Memory) Resize(size uint64) { if uint64(m.Len()) < size { - m.store = append(m.store, make([]byte, size-uint64(m.Len()))...) + m.Store = append(m.Store, make([]byte, size-uint64(m.Len()))...) } } @@ -75,9 +75,9 @@ func (m *Memory) Get(offset, size int64) (cpy []byte) { return nil } - if len(m.store) > int(offset) { + if len(m.Store) > int(offset) { cpy = make([]byte, size) - copy(cpy, m.store[offset:offset+size]) + copy(cpy, m.Store[offset:offset+size]) return } @@ -91,8 +91,8 @@ func (m *Memory) GetPtr(offset, size int64) []byte { return nil } - if len(m.store) > int(offset) { - return m.store[offset : offset+size] + if len(m.Store) > int(offset) { + return m.Store[offset : offset+size] } return nil @@ -100,21 +100,21 @@ func (m *Memory) GetPtr(offset, size int64) []byte { // Len returns the length of the backing slice func (m *Memory) Len() int { - return len(m.store) + return len(m.Store) } // Data returns the backing slice func (m *Memory) Data() []byte { - return m.store + return m.Store } // Print dumps the content of the memory. func (m *Memory) Print() { - fmt.Printf("### mem %d bytes ###\n", len(m.store)) - if len(m.store) > 0 { + fmt.Printf("### mem %d bytes ###\n", len(m.Store)) + if len(m.Store) > 0 { addr := 0 - for i := 0; i+32 <= len(m.store); i += 32 { - fmt.Printf("%03d: % x\n", addr, m.store[i:i+32]) + for i := 0; i+32 <= len(m.Store); i += 32 { + fmt.Printf("%03d: % x\n", addr, m.Store[i:i+32]) addr++ } } else { diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go deleted file mode 100644 index 13f15b943..000000000 --- a/core/vm/memory_table.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package vm - -import ( - "math/big" - - "github.com/dexon-foundation/dexon/common/math" -) - -func memorySha3(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(1)) -} - -func memoryCallDataCopy(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(2)) -} - -func memoryReturnDataCopy(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(2)) -} - -func memoryCodeCopy(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(2)) -} - -func memoryExtCodeCopy(stack *Stack) *big.Int { - return calcMemSize(stack.Back(1), stack.Back(3)) -} - -func memoryMLoad(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), big32) -} - -func memoryMStore8(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), big1) -} - -func memoryMStore(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), big32) -} - -func memoryCreate(stack *Stack) *big.Int { - return calcMemSize(stack.Back(1), stack.Back(2)) -} - -func memoryCreate2(stack *Stack) *big.Int { - return calcMemSize(stack.Back(1), stack.Back(2)) -} - -func memoryCall(stack *Stack) *big.Int { - x := calcMemSize(stack.Back(5), stack.Back(6)) - y := calcMemSize(stack.Back(3), stack.Back(4)) - - return math.BigMax(x, y) -} - -func memoryDelegateCall(stack *Stack) *big.Int { - x := calcMemSize(stack.Back(4), stack.Back(5)) - y := calcMemSize(stack.Back(2), stack.Back(3)) - - return math.BigMax(x, y) -} - -func memoryStaticCall(stack *Stack) *big.Int { - x := calcMemSize(stack.Back(4), stack.Back(5)) - y := calcMemSize(stack.Back(2), stack.Back(3)) - - return math.BigMax(x, y) -} - -func memoryReturn(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(1)) -} - -func memoryRevert(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(1)) -} - -func memoryLog(stack *Stack) *big.Int { - mSize, mStart := stack.Back(1), stack.Back(0) - return calcMemSize(mStart, mSize) -} diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go index 3a84015b5..4a3c05ccf 100644 --- a/core/vm/oracle_contracts.go +++ b/core/vm/oracle_contracts.go @@ -1921,7 +1921,7 @@ func (g *GovernanceContract) payFine(nodeAddr common.Address) ([]byte, error) { g.state.UpdateNode(nodeOffset, node) // Pay the fine to governance owner. - g.evm.StateDB.AddBalance(g.state.Owner(), g.contract.Value()) + g.evm.StateDB.AddBalance(g.state.Owner(), g.contract.Value) g.state.emitFinePaid(nodeAddr, g.contract.Value()) diff --git a/core/vm/stack.go b/core/vm/stack.go index 14b1c289b..45553d499 100644 --- a/core/vm/stack.go +++ b/core/vm/stack.go @@ -13,83 +13,60 @@ // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - package vm import ( "fmt" "math/big" - "sync" ) -var stackPool = sync.Pool{ - New: func() interface{} { - return &Stack{data: make([]*big.Int, 0, 1024)} - }, -} - // Stack is an object for basic stack operations. Items popped to the stack are // expected to be changed and modified. stack does not take care of adding newly // initialised objects. type Stack struct { - data []*big.Int -} - -func newstack() *Stack { - stack := stackPool.Get().(*Stack) - stack.data = stack.data[:0] - return stack -} - -func recyclestack(stack *Stack) { - stackPool.Put(stack) -} - -// Data returns the underlying big.Int array. -func (st *Stack) Data() []*big.Int { - return st.data + Data []*big.Int } -func (st *Stack) push(d *big.Int) { +func (st *Stack) Push(d *big.Int) { // NOTE push limit (1024) is checked in baseCheck //stackItem := new(big.Int).Set(d) - //st.data = append(st.data, stackItem) - st.data = append(st.data, d) + //st.Data = append(st.Data, stackItem) + st.Data = append(st.Data, d) } -func (st *Stack) pushN(ds ...*big.Int) { - st.data = append(st.data, ds...) +func (st *Stack) PushN(ds ...*big.Int) { + st.Data = append(st.Data, ds...) } -func (st *Stack) pop() (ret *big.Int) { - ret = st.data[len(st.data)-1] - st.data = st.data[:len(st.data)-1] +func (st *Stack) Pop() (ret *big.Int) { + ret = st.Data[len(st.Data)-1] + st.Data = st.Data[:len(st.Data)-1] return } -func (st *Stack) len() int { - return len(st.data) +func (st *Stack) Len() int { + return len(st.Data) } -func (st *Stack) swap(n int) { - st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n] +func (st *Stack) Swap(n int) { + st.Data[st.Len()-n], st.Data[st.Len()-1] = st.Data[st.Len()-1], st.Data[st.Len()-n] } -func (st *Stack) dup(pool *intPool, n int) { - st.push(pool.get().Set(st.data[st.len()-n])) +func (st *Stack) Dup(pool *IntPool, n int) { + st.Push(pool.Get().Set(st.Data[st.Len()-n])) } -func (st *Stack) peek() *big.Int { - return st.data[st.len()-1] +func (st *Stack) Peek() *big.Int { + return st.Data[st.Len()-1] } // Back returns the n'th item in stack func (st *Stack) Back(n int) *big.Int { - return st.data[st.len()-n-1] + return st.Data[st.Len()-n-1] } -func (st *Stack) require(n int) error { - if st.len() < n { - return fmt.Errorf("stack underflow (%d <=> %d)", len(st.data), n) +func (st *Stack) Require(n int) error { + if st.Len() < n { + return fmt.Errorf("stack underflow (%d <=> %d)", len(st.Data), n) } return nil } @@ -97,8 +74,8 @@ func (st *Stack) require(n int) error { // Print dumps the content of the stack func (st *Stack) Print() { fmt.Println("### stack ###") - if len(st.data) > 0 { - for i, val := range st.data { + if len(st.Data) > 0 { + for i, val := range st.Data { fmt.Printf("%-3d %v\n", i, val) } } else { diff --git a/core/vm/stack_table.go b/core/vm/stack_table.go index df544aef8..187d8fa1f 100644 --- a/core/vm/stack_table.go +++ b/core/vm/stack_table.go @@ -22,23 +22,27 @@ import ( "github.com/dexon-foundation/dexon/params" ) -func makeStackFunc(pop, push int) stackValidationFunc { +type ( + StackValidationFunc func(*Stack) error +) + +func MakeStackFunc(pop, push int) StackValidationFunc { return func(stack *Stack) error { - if err := stack.require(pop); err != nil { + if err := stack.Require(pop); err != nil { return err } - if stack.len()+push-pop > int(params.StackLimit) { - return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit) + if stack.Len()+push-pop > int(params.StackLimit) { + return fmt.Errorf("stack limit reached %d (%d)", stack.Len(), params.StackLimit) } return nil } } -func makeDupStackFunc(n int) stackValidationFunc { - return makeStackFunc(n, n+1) +func MakeDupStackFunc(n int) StackValidationFunc { + return MakeStackFunc(n, n+1) } -func makeSwapStackFunc(n int) stackValidationFunc { - return makeStackFunc(n, n) +func MakeSwapStackFunc(n int) StackValidationFunc { + return MakeStackFunc(n, n) } |