github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/tests/vm_test_util.go (about) 1 package tests 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "math/big" 8 9 "github.com/neatlab/neatio/chain/core" 10 "github.com/neatlab/neatio/chain/core/rawdb" 11 "github.com/neatlab/neatio/chain/core/state" 12 "github.com/neatlab/neatio/chain/core/vm" 13 "github.com/neatlab/neatio/params" 14 "github.com/neatlab/neatio/utilities/common" 15 "github.com/neatlab/neatio/utilities/common/hexutil" 16 "github.com/neatlab/neatio/utilities/common/math" 17 "github.com/neatlab/neatio/utilities/crypto" 18 ) 19 20 type VMTest struct { 21 json vmJSON 22 } 23 24 func (t *VMTest) UnmarshalJSON(data []byte) error { 25 return json.Unmarshal(data, &t.json) 26 } 27 28 type vmJSON struct { 29 Env stEnv `json:"env"` 30 Exec vmExec `json:"exec"` 31 Logs common.UnprefixedHash `json:"logs"` 32 GasRemaining *math.HexOrDecimal64 `json:"gas"` 33 Out hexutil.Bytes `json:"out"` 34 Pre core.GenesisAlloc `json:"pre"` 35 Post core.GenesisAlloc `json:"post"` 36 PostStateRoot common.Hash `json:"postStateRoot"` 37 } 38 39 type vmExec struct { 40 Address common.Address `json:"address" gencodec:"required"` 41 Caller common.Address `json:"caller" gencodec:"required"` 42 Origin common.Address `json:"origin" gencodec:"required"` 43 Code []byte `json:"code" gencodec:"required"` 44 Data []byte `json:"data" gencodec:"required"` 45 Value *big.Int `json:"value" gencodec:"required"` 46 GasLimit uint64 `json:"gas" gencodec:"required"` 47 GasPrice *big.Int `json:"gasPrice" gencodec:"required"` 48 } 49 50 type vmExecMarshaling struct { 51 Address common.UnprefixedAddress 52 Caller common.UnprefixedAddress 53 Origin common.UnprefixedAddress 54 Code hexutil.Bytes 55 Data hexutil.Bytes 56 Value *math.HexOrDecimal256 57 GasLimit math.HexOrDecimal64 58 GasPrice *math.HexOrDecimal256 59 } 60 61 func (t *VMTest) Run(vmconfig vm.Config) error { 62 db := rawdb.NewMemoryDatabase() 63 statedb := MakePreState(db, t.json.Pre) 64 ret, gasRemaining, err := t.exec(statedb, vmconfig) 65 66 if t.json.GasRemaining == nil { 67 if err == nil { 68 return fmt.Errorf("gas unspecified (indicating an error), but VM returned no error") 69 } 70 if gasRemaining > 0 { 71 return fmt.Errorf("gas unspecified (indicating an error), but VM returned gas remaining > 0") 72 } 73 return nil 74 } 75 76 if !bytes.Equal(ret, t.json.Out) { 77 return fmt.Errorf("return data mismatch: got %x, want %x", ret, t.json.Out) 78 } 79 if gasRemaining != uint64(*t.json.GasRemaining) { 80 return fmt.Errorf("remaining gas %v, want %v", gasRemaining, *t.json.GasRemaining) 81 } 82 for addr, account := range t.json.Post { 83 for k, wantV := range account.Storage { 84 if haveV := statedb.GetState(addr, k); haveV != wantV { 85 return fmt.Errorf("wrong storage value at %x:\n got %x\n want %x", k, haveV, wantV) 86 } 87 } 88 } 89 90 if logs := rlpHash(statedb.Logs()); logs != common.Hash(t.json.Logs) { 91 return fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, t.json.Logs) 92 } 93 return nil 94 } 95 96 func (t *VMTest) exec(statedb *state.StateDB, vmconfig vm.Config) ([]byte, uint64, error) { 97 evm := t.newEVM(statedb, vmconfig) 98 e := t.json.Exec 99 return evm.Call(vm.AccountRef(e.Caller), e.Address, e.Data, e.GasLimit, e.Value) 100 } 101 102 func (t *VMTest) newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM { 103 initialCall := true 104 canTransfer := func(db vm.StateDB, address common.Address, amount *big.Int) bool { 105 if initialCall { 106 initialCall = false 107 return true 108 } 109 return core.CanTransfer(db, address, amount) 110 } 111 transfer := func(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {} 112 context := vm.Context{ 113 CanTransfer: canTransfer, 114 Transfer: transfer, 115 GetHash: vmTestBlockHash, 116 Origin: t.json.Exec.Origin, 117 Coinbase: t.json.Env.Coinbase, 118 BlockNumber: new(big.Int).SetUint64(t.json.Env.Number), 119 Time: new(big.Int).SetUint64(t.json.Env.Timestamp), 120 GasLimit: t.json.Env.GasLimit, 121 Difficulty: t.json.Env.Difficulty, 122 GasPrice: t.json.Exec.GasPrice, 123 } 124 vmconfig.NoRecursion = true 125 return vm.NewEVM(context, statedb, params.MainnetChainConfig, vmconfig) 126 } 127 128 func vmTestBlockHash(n uint64) common.Hash { 129 return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String()))) 130 }