diff --git a/execution/evm/log_event_test.go b/execution/evm/log_event_test.go index 3a054d51afd1281da7c51ef66aab91a68425337a..91808042a822a57643f624875f152c22412e9e84 100644 --- a/execution/evm/log_event_test.go +++ b/execution/evm/log_event_test.go @@ -22,6 +22,7 @@ import ( "time" acm "github.com/hyperledger/burrow/account" + "github.com/hyperledger/burrow/account/state" . "github.com/hyperledger/burrow/binary" "github.com/hyperledger/burrow/event" . "github.com/hyperledger/burrow/execution/evm/asm" @@ -42,6 +43,7 @@ var expectedTopics = []Word256{ func TestLog4(t *testing.T) { st := newAppState() + cache := state.NewCache(st) // Create accounts account1 := acm.ConcreteAccount{ Address: acm.Address{1, 3, 5, 7, 9}, @@ -52,7 +54,7 @@ func TestLog4(t *testing.T) { st.accounts[account1.Address()] = account1 st.accounts[account2.Address()] = account2 - ourVm := NewVM(st, newParams(), acm.ZeroAddress, nil, logger) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger) emitter := event.NewEmitter(logging.NewNoopLogger()) @@ -83,7 +85,7 @@ func TestLog4(t *testing.T) { stop, } - _, err := ourVm.Call(account1, account2, code, []byte{}, 0, &gas) + _, err := ourVm.Call(cache, account1, account2, code, []byte{}, 0, &gas) require.NoError(t, err) select { case <-time.After(5 * time.Second): diff --git a/execution/evm/vm.go b/execution/evm/vm.go index 03c67c3fc5c5e83919f037ffffd450190b1f0350..32ea15dff619f8f8b1f9a8ea2d68d879fe9e3252 100644 --- a/execution/evm/vm.go +++ b/execution/evm/vm.go @@ -105,7 +105,6 @@ type Params struct { } type VM struct { - stateWriter state.Writer memoryProvider func() Memory params Params origin acm.Address @@ -119,10 +118,9 @@ type VM struct { dumpTokens bool } -func NewVM(stateWriter state.Writer, params Params, origin acm.Address, txid []byte, +func NewVM(params Params, origin acm.Address, txid []byte, logger *logging.Logger, options ...func(*VM)) *VM { vm := &VM{ - stateWriter: stateWriter, memoryProvider: DefaultDynamicMemoryProvider, params: params, origin: origin, @@ -184,7 +182,7 @@ func (vm *VM) fireCallEvent(exception *string, output *[]byte, callerAddress, ca // value: To be transferred from caller to callee. Refunded upon error. // gas: Available gas. No refunds for gas. // code: May be nil, since the CALL opcode may be used to send value from contracts to accounts -func (vm *VM) Call(caller, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err error) { +func (vm *VM) Call(callState state.Cache, caller, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err error) { exception := new(string) // fire the post call event (including exception if applicable) @@ -194,10 +192,12 @@ func (vm *VM) Call(caller, callee acm.MutableAccount, code, input []byte, value *exception = err.Error() return } + //childCallState + childCallState := state.NewCache(callState) if len(code) > 0 { vm.stackDepth += 1 - output, err = vm.call(caller, callee, code, input, value, gas) + output, err = vm.call(childCallState, caller, callee, code, input, value, gas) vm.stackDepth -= 1 if err != nil { err = ErrCall{ @@ -210,6 +210,9 @@ func (vm *VM) Call(caller, callee acm.MutableAccount, code, input []byte, value return nil, fmt.Errorf("error transferring value %v %s (callee) -> %s (caller)", value, callee, caller) } + } else { + // Copy any state updates from child call frame into current call frame + childCallState.Sync(callState) } if vm.stackDepth == 0 { // clean up ready for next call @@ -224,7 +227,7 @@ func (vm *VM) Call(caller, callee acm.MutableAccount, code, input []byte, value // The intent of delegate call is to run the code of the callee in the storage context of the caller; // while preserving the original caller to the previous callee. // Different to the normal CALL or CALLCODE, the value does not need to be transferred to the callee. -func (vm *VM) DelegateCall(caller acm.Account, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err error) { +func (vm *VM) DelegateCall(callState state.Cache, caller acm.Account, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err error) { exception := new(string) // fire the post call event (including exception if applicable) @@ -234,12 +237,17 @@ func (vm *VM) DelegateCall(caller acm.Account, callee acm.MutableAccount, code, // DelegateCall does not transfer the value to the callee. + childCallState := state.NewCache(callState) + if len(code) > 0 { vm.stackDepth += 1 - output, err = vm.call(caller, callee, code, input, value, gas) + output, err = vm.call(childCallState, caller, callee, code, input, value, gas) vm.stackDepth -= 1 if err != nil { *exception = err.Error() + } else { + // Copy any state updates from child call frame into current call frame + childCallState.Sync(callState) } } @@ -259,7 +267,7 @@ func useGasNegative(gasLeft *uint64, gasToUse uint64, err *error) bool { } // Just like Call() but does not transfer 'value' or modify the callDepth. -func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err error) { +func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err error) { vm.Debugf("(%d) (%X) %X (code=%d) gas: %v (d) %X\n", vm.stackDepth, caller.Address().Bytes()[:4], callee.Address(), len(callee.Code()), *gas, input) @@ -561,7 +569,7 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] if useGasNegative(gas, GasGetAccount, &err) { return nil, err } - acc, errAcc := vm.stateWriter.GetAccount(acm.AddressFromWord256(addr)) + acc, errAcc := callState.GetAccount(acm.AddressFromWord256(addr)) if errAcc != nil { return nil, firstErr(err, errAcc) } @@ -657,7 +665,7 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] if useGasNegative(gas, GasGetAccount, &err) { return nil, err } - acc, errAcc := vm.stateWriter.GetAccount(acm.AddressFromWord256(addr)) + acc, errAcc := callState.GetAccount(acm.AddressFromWord256(addr)) if errAcc != nil { return nil, firstErr(err, errAcc) } @@ -678,7 +686,7 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] if useGasNegative(gas, GasGetAccount, &err) { return nil, err } - acc, errAcc := vm.stateWriter.GetAccount(acm.AddressFromWord256(addr)) + acc, errAcc := callState.GetAccount(acm.AddressFromWord256(addr)) if errAcc != nil { return nil, firstErr(err, errAcc) } @@ -793,7 +801,7 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] case SLOAD: // 0x54 loc := stack.Pop() - data, errSto := vm.stateWriter.GetStorage(callee.Address(), loc) + data, errSto := callState.GetStorage(callee.Address(), loc) if errSto != nil { return nil, firstErr(err, errSto) } @@ -805,7 +813,7 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] if useGasNegative(gas, GasStorageUpdate, &err) { return nil, err } - vm.stateWriter.SetStorage(callee.Address(), loc, data) + callState.SetStorage(callee.Address(), loc, data) vm.Debugf("%s {0x%X := 0x%X}\n", callee.Address(), loc, data) case JUMP: // 0x56 @@ -902,7 +910,7 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] case CREATE: // 0xF0 vm.returnData = nil - if !HasPermission(vm.stateWriter, callee, permission.CreateContract) { + if !HasPermission(callState, callee, permission.CreateContract) { return nil, ErrPermission{"create_contract"} } contractValue, popErr := stack.PopU64() @@ -926,14 +934,14 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] if useGasNegative(gas, GasCreateAccount, &gasErr) { return nil, firstErr(err, gasErr) } - newAccount, createErr := vm.createAccount(callee, logger) + newAccount, createErr := vm.createAccount(callState, callee, logger) if createErr != nil { return nil, firstErr(err, createErr) } // Run the input to get the contract code. // NOTE: no need to copy 'input' as per Call contract. - ret, err_ := vm.Call(callee, newAccount, input, input, contractValue, gas) + ret, err_ := vm.Call(callState, callee, newAccount, input, input, contractValue, gas) if err_ != nil { stack.Push(Zero256) vm.returnData = ret @@ -943,13 +951,13 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] } if err_ == ErrExecutionReverted { - return ret, nil + return nil, ErrExecutionReverted } case CALL, CALLCODE, DELEGATECALL: // 0xF1, 0xF2, 0xF4 vm.returnData = nil - if !HasPermission(vm.stateWriter, callee, permission.Call) { + if !HasPermission(callState, callee, permission.Call) { return nil, ErrPermission{"call"} } gasLimit, popErr := stack.PopU64() @@ -999,7 +1007,7 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] if nativeContract := registeredNativeContracts[addr]; nativeContract != nil { // Native contract - ret, callErr = nativeContract(vm.stateWriter, callee, args, &gasLimit, logger) + ret, callErr = nativeContract(callState, callee, args, &gasLimit, logger) // for now we fire the Call event. maybe later we'll fire more particulars var exception string @@ -1013,7 +1021,7 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] if useGasNegative(gas, GasGetAccount, &callErr) { return nil, callErr } - acc, errAcc := state.GetMutableAccount(vm.stateWriter, acm.AddressFromWord256(addr)) + acc, errAcc := state.GetMutableAccount(callState, acm.AddressFromWord256(addr)) if errAcc != nil { return nil, firstErr(callErr, errAcc) } @@ -1025,23 +1033,23 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] if acc == nil { return nil, firstErr(callErr, ErrUnknownAddress) } - ret, callErr = vm.Call(callee, callee, acc.Code(), args, value, &gasLimit) + ret, callErr = vm.Call(callState, callee, callee, acc.Code(), args, value, &gasLimit) } else if op == DELEGATECALL { if acc == nil { return nil, firstErr(callErr, ErrUnknownAddress) } - ret, callErr = vm.DelegateCall(caller, callee, acc.Code(), args, value, &gasLimit) + ret, callErr = vm.DelegateCall(callState, caller, callee, acc.Code(), args, value, &gasLimit) } else { // nil account means we're sending funds to a new account if acc == nil { - if !HasPermission(vm.stateWriter, caller, permission.CreateAccount) { + if !HasPermission(callState, caller, permission.CreateAccount) { return nil, ErrPermission{"create_account"} } acc = acm.ConcreteAccount{Address: acm.AddressFromWord256(addr)}.MutableAccount() } // add account to the tx cache - vm.stateWriter.UpdateAccount(acc) - ret, callErr = vm.Call(callee, acc, acc.Code(), args, value, &gasLimit) + callState.UpdateAccount(acc) + ret, callErr = vm.Call(callState, callee, acc, acc.Code(), args, value, &gasLimit) } } vm.returnData = ret @@ -1049,11 +1057,11 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] // In case any calls deeper in the stack (particularly SNatives) has altered either of two accounts to which // we hold a reference, we need to freshen our state for subsequent iterations of this call frame's EVM loop var getErr error - caller, getErr = vm.stateWriter.GetAccount(caller.Address()) + caller, getErr = callState.GetAccount(caller.Address()) if getErr != nil { return nil, firstErr(err, getErr) } - callee, getErr = state.GetMutableAccount(vm.stateWriter, callee.Address()) + callee, getErr = state.GetMutableAccount(callState, callee.Address()) if getErr != nil { return nil, firstErr(err, getErr) } @@ -1102,7 +1110,6 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] return output, nil case REVERT: // 0xFD - return nil, fmt.Errorf("REVERT not yet fully implemented") offset, size := stack.PopBigInt(), stack.PopBigInt() output, memErr := memory.Read(offset, size) if memErr != nil { @@ -1121,7 +1128,7 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] if useGasNegative(gas, GasGetAccount, &err) { return nil, err } - receiver, errAcc := state.GetMutableAccount(vm.stateWriter, acm.AddressFromWord256(addr)) + receiver, errAcc := state.GetMutableAccount(callState, acm.AddressFromWord256(addr)) if errAcc != nil { return nil, firstErr(err, errAcc) } @@ -1130,11 +1137,11 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] if useGasNegative(gas, GasCreateAccount, &gasErr) { return nil, firstErr(err, gasErr) } - if !HasPermission(vm.stateWriter, callee, permission.CreateContract) { + if !HasPermission(callState, callee, permission.CreateContract) { return nil, firstErr(err, ErrPermission{"create_contract"}) } var createErr error - receiver, createErr = vm.createAccount(callee, logger) + receiver, createErr = vm.createAccount(callState, callee, logger) if createErr != nil { return nil, firstErr(err, createErr) } @@ -1145,8 +1152,8 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] if errAdd != nil { return nil, firstErr(err, errAdd) } - vm.stateWriter.UpdateAccount(receiver) - vm.stateWriter.RemoveAccount(callee.Address()) + callState.UpdateAccount(receiver) + callState.RemoveAccount(callee.Address()) vm.Debugf(" => (%X) %v\n", addr[:4], callee.Balance()) fallthrough @@ -1155,6 +1162,7 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] case STATICCALL, CREATE2: return nil, fmt.Errorf("%s not yet implemented", op.Name()) + default: vm.Debugf("(pc) %-3v Unknown opcode %X\n", pc, op) return nil, fmt.Errorf("unknown opcode %X", op) @@ -1163,13 +1171,13 @@ func (vm *VM) call(caller acm.Account, callee acm.MutableAccount, code, input [] } } -func (vm *VM) createAccount(callee acm.MutableAccount, logger *logging.Logger) (acm.MutableAccount, error) { - newAccount := DeriveNewAccount(callee, state.GlobalAccountPermissions(vm.stateWriter), logger) - err := vm.stateWriter.UpdateAccount(newAccount) +func (vm *VM) createAccount(callState state.Cache, callee acm.MutableAccount, logger *logging.Logger) (acm.MutableAccount, error) { + newAccount := DeriveNewAccount(callee, state.GlobalAccountPermissions(callState), logger) + err := callState.UpdateAccount(newAccount) if err != nil { return nil, err } - err = vm.stateWriter.UpdateAccount(callee) + err = callState.UpdateAccount(callee) if err != nil { return nil, err } diff --git a/execution/evm/vm_test.go b/execution/evm/vm_test.go index b885d2664aad7e03f163cefaf9c008aade5b1346..edce8d7d8f0f057bab30d54e7d32adb88753dbfb 100644 --- a/execution/evm/vm_test.go +++ b/execution/evm/vm_test.go @@ -74,7 +74,8 @@ func newAccount(seed ...byte) acm.MutableAccount { // Runs a basic loop func TestVM(t *testing.T) { - ourVm := NewVM(newAppState(), newParams(), acm.ZeroAddress, nil, logger) + cache := state.NewCache(newAppState()) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger) // Create accounts account1 := newAccount(1) @@ -87,7 +88,7 @@ func TestVM(t *testing.T) { MSTORE, PUSH1, 0x05, JUMP, JUMPDEST) start := time.Now() - output, err := ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err := ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) fmt.Printf("Output: %v Error: %v\n", output, err) fmt.Println("Call took:", time.Since(start)) if err != nil { @@ -96,7 +97,8 @@ func TestVM(t *testing.T) { } func TestSHL(t *testing.T) { - ourVm := NewVM(newAppState(), newParams(), acm.ZeroAddress, nil, logger) + cache := state.NewCache(newAppState()) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger) account1 := newAccount(1) account2 := newAccount(1, 0, 1) @@ -104,7 +106,7 @@ func TestSHL(t *testing.T) { //Shift left 0 bytecode := MustSplice(PUSH1, 0x01, PUSH1, 0x00, SHL, return1()) - output, err := ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err := ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value := []uint8([]byte{0x1}) expected := LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -118,7 +120,7 @@ func TestSHL(t *testing.T) { //Alternative shift left 0 bytecode = MustSplice(PUSH32, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, PUSH1, 0x00, SHL, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) expected = []uint8([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}) @@ -132,7 +134,7 @@ func TestSHL(t *testing.T) { //Shift left 1 bytecode = MustSplice(PUSH1, 0x01, PUSH1, 0x01, SHL, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x2}) expected = LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -146,7 +148,7 @@ func TestSHL(t *testing.T) { //Alternative shift left 1 bytecode = MustSplice(PUSH32, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, PUSH1, 0x01, SHL, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) expected = []uint8([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}) @@ -161,7 +163,7 @@ func TestSHL(t *testing.T) { //Alternative shift left 1 bytecode = MustSplice(PUSH32, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, PUSH1, 0x01, SHL, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) expected = []uint8([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}) @@ -175,7 +177,7 @@ func TestSHL(t *testing.T) { //Shift left 255 bytecode = MustSplice(PUSH1, 0x01, PUSH1, 0xFF, SHL, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x80}) expected = RightPadBytes(value, 32) assert.Equal(t, expected, output) @@ -189,7 +191,7 @@ func TestSHL(t *testing.T) { //Alternative shift left 255 bytecode = MustSplice(PUSH32, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, PUSH1, 0xFF, SHL, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x80}) expected = RightPadBytes(value, 32) assert.Equal(t, expected, output) @@ -202,7 +204,7 @@ func TestSHL(t *testing.T) { //Shift left 256 (overflow) bytecode = MustSplice(PUSH1, 0x01, PUSH2, 0x01, 0x00, SHL, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x00}) expected = LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -217,7 +219,7 @@ func TestSHL(t *testing.T) { bytecode = MustSplice(PUSH32, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, PUSH2, 0x01, 0x00, SHL, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x00}) expected = LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -230,7 +232,7 @@ func TestSHL(t *testing.T) { //Shift left 257 (overflow) bytecode = MustSplice(PUSH1, 0x01, PUSH2, 0x01, 0x01, SHL, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x00}) expected = LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -244,7 +246,8 @@ func TestSHL(t *testing.T) { } func TestSHR(t *testing.T) { - ourVm := NewVM(newAppState(), newParams(), acm.ZeroAddress, nil, logger) + cache := state.NewCache(newAppState()) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger) account1 := newAccount(1) account2 := newAccount(1, 0, 1) @@ -252,7 +255,7 @@ func TestSHR(t *testing.T) { //Shift right 0 bytecode := MustSplice(PUSH1, 0x01, PUSH1, 0x00, SHR, return1()) - output, err := ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err := ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value := []uint8([]byte{0x1}) expected := LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -266,7 +269,7 @@ func TestSHR(t *testing.T) { //Alternative shift right 0 bytecode = MustSplice(PUSH32, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, PUSH1, 0x00, SHR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) expected = []uint8([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}) @@ -280,7 +283,7 @@ func TestSHR(t *testing.T) { //Shift right 1 bytecode = MustSplice(PUSH1, 0x01, PUSH1, 0x01, SHR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x00}) expected = LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -294,7 +297,7 @@ func TestSHR(t *testing.T) { //Alternative shift right 1 bytecode = MustSplice(PUSH32, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, PUSH1, 0x01, SHR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x40}) expected = RightPadBytes(value, 32) assert.Equal(t, expected, output) @@ -308,7 +311,7 @@ func TestSHR(t *testing.T) { //Alternative shift right 1 bytecode = MustSplice(PUSH32, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, PUSH1, 0x01, SHR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) expected = []uint8([]byte{0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}) @@ -323,7 +326,7 @@ func TestSHR(t *testing.T) { //Shift right 255 bytecode = MustSplice(PUSH32, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, PUSH1, 0xFF, SHR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x1}) expected = LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -337,7 +340,7 @@ func TestSHR(t *testing.T) { //Alternative shift right 255 bytecode = MustSplice(PUSH32, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, PUSH1, 0xFF, SHR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x1}) expected = LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -352,7 +355,7 @@ func TestSHR(t *testing.T) { bytecode = MustSplice(PUSH32, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, PUSH2, 0x01, 0x00, SHR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x00}) expected = LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -367,7 +370,7 @@ func TestSHR(t *testing.T) { bytecode = MustSplice(PUSH32, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, PUSH2, 0x01, 0x00, SHR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x00}) expected = LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -382,7 +385,7 @@ func TestSHR(t *testing.T) { bytecode = MustSplice(PUSH32, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, PUSH2, 0x01, 0x01, SHR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x00}) expected = LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -396,7 +399,8 @@ func TestSHR(t *testing.T) { } func TestSAR(t *testing.T) { - ourVm := NewVM(newAppState(), newParams(), acm.ZeroAddress, nil, logger) + cache := state.NewCache(newAppState()) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger) account1 := newAccount(1) account2 := newAccount(1, 0, 1) @@ -404,7 +408,7 @@ func TestSAR(t *testing.T) { //Shift arith right 0 bytecode := MustSplice(PUSH1, 0x01, PUSH1, 0x00, SAR, return1()) - output, err := ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err := ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value := []uint8([]byte{0x1}) expected := LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -418,7 +422,7 @@ func TestSAR(t *testing.T) { //Alternative arith shift right 0 bytecode = MustSplice(PUSH32, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, PUSH1, 0x00, SAR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) expected = []uint8([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}) @@ -432,7 +436,7 @@ func TestSAR(t *testing.T) { //Shift arith right 1 bytecode = MustSplice(PUSH1, 0x01, PUSH1, 0x01, SAR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x00}) expected = LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -446,7 +450,7 @@ func TestSAR(t *testing.T) { //Alternative shift arith right 1 bytecode = MustSplice(PUSH32, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, PUSH1, 0x01, SAR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0xc0}) expected = RightPadBytes(value, 32) assert.Equal(t, expected, output) @@ -460,7 +464,7 @@ func TestSAR(t *testing.T) { //Alternative shift arith right 1 bytecode = MustSplice(PUSH32, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, PUSH1, 0x01, SAR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) expected = []uint8([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}) @@ -475,7 +479,7 @@ func TestSAR(t *testing.T) { //Shift arith right 255 bytecode = MustSplice(PUSH32, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, PUSH1, 0xFF, SAR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) expected = []uint8([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}) @@ -490,7 +494,7 @@ func TestSAR(t *testing.T) { //Alternative shift arith right 255 bytecode = MustSplice(PUSH32, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, PUSH1, 0xFF, SAR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) expected = []uint8([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}) @@ -505,7 +509,7 @@ func TestSAR(t *testing.T) { //Alternative shift arith right 255 bytecode = MustSplice(PUSH32, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, PUSH1, 0xFF, SAR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x00}) expected = RightPadBytes(value, 32) assert.Equal(t, expected, output) @@ -520,7 +524,7 @@ func TestSAR(t *testing.T) { bytecode = MustSplice(PUSH32, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, PUSH2, 0x01, 0x00, SAR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) expected = []uint8([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}) @@ -536,7 +540,7 @@ func TestSAR(t *testing.T) { bytecode = MustSplice(PUSH32, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, PUSH2, 0x01, 0x00, SAR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) value = []uint8([]byte{0x00}) expected = LeftPadBytes(value, 32) assert.Equal(t, expected, output) @@ -551,7 +555,7 @@ func TestSAR(t *testing.T) { bytecode = MustSplice(PUSH32, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, PUSH2, 0x01, 0x01, SAR, return1()) - output, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) expected = []uint8([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}) @@ -567,7 +571,8 @@ func TestSAR(t *testing.T) { //Test attempt to jump to bad destination (position 16) func TestJumpErr(t *testing.T) { - ourVm := NewVM(newAppState(), newParams(), acm.ZeroAddress, nil, logger) + cache := state.NewCache(newAppState()) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger) // Create accounts account1 := newAccount(1) @@ -580,7 +585,7 @@ func TestJumpErr(t *testing.T) { var err error ch := make(chan struct{}) go func() { - _, err = ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + _, err = ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) ch <- struct{}{} }() tick := time.NewTicker(time.Second * 2) @@ -597,14 +602,17 @@ func TestJumpErr(t *testing.T) { // Tests the code for a subcurrency contract compiled by serpent func TestSubcurrency(t *testing.T) { st := newAppState() - + cache := state.NewCache(st) // Create accounts account1 := newAccount(1, 2, 3) account2 := newAccount(3, 2, 1) - st.accounts[account1.Address()] = account1 - st.accounts[account2.Address()] = account2 + cache.UpdateAccount(account1) + cache.UpdateAccount(account2) + cache.Sync(st) + //st.accounts[account1.Address()] = account1 + //st.accounts[account2.Address()] = account2 - ourVm := NewVM(st, newParams(), acm.ZeroAddress, nil, logger) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger) var gas uint64 = 1000 @@ -623,7 +631,7 @@ func TestSubcurrency(t *testing.T) { JUMPDEST, POP, JUMPDEST, PUSH1, 0x00, RETURN) data, _ := hex.DecodeString("693200CE0000000000000000000000004B4363CDE27C2EB05E66357DB05BC5C88F850C1A0000000000000000000000000000000000000000000000000000000000000005") - output, err := ourVm.Call(account1, account2, bytecode, data, 0, &gas) + output, err := ourVm.Call(cache, account1, account2, bytecode, data, 0, &gas) fmt.Printf("Output: %v Error: %v\n", output, err) if err != nil { t.Fatal(err) @@ -633,59 +641,71 @@ func TestSubcurrency(t *testing.T) { //This test case is taken from EIP-140 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-140.md); //it is meant to test the implementation of the REVERT opcode func TestRevert(t *testing.T) { - ourVm := NewVM(newAppState(), newParams(), acm.ZeroAddress, nil, logger) + cache := state.NewCache(newAppState()) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger) // Create accounts account1 := newAccount(1) account2 := newAccount(1, 0, 1) + key, value := []byte{0x00}, []byte{0x00} + cache.SetStorage(account1.Address(), LeftPadWord256(key), LeftPadWord256(value)) + var gas uint64 = 100000 - bytecode := MustSplice(PUSH32, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x20, 0x6D, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, PUSH1, 0x00, MSTORE, PUSH1, 0x0E, PUSH1, 0x00, REVERT) + bytecode := MustSplice(PUSH13, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, + PUSH1, 0x00, SSTORE, PUSH32, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x20, 0x6D, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + PUSH1, 0x00, MSTORE, PUSH1, 0x0E, PUSH1, 0x00, REVERT) - start := time.Now() - output, err := ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + /*bytecode := MustSplice(PUSH32, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x20, 0x6D, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, PUSH1, 0x00, MSTORE, PUSH1, 0x0E, PUSH1, 0x00, REVERT)*/ + + output, err := ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) assert.Error(t, err, "Expected execution reverted error") - fmt.Printf("Output: %v Error: %v\n", output, err) - fmt.Println("Call took:", time.Since(start)) + + storageVal, err := cache.GetStorage(account1.Address(), LeftPadWord256(key)) + assert.Equal(t, LeftPadWord256(value), storageVal) + + t.Logf("Output: %v Error: %v\n", output, err) + } // Test sending tokens from a contract to another account func TestSendCall(t *testing.T) { - fakeAppState := newAppState() - ourVm := NewVM(fakeAppState, newParams(), acm.ZeroAddress, nil, logger) + cache := state.NewCache(newAppState()) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger) // Create accounts account1 := newAccount(1) account2 := newAccount(2) account3 := newAccount(3) - fakeAppState.UpdateAccount(account1) - fakeAppState.UpdateAccount(account2) - fakeAppState.UpdateAccount(account3) + cache.UpdateAccount(account1) + cache.UpdateAccount(account2) + cache.UpdateAccount(account3) // account1 will call account2 which will trigger CALL opcode to account3 addr := account3.Address() contractCode := callContractCode(addr) //---------------------------------------------- // account2 has insufficient balance, should fail - _, err := runVMWaitError(ourVm, account1, account2, addr, contractCode, 1000) + _, err := runVMWaitError(cache, ourVm, account1, account2, addr, contractCode, 1000) assert.Error(t, err, "Expected insufficient balance error") //---------------------------------------------- // give account2 sufficient balance, should pass account2, err = newAccount(2).AddToBalance(100000) require.NoError(t, err) - _, err = runVMWaitError(ourVm, account1, account2, addr, contractCode, 1000) + _, err = runVMWaitError(cache, ourVm, account1, account2, addr, contractCode, 1000) assert.NoError(t, err, "Should have sufficient balance") //---------------------------------------------- // insufficient gas, should fail account2, err = newAccount(2).AddToBalance(100000) require.NoError(t, err) - _, err = runVMWaitError(ourVm, account1, account2, addr, contractCode, 100) + _, err = runVMWaitError(cache, ourVm, account1, account2, addr, contractCode, 100) assert.NoError(t, err, "Expected insufficient gas error") } @@ -695,8 +715,8 @@ func TestSendCall(t *testing.T) { // We first run the DELEGATECALL with _just_ enough gas expecting a simple return, // and then run it with 1 gas unit less, expecting a failure func TestDelegateCallGas(t *testing.T) { - appState := newAppState() - ourVm := NewVM(appState, newParams(), acm.ZeroAddress, nil, logger) + cache := state.NewCache(newAppState()) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger) inOff := 0 inSize := 0 // no call data @@ -716,7 +736,7 @@ func TestDelegateCallGas(t *testing.T) { costBetweenGasAndDelegateCall := gasCost + subCost + delegateCallCost + pushCost // Do a simple operation using 1 gas unit - calleeAccount, calleeAddress := makeAccountWithCode(appState, "callee", + calleeAccount, calleeAddress := makeAccountWithCode(cache, "callee", MustSplice(PUSH1, calleeReturnValue, return1())) // Here we split up the caller code so we can make a DELEGATE call with @@ -729,14 +749,14 @@ func TestDelegateCallGas(t *testing.T) { callerCodeSuffix := MustSplice(GAS, SUB, DELEGATECALL, returnWord()) // Perform a delegate call - callerAccount, _ := makeAccountWithCode(appState, "caller", + callerAccount, _ := makeAccountWithCode(cache, "caller", MustSplice(callerCodePrefix, // Give just enough gas to make the DELEGATECALL costBetweenGasAndDelegateCall, callerCodeSuffix)) // Should pass - output, err := runVMWaitError(ourVm, callerAccount, calleeAccount, calleeAddress, + output, err := runVMWaitError(cache, ourVm, callerAccount, calleeAccount, calleeAddress, callerAccount.Code(), 100) assert.NoError(t, err, "Should have sufficient funds for call") assert.Equal(t, Int64ToWord256(calleeReturnValue).Bytes(), output) @@ -747,23 +767,23 @@ func TestDelegateCallGas(t *testing.T) { callerCodeSuffix)) // Should fail - _, err = runVMWaitError(ourVm, callerAccount, calleeAccount, calleeAddress, + _, err = runVMWaitError(cache, ourVm, callerAccount, calleeAccount, calleeAddress, callerAccount.Code(), 100) assert.Error(t, err, "Should have insufficient gas for call") } func TestMemoryBounds(t *testing.T) { - appState := newAppState() + cache := state.NewCache(newAppState()) memoryProvider := func() Memory { return NewDynamicMemory(1024, 2048) } - ourVm := NewVM(appState, newParams(), acm.ZeroAddress, nil, logger, MemoryProvider(memoryProvider)) - caller, _ := makeAccountWithCode(appState, "caller", nil) - callee, _ := makeAccountWithCode(appState, "callee", nil) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger, MemoryProvider(memoryProvider)) + caller, _ := makeAccountWithCode(cache, "caller", nil) + callee, _ := makeAccountWithCode(cache, "callee", nil) gas := uint64(100000) // This attempts to store a value at the memory boundary and return it word := One256 - output, err := ourVm.call(caller, callee, + output, err := ourVm.call(cache, caller, callee, MustSplice(pushWord(word), storeAtEnd(), MLOAD, storeAtEnd(), returnAfterStore()), nil, 0, &gas) assert.NoError(t, err) @@ -771,7 +791,7 @@ func TestMemoryBounds(t *testing.T) { // Same with number word = Int64ToWord256(232234234432) - output, err = ourVm.call(caller, callee, + output, err = ourVm.call(cache, caller, callee, MustSplice(pushWord(word), storeAtEnd(), MLOAD, storeAtEnd(), returnAfterStore()), nil, 0, &gas) assert.NoError(t, err) @@ -782,7 +802,7 @@ func TestMemoryBounds(t *testing.T) { for i := 0; i < 10; i++ { code = MustSplice(code, storeAtEnd(), MLOAD) } - output, err = ourVm.call(caller, callee, MustSplice(code, storeAtEnd(), returnAfterStore()), + output, err = ourVm.call(cache, caller, callee, MustSplice(code, storeAtEnd(), returnAfterStore()), nil, 0, &gas) assert.NoError(t, err) assert.Equal(t, word.Bytes(), output) @@ -792,19 +812,23 @@ func TestMemoryBounds(t *testing.T) { for i := 0; i < 100; i++ { code = MustSplice(code, storeAtEnd(), MLOAD) } - output, err = ourVm.call(caller, callee, MustSplice(code, storeAtEnd(), returnAfterStore()), + output, err = ourVm.call(cache, caller, callee, MustSplice(code, storeAtEnd(), returnAfterStore()), nil, 0, &gas) assert.Error(t, err, "Should hit memory out of bounds") } func TestMsgSender(t *testing.T) { st := newAppState() + cache := state.NewCache(st) account1 := newAccount(1, 2, 3) account2 := newAccount(3, 2, 1) - st.accounts[account1.Address()] = account1 - st.accounts[account2.Address()] = account2 + cache.UpdateAccount(account1) + cache.UpdateAccount(account2) + cache.Sync(st) + //st.accounts[account1.Address()] = account1 + //st.accounts[account2.Address()] = account2 - ourVm := NewVM(st, newParams(), acm.ZeroAddress, nil, logger) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger) var gas uint64 = 100000 @@ -827,7 +851,7 @@ func TestMsgSender(t *testing.T) { require.NoError(t, err) // Run the contract initialisation code to obtain the contract code that would be mounted at account2 - contractCode, err := ourVm.Call(account1, account2, code, code, 0, &gas) + contractCode, err := ourVm.Call(cache, account1, account2, code, code, 0, &gas) require.NoError(t, err) // Not needed for this test (since contract code is passed as argument to vm), but this is what an execution @@ -837,7 +861,7 @@ func TestMsgSender(t *testing.T) { // Input is the function hash of `get()` input, err := hex.DecodeString("6d4ce63c") - output, err := ourVm.Call(account1, account2, contractCode, input, 0, &gas) + output, err := ourVm.Call(cache, account1, account2, contractCode, input, 0, &gas) require.NoError(t, err) assert.Equal(t, account1.Address().Word256().Bytes(), output) @@ -845,7 +869,8 @@ func TestMsgSender(t *testing.T) { } func TestInvalid(t *testing.T) { - ourVm := NewVM(newAppState(), newParams(), acm.ZeroAddress, nil, logger) + cache := state.NewCache(newAppState()) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger) // Create accounts account1 := newAccount(1) @@ -857,7 +882,7 @@ func TestInvalid(t *testing.T) { 0x67, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, PUSH1, 0x00, MSTORE, PUSH1, 0x0E, PUSH1, 0x00, INVALID) - output, err := ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err := ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) expected := "call error: " + ErrExecutionAborted.Error() assert.EqualError(t, err, expected) t.Logf("Output: %v Error: %v\n", output, err) @@ -866,7 +891,7 @@ func TestInvalid(t *testing.T) { func TestReturnDataSize(t *testing.T) { cache := state.NewCache(newAppState()) - ourVm := NewVM(cache, newParams(), acm.ZeroAddress, nil, logger) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger) accountName := "account2addresstests" @@ -877,6 +902,7 @@ func TestReturnDataSize(t *testing.T) { // Create accounts account1 := newAccount(1) account2, _ := makeAccountWithCode(cache, accountName, callcode) + cache.UpdateAccount(account2) var gas uint64 = 100000 @@ -891,7 +917,7 @@ func TestReturnDataSize(t *testing.T) { expected := LeftPadBytes([]byte{0x0E}, 32) - output, err := ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err := ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) assert.Equal(t, expected, output) @@ -904,7 +930,7 @@ func TestReturnDataSize(t *testing.T) { func TestReturnDataCopy(t *testing.T) { cache := state.NewCache(newAppState()) - ourVm := NewVM(cache, newParams(), acm.ZeroAddress, nil, logger) + ourVm := NewVM(newParams(), acm.ZeroAddress, nil, logger) accountName := "account2addresstests" @@ -915,6 +941,7 @@ func TestReturnDataCopy(t *testing.T) { // Create accounts account1 := newAccount(1) account2, _ := makeAccountWithCode(cache, accountName, callcode) + cache.UpdateAccount(account2) var gas uint64 = 100000 @@ -930,7 +957,7 @@ func TestReturnDataCopy(t *testing.T) { expected := []byte{0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x20, 0x6D, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65} - output, err := ourVm.Call(account1, account2, bytecode, []byte{}, 0, &gas) + output, err := ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas) assert.Equal(t, expected, output) @@ -984,10 +1011,10 @@ func makeAccountWithCode(accountUpdater state.AccountUpdater, name string, // and then waits for any exceptions transmitted by Data in the AccCall // event (in the case of no direct error from call we will block waiting for // at least 1 AccCall event) -func runVMWaitError(ourVm *VM, caller, callee acm.MutableAccount, subscribeAddr acm.Address, +func runVMWaitError(vmCache state.Cache, ourVm *VM, caller, callee acm.MutableAccount, subscribeAddr acm.Address, contractCode []byte, gas uint64) ([]byte, error) { eventCh := make(chan *evm_events.EventDataCall) - output, err := runVM(eventCh, ourVm, caller, callee, subscribeAddr, contractCode, gas) + output, err := runVM(eventCh, vmCache, ourVm, caller, callee, subscribeAddr, contractCode, gas) if err != nil { return output, err } @@ -1002,7 +1029,7 @@ func runVMWaitError(ourVm *VM, caller, callee acm.MutableAccount, subscribeAddr // Subscribes to an AccCall, runs the vm, returns the output and any direct // exception -func runVM(eventCh chan<- *evm_events.EventDataCall, ourVm *VM, caller, callee acm.MutableAccount, +func runVM(eventCh chan<- *evm_events.EventDataCall, vmCache state.Cache, ourVm *VM, caller, callee acm.MutableAccount, subscribeAddr acm.Address, contractCode []byte, gas uint64) ([]byte, error) { // we need to catch the event from the CALL to check for exceptions @@ -1017,7 +1044,7 @@ func runVM(eventCh chan<- *evm_events.EventDataCall, ourVm *VM, caller, callee a evc := event.NewEventCache(emitter) ourVm.SetPublisher(evc) start := time.Now() - output, err := ourVm.Call(caller, callee, contractCode, []byte{}, 0, &gas) + output, err := ourVm.Call(vmCache, caller, callee, contractCode, []byte{}, 0, &gas) fmt.Printf("Output: %v Error: %v\n", output, err) fmt.Println("Call took:", time.Since(start)) evc.Flush() diff --git a/execution/execution.go b/execution/execution.go index ee3c342fbe486dee7b0db3752649f7de7518d585..a26646e00096aba66eaf2cb4bb1ee33190c36091 100644 --- a/execution/execution.go +++ b/execution/execution.go @@ -388,10 +388,10 @@ func (exe *executor) Execute(tx txs.Tx) (err error) { // Write caller/callee to txCache. txCache.UpdateAccount(caller) txCache.UpdateAccount(callee) - vmach := evm.NewVM(txCache, params, caller.Address(), tx.Hash(exe.chainID), logger, exe.vmOptions...) + vmach := evm.NewVM(params, caller.Address(), tx.Hash(exe.chainID), logger, exe.vmOptions...) vmach.SetPublisher(exe.eventCache) // NOTE: Call() transfers the value from caller to callee iff call succeeds. - ret, err = vmach.Call(caller, callee, code, tx.Data, value, &gas) + ret, err = vmach.Call(txCache, caller, callee, code, tx.Data, value, &gas) if err != nil { // Failure. Charge the gas fee. The 'value' was otherwise not transferred. logger.InfoMsg("Error on execution", diff --git a/execution/transactor.go b/execution/transactor.go index f42278b580a15c02cb8d6f695cfc562ef984e6ee..d6e2206d3a8dcf40e220d8a7dd6a777cea4eb665 100644 --- a/execution/transactor.go +++ b/execution/transactor.go @@ -87,7 +87,7 @@ func (trans *Transactor) Call(reader state.Reader, fromAddress, toAddress acm.Ad txCache := state.NewCache(reader) params := vmParams(trans.tip) - vmach := evm.NewVM(txCache, params, caller.Address(), nil, trans.logger.WithScope("Call")) + vmach := evm.NewVM(params, caller.Address(), nil, trans.logger.WithScope("Call")) vmach.SetPublisher(trans.eventEmitter) gas := params.GasLimit @@ -96,7 +96,7 @@ func (trans *Transactor) Call(reader state.Reader, fromAddress, toAddress acm.Ad err = fmt.Errorf("panic from VM in simulated call: %v\n%s", r, debug.Stack()) } }() - ret, err := vmach.Call(caller, callee, callee.Code(), data, 0, &gas) + ret, err := vmach.Call(txCache, caller, callee, callee.Code(), data, 0, &gas) if err != nil { return nil, err } @@ -113,9 +113,9 @@ func (trans *Transactor) CallCode(reader state.Reader, fromAddress acm.Address, txCache := state.NewCache(reader) params := vmParams(trans.tip) - vmach := evm.NewVM(txCache, params, caller.Address(), nil, trans.logger.WithScope("CallCode")) + vmach := evm.NewVM(params, caller.Address(), nil, trans.logger.WithScope("CallCode")) gas := params.GasLimit - ret, err := vmach.Call(caller, callee, code, data, 0, &gas) + ret, err := vmach.Call(txCache, caller, callee, code, data, 0, &gas) if err != nil { return nil, err }