diff --git a/jsonrpc/eth_endpoint.go b/jsonrpc/eth_endpoint.go index 83d8b876f9..ac868fcd12 100644 --- a/jsonrpc/eth_endpoint.go +++ b/jsonrpc/eth_endpoint.go @@ -6,7 +6,6 @@ import ( "math/big" "github.com/hashicorp/go-hclog" - "github.com/umbracle/fastrlp" "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/helper/common" @@ -358,23 +357,8 @@ func (e *Eth) GetStorageAt( return nil, err } - // TODO: GetStorage should return the values already parsed - - // Parse the RLP value - p := &fastrlp.Parser{} - - v, err := p.Parse(result) - if err != nil { - return argBytesPtr(types.ZeroHash[:]), nil - } - - data, err := v.Bytes() - if err != nil { - return argBytesPtr(types.ZeroHash[:]), nil - } - // Pad to return 32 bytes data - return argBytesPtr(types.BytesToHash(data).Bytes()), nil + return argBytesPtr(types.BytesToHash(result).Bytes()), nil } // GasPrice returns the average gas price based on the last x blocks diff --git a/state/runtime/tracer/structtracer/tracer.go b/state/runtime/tracer/structtracer/tracer.go index 24260abcc7..42278912ab 100644 --- a/state/runtime/tracer/structtracer/tracer.go +++ b/state/runtime/tracer/structtracer/tracer.go @@ -55,17 +55,22 @@ type StructTracer struct { consumedGas uint64 output []byte err error - storage map[types.Address]map[types.Hash]types.Hash - currentMemory []byte - currentStack []*big.Int + storage []map[types.Address]map[types.Hash]types.Hash + currentMemory []([]byte) + currentStack []([]*big.Int) } func NewStructTracer(config Config) *StructTracer { + storage := make([](map[types.Address]map[types.Hash]types.Hash), 1) + storage[0] = make(map[types.Address]map[types.Hash]types.Hash) + return &StructTracer{ - Config: config, - cancelLock: sync.RWMutex{}, - storage: make(map[types.Address]map[types.Hash]types.Hash), + Config: config, + cancelLock: sync.RWMutex{}, + storage: storage, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), } } @@ -92,9 +97,10 @@ func (t *StructTracer) Clear() { t.consumedGas = 0 t.output = t.output[:0] t.err = nil - t.storage = make(map[types.Address]map[types.Hash]types.Hash) - t.currentMemory = t.currentMemory[:0] - t.currentStack = t.currentStack[:0] + t.storage = make([](map[types.Address]map[types.Hash]types.Hash), 1) + t.storage[0] = make(map[types.Address]map[types.Hash]types.Hash) + t.currentMemory = make([]([]byte), 1) + t.currentStack = make([]([]*big.Int), 1) } func (t *StructTracer) TxStart(gasLimit uint64) { @@ -141,9 +147,9 @@ func (t *StructTracer) CaptureState( return } - t.captureMemory(memory) + t.captureMemory(memory, opCode) - t.captureStack(stack, sp) + t.captureStack(stack, sp, opCode) t.captureStorage( stack, @@ -156,33 +162,46 @@ func (t *StructTracer) CaptureState( func (t *StructTracer) captureMemory( memory []byte, + opCode int, ) { if !t.Config.EnableMemory { return } // always allocate new space to get new reference - t.currentMemory = make([]byte, len(memory)) + currentMemory := make([]byte, len(memory)) + copy(currentMemory, memory) - copy(t.currentMemory, memory) + t.currentMemory[len(t.currentMemory)-1] = currentMemory + + if opCode == evm.CALL || opCode == evm.STATICCALL { + t.currentMemory = append(t.currentMemory, make([]byte, len(memory))) + } } func (t *StructTracer) captureStack( stack []*big.Int, sp int, + opCode int, ) { if !t.Config.EnableStack { return } - t.currentStack = make([]*big.Int, sp) + currentStack := make([]*big.Int, sp) for i, v := range stack { if i >= sp { break } - t.currentStack[i] = new(big.Int).Set(v) + currentStack[i] = new(big.Int).Set(v) + } + + t.currentStack[len(t.currentStack)-1] = currentStack + + if opCode == evm.CALL || opCode == evm.STATICCALL { + t.currentStack = append(t.currentStack, make([]*big.Int, sp)) } } @@ -193,11 +212,16 @@ func (t *StructTracer) captureStorage( sp int, host tracer.RuntimeHost, ) { + if opCode == evm.CALL || opCode == evm.STATICCALL { + t.storage = append(t.storage, make(map[types.Address]map[types.Hash]types.Hash)) + } + if !t.Config.EnableStorage || (opCode != evm.SLOAD && opCode != evm.SSTORE) { return } - _, initialized := t.storage[contractAddress] + storage := &t.storage[len(t.storage)-1] + _, initialized := (*storage)[contractAddress] switch opCode { case evm.SLOAD: @@ -206,13 +230,13 @@ func (t *StructTracer) captureStorage( } if !initialized { - t.storage[contractAddress] = make(map[types.Hash]types.Hash) + (*storage)[contractAddress] = make(map[types.Hash]types.Hash) } slot := types.BytesToHash(stack[sp-1].Bytes()) value := host.GetStorage(contractAddress, slot) - t.storage[contractAddress][slot] = value + (*storage)[contractAddress][slot] = value case evm.SSTORE: if sp < 2 { @@ -220,13 +244,13 @@ func (t *StructTracer) captureStorage( } if !initialized { - t.storage[contractAddress] = make(map[types.Hash]types.Hash) + (*storage)[contractAddress] = make(map[types.Hash]types.Hash) } - slot := types.BytesToHash(stack[sp-2].Bytes()) - value := types.BytesToHash(stack[sp-1].Bytes()) + slot := types.BytesToHash(stack[sp-1].Bytes()) + value := types.BytesToHash(stack[sp-2].Bytes()) - t.storage[contractAddress][slot] = value + (*storage)[contractAddress][slot] = value } } @@ -250,16 +274,22 @@ func (t *StructTracer) ExecuteState( ) if t.Config.EnableMemory { - memorySize = len(t.currentMemory) + if opCode == evm.OpCode(evm.CALL).String() || opCode == evm.OpCode(evm.STATICCALL).String() { + t.currentMemory = t.currentMemory[:len(t.currentMemory)-1] + } + memorySize = len(t.currentMemory[len(t.currentMemory)-1]) memory = make([]byte, memorySize) - copy(memory, t.currentMemory) + copy(memory, t.currentMemory[len(t.currentMemory)-1]) } if t.Config.EnableStack { - stack = make([]*big.Int, len(t.currentStack)) + if opCode == evm.OpCode(evm.CALL).String() || opCode == evm.OpCode(evm.STATICCALL).String() { + t.currentStack = t.currentStack[:len(t.currentStack)-1] + } - for i, v := range t.currentStack { + stack = make([]*big.Int, len(t.currentStack[len(t.currentStack)-1])) + for i, v := range t.currentStack[len(t.currentStack)-1] { stack[i] = new(big.Int).Set(v) } } @@ -271,7 +301,12 @@ func (t *StructTracer) ExecuteState( } if t.Config.EnableStorage { - contractStorage, ok := t.storage[contractAddress] + if opCode == evm.OpCode(evm.CALL).String() || opCode == evm.OpCode(evm.STATICCALL).String() { + t.storage = t.storage[:len(t.storage)-1] + } + + contractStorage, ok := t.storage[len(t.storage)-1][contractAddress] + if ok { storage = make(map[types.Hash]types.Hash, len(contractStorage)) diff --git a/state/runtime/tracer/structtracer/tracer_test.go b/state/runtime/tracer/structtracer/tracer_test.go index f2660faedb..abbca4884d 100644 --- a/state/runtime/tracer/structtracer/tracer_test.go +++ b/state/runtime/tracer/structtracer/tracer_test.go @@ -131,16 +131,18 @@ func TestStructTracerClear(t *testing.T) { consumedGas: 512, output: []byte("output example"), err: runtime.ErrInsufficientBalance, - storage: map[types.Address]map[types.Hash]types.Hash{ - types.StringToAddress("1"): { - types.StringToHash("2"): types.StringToHash("3"), + storage: []map[types.Address]map[types.Hash]types.Hash{ + { + types.StringToAddress("1"): { + types.StringToHash("2"): types.StringToHash("3"), + }, }, }, - currentMemory: []byte("memory example"), - currentStack: []*big.Int{ + currentMemory: [][]byte{[]byte("memory example")}, + currentStack: []([]*big.Int){[]*big.Int{ new(big.Int).SetUint64(1), new(big.Int).SetUint64(2), - }, + }}, } tracer.Clear() @@ -154,16 +156,18 @@ func TestStructTracerClear(t *testing.T) { EnableStorage: true, EnableReturnData: true, }, - reason: nil, - interrupt: false, - logs: []StructLog{}, - gasLimit: 0, - consumedGas: 0, - output: []byte{}, - err: nil, - storage: map[types.Address]map[types.Hash]types.Hash{}, - currentMemory: []byte{}, - currentStack: []*big.Int{}, + reason: nil, + interrupt: false, + logs: []StructLog{}, + gasLimit: 0, + consumedGas: 0, + output: []byte{}, + err: nil, + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), }, tracer, ) @@ -183,9 +187,13 @@ func TestStructTracerTxStart(t *testing.T) { assert.Equal( t, &StructTracer{ - Config: testEmptyConfig, - storage: make(map[types.Address]map[types.Hash]types.Hash), - gasLimit: gasLimit, + Config: testEmptyConfig, + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, + gasLimit: gasLimit, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), }, tracer, ) @@ -207,10 +215,14 @@ func TestStructTracerTxEnd(t *testing.T) { assert.Equal( t, &StructTracer{ - Config: testEmptyConfig, - storage: make(map[types.Address]map[types.Hash]types.Hash), - gasLimit: gasLimit, - consumedGas: gasLimit - gasLeft, + Config: testEmptyConfig, + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, + gasLimit: gasLimit, + consumedGas: gasLimit - gasLeft, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), }, tracer, ) @@ -260,10 +272,14 @@ func TestStructTracerCallEnd(t *testing.T) { output: output, err: err, expected: &StructTracer{ - Config: testEmptyConfig, - storage: make(map[types.Address]map[types.Hash]types.Hash), - output: output, - err: err, + Config: testEmptyConfig, + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, + output: output, + err: err, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), }, }, { @@ -272,8 +288,12 @@ func TestStructTracerCallEnd(t *testing.T) { output: output, err: err, expected: &StructTracer{ - Config: testEmptyConfig, - storage: make(map[types.Address]map[types.Hash]types.Hash), + Config: testEmptyConfig, + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), }, }, } @@ -301,11 +321,11 @@ func TestStructTracerCaptureState(t *testing.T) { t.Parallel() var ( - memory = []byte("memory") - stack = []*big.Int{ - big.NewInt(1), - big.NewInt(2), - } + memory = [][]byte{[]byte("memory")} + stack = []([]*big.Int){[]*big.Int{ + big.NewInt(1), /* value */ + big.NewInt(2), /* key */ + }} contractAddress = types.StringToAddress("3") storageValue = types.StringToHash("4") ) @@ -317,8 +337,8 @@ func TestStructTracerCaptureState(t *testing.T) { tracer *StructTracer // input - memory []byte - stack []*big.Int + memory [][]byte + stack [][]*big.Int opCode int contractAddress types.Address sp int @@ -335,6 +355,7 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableMemory: true, }, + currentMemory: make([]([]byte), 1), }, memory: memory, stack: stack, @@ -359,6 +380,7 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStack: true, }, + currentStack: make([]([]*big.Int), 1), }, memory: memory, stack: stack, @@ -383,7 +405,9 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: make(map[types.Address]map[types.Hash]types.Hash), + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, }, memory: memory, stack: stack, @@ -405,9 +429,11 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: map[types.Address]map[types.Hash]types.Hash{ - contractAddress: { - types.BytesToHash(big.NewInt(2).Bytes()): storageValue, + storage: [](map[types.Address]map[types.Hash]types.Hash){ + map[types.Address]map[types.Hash]types.Hash{ + contractAddress: { + types.BytesToHash(big.NewInt(2).Bytes()): storageValue, + }, }, }, }, @@ -419,7 +445,9 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: make(map[types.Address]map[types.Hash]types.Hash), + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, }, memory: memory, stack: stack, @@ -434,12 +462,13 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: map[types.Address]map[types.Hash]types.Hash{ - contractAddress: { - types.BytesToHash(big.NewInt(1).Bytes()): types.BytesToHash(big.NewInt(2).Bytes()), + storage: []map[types.Address]map[types.Hash]types.Hash{ + { + contractAddress: { + types.BytesToHash(big.NewInt(2).Bytes()): types.BytesToHash(big.NewInt(1).Bytes()), + }, }, - }, - }, + }}, expectedVMState: &mockState{}, }, { @@ -471,7 +500,9 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: make(map[types.Address]map[types.Hash]types.Hash), + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, }, memory: memory, stack: stack, @@ -486,7 +517,9 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: map[types.Address]map[types.Hash]types.Hash{}, + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, }, expectedVMState: &mockState{}, }, @@ -496,7 +529,9 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: make(map[types.Address]map[types.Hash]types.Hash), + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, }, memory: memory, stack: stack, @@ -511,7 +546,9 @@ func TestStructTracerCaptureState(t *testing.T) { Config: Config{ EnableStorage: true, }, - storage: map[types.Address]map[types.Hash]types.Hash{}, + storage: []map[types.Address]map[types.Hash]types.Hash{ + make(map[types.Address]map[types.Hash]types.Hash), + }, }, expectedVMState: &mockState{}, }, @@ -524,8 +561,8 @@ func TestStructTracerCaptureState(t *testing.T) { t.Parallel() test.tracer.CaptureState( - test.memory, - test.stack, + test.memory[0], + test.stack[0], test.opCode, test.contractAddress, test.sp, @@ -562,8 +599,8 @@ func TestStructTracerExecuteState(t *testing.T) { err = errors.New("err") refund = uint64(10000) - memory = []byte("memory sample") - storage = map[types.Address]map[types.Hash]types.Hash{ + memory = [][]byte{[]byte("memory sample")} + storage = []map[types.Address]map[types.Hash]types.Hash{{ contractAddress: { types.StringToHash("1"): types.StringToHash("2"), types.StringToHash("3"): types.StringToHash("4"), @@ -572,6 +609,7 @@ func TestStructTracerExecuteState(t *testing.T) { types.StringToHash("5"): types.StringToHash("6"), types.StringToHash("7"): types.StringToHash("8"), }, + }, } ) @@ -657,8 +695,8 @@ func TestStructTracerExecuteState(t *testing.T) { Op: opCode, Gas: availableGas, GasCost: cost, - Memory: memory, - MemorySize: len(memory), + Memory: memory[0], + MemorySize: len(memory[0]), Stack: nil, ReturnData: nil, Storage: nil, @@ -674,10 +712,10 @@ func TestStructTracerExecuteState(t *testing.T) { Config: Config{ EnableStack: true, }, - currentStack: []*big.Int{ + currentStack: [][]*big.Int{{ big.NewInt(1), big.NewInt(2), - }, + }}, }, contractAddress: contractAddress, ip: ip,