From 4ac0a4bd2c68911831182dc033e69aaee702a154 Mon Sep 17 00:00:00 2001 From: Marko Atanasievski Date: Mon, 3 Jul 2023 11:59:38 +0200 Subject: [PATCH] fix: storage access --- jsonrpc/eth_endpoint.go | 10 +- prover/prover.go | 12 +- state/runtime/tracer/structtracer/tracer.go | 51 +++++---- .../tracer/structtracer/tracer_test.go | 106 +++++++++++------- 4 files changed, 102 insertions(+), 77 deletions(-) diff --git a/jsonrpc/eth_endpoint.go b/jsonrpc/eth_endpoint.go index 530c4c7de9..cac6fdbf9d 100644 --- a/jsonrpc/eth_endpoint.go +++ b/jsonrpc/eth_endpoint.go @@ -734,6 +734,7 @@ func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) { // Get the previous block header var previousBlockNumber = BlockNumber(header.Number) - 1 + previousHeader, err := GetHeaderFromBlockNumberOrHash(BlockNumberOrHash{BlockNumber: &previousBlockNumber}, e.store) if err != nil { return nil, err @@ -799,7 +800,7 @@ func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) { // Lear of the storage changes in this block storages := make([]prover.Storage, 0) - storageChanges, err := prover.ParseTraceForStorageChanges(tracesJSON) + storageChanges, err := prover.ParseTraceForStorageAccess(tracesJSON) if err != nil { return nil, err } @@ -808,7 +809,7 @@ func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) { // that will be changed in this block execution for account, accountData := range accounts { if accountData.CodeHash != EmptyCodeHash { - storageUpdates := make([]prover.StorageUpdate, 0) + storageAccesses := make([]prover.StorageAccess, 0) // Account is smart contract (has code) for _, storageChange := range storageChanges[account] { @@ -823,7 +824,7 @@ func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) { ss[i] = hex.EncodeToHex(s) } - storageUpdates = append(storageUpdates, prover.StorageUpdate{ + storageAccesses = append(storageAccesses, prover.StorageAccess{ Slot: storageChange.Slot.String(), MerkleProof: ss, }) @@ -832,7 +833,7 @@ func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) { storages = append(storages, prover.Storage{ Account: account, StorageRoot: accountData.Root, - Storage: storageUpdates, + Storage: storageAccesses, }) } } @@ -869,6 +870,7 @@ func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) { // Manually add zero account (beneficiary account) zeroAccount := "0x0000000000000000000000000000000000000000" + zeroAccountData, err := e.store.GetAccount(previousHeader.StateRoot, types.StringToAddress(zeroAccount)) if err != nil { accounts[zeroAccount] = &prover.ProverAccount{ diff --git a/prover/prover.go b/prover/prover.go index 78cf83f885..517f595dcd 100644 --- a/prover/prover.go +++ b/prover/prover.go @@ -9,7 +9,7 @@ import ( "github.com/0xPolygon/polygon-edge/types" ) -type StorageUpdate struct { +type StorageAccess struct { Slot string MerkleProof []string } @@ -17,7 +17,7 @@ type StorageUpdate struct { type Storage struct { Account string StorageRoot string - Storage []StorageUpdate + Storage []StorageAccess } type ProverAccount struct { @@ -78,8 +78,8 @@ func ParseContractCodeForAccounts(tracesJSON []interface{}) ([]string, error) { return result, nil } -func ParseTraceForStorageChanges(tracesJSON []interface{}) (map[string][]structtracer.StorageUpdate, error) { - var storageChanges = make(map[string][]structtracer.StorageUpdate) +func ParseTraceForStorageAccess(tracesJSON []interface{}) (map[string][]structtracer.StorageAccess, error) { + var storageChanges = make(map[string][]structtracer.StorageAccess) for _, traceJSON := range tracesJSON { trace, ok := traceJSON.(*structtracer.StructTraceResult) @@ -88,7 +88,9 @@ func ParseTraceForStorageChanges(tracesJSON []interface{}) (map[string][]structt } for account, storage := range trace.StorageUpdates { - storageChanges[account.String()] = append(storageChanges[account.String()], storage...) + for storageAccess := range storage { + storageChanges[account.String()] = append(storageChanges[account.String()], storageAccess) + } } } diff --git a/state/runtime/tracer/structtracer/tracer.go b/state/runtime/tracer/structtracer/tracer.go index 0ed9f68b90..6b7e41208a 100644 --- a/state/runtime/tracer/structtracer/tracer.go +++ b/state/runtime/tracer/structtracer/tracer.go @@ -43,9 +43,8 @@ func (l *StructLog) ErrorString() string { return "" } -type StorageUpdate struct { - Slot types.Hash `json:"slot"` - Value types.Hash `json:"value"` +type StorageAccess struct { + Slot types.Hash `json:"slot"` } type StructTracer struct { @@ -65,13 +64,15 @@ type StructTracer struct { storage []map[types.Address]map[types.Hash]types.Hash currentMemory []([]byte) currentStack []([]*big.Int) - storageUpdates [][]StorageUpdate - accountStorageUpdates map[types.Address][]StorageUpdate + storageAccess []map[StorageAccess]bool + accountStorageUpdates map[types.Address]map[StorageAccess]bool } 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) + storageAccess := make([]map[StorageAccess]bool, 1) + storageAccess[0] = make(map[StorageAccess]bool) return &StructTracer{ Config: config, @@ -79,8 +80,8 @@ func NewStructTracer(config Config) *StructTracer { storage: storage, currentMemory: make([]([]byte), 1), currentStack: make([]([]*big.Int), 1), - storageUpdates: make([][]StorageUpdate, 1), - accountStorageUpdates: make(map[types.Address][]StorageUpdate), + storageAccess: storageAccess, + accountStorageUpdates: make(map[types.Address]map[StorageAccess]bool), } } @@ -224,7 +225,7 @@ func (t *StructTracer) captureStorage( ) { if opCode == evm.CALL || opCode == evm.STATICCALL { t.storage = append(t.storage, make(map[types.Address]map[types.Hash]types.Hash)) - t.storageUpdates = append(t.storageUpdates, make([]StorageUpdate, 0)) + t.storageAccess = append(t.storageAccess, make(map[StorageAccess]bool)) } if !t.Config.EnableStorage || (opCode != evm.SLOAD && opCode != evm.SSTORE) { @@ -247,6 +248,10 @@ func (t *StructTracer) captureStorage( slot := types.BytesToHash(stack[sp-1].Bytes()) value := host.GetStorage(contractAddress, slot) + t.storageAccess[len(t.storageAccess)-1][StorageAccess{ + Slot: slot, + }] = true + (*storage)[contractAddress][slot] = value case evm.SSTORE: @@ -263,10 +268,9 @@ func (t *StructTracer) captureStorage( (*storage)[contractAddress][slot] = value - t.storageUpdates[len(t.storageUpdates)-1] = append(t.storageUpdates[len(t.storageUpdates)-1], StorageUpdate{ - Slot: slot, - Value: value, - }) + t.storageAccess[len(t.storageAccess)-1][StorageAccess{ + Slot: slot, + }] = true } } @@ -320,15 +324,10 @@ func (t *StructTracer) ExecuteState( if opCode == evm.OpCode(evm.CALL).String() || opCode == evm.OpCode(evm.STATICCALL).String() { contract := types.BytesToAddress(stack[len(stack)-2].Bytes()) - if t.accountStorageUpdates[contract] != nil { - t.accountStorageUpdates[contract] = append(t.accountStorageUpdates[contract], - t.storageUpdates[len(t.storageUpdates)-1]...) - } else { - t.accountStorageUpdates[contract] = t.storageUpdates[len(t.storageUpdates)-1] - } + t.accountStorageUpdates[contract] = t.storageAccess[len(t.storageAccess)-1] t.storage = t.storage[:len(t.storage)-1] - t.storageUpdates = t.storageUpdates[:len(t.storageUpdates)-1] + t.storageAccess = t.storageAccess[:len(t.storageAccess)-1] } contractStorage, ok := t.storage[len(t.storage)-1][contractAddress] @@ -364,12 +363,12 @@ func (t *StructTracer) ExecuteState( } type StructTraceResult struct { - Account string `json:"account"` - Failed bool `json:"failed"` - StorageUpdates map[types.Address][]StorageUpdate `json:"storageUpdates"` - Gas uint64 `json:"gas"` - ReturnValue string `json:"returnValue"` - StructLogs []StructLogRes `json:"structLogs"` + Account string `json:"account"` + Failed bool `json:"failed"` + StorageUpdates map[types.Address]map[StorageAccess]bool `json:"storageUpdates"` + Gas uint64 `json:"gas"` + ReturnValue string `json:"returnValue"` + StructLogs []StructLogRes `json:"structLogs"` } type StructLogRes struct { @@ -398,7 +397,7 @@ func (t *StructTracer) GetResult() (interface{}, error) { returnValue = fmt.Sprintf("%x", t.output) } - t.accountStorageUpdates[t.contractAddress] = t.storageUpdates[len(t.storageUpdates)-1] + t.accountStorageUpdates[t.contractAddress] = t.storageAccess[len(t.storageAccess)-1] storageUpdates := t.accountStorageUpdates return &StructTraceResult{ diff --git a/state/runtime/tracer/structtracer/tracer_test.go b/state/runtime/tracer/structtracer/tracer_test.go index 5c1f82fb38..2c31053f9d 100644 --- a/state/runtime/tracer/structtracer/tracer_test.go +++ b/state/runtime/tracer/structtracer/tracer_test.go @@ -191,11 +191,13 @@ func TestStructTracerTxStart(t *testing.T) { 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), - storageUpdates: make([][]StorageUpdate, 1), - accountStorageUpdates: make(map[types.Address][]StorageUpdate), + gasLimit: gasLimit, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), + storageAccess: []map[StorageAccess]bool{ + make(map[StorageAccess]bool), + }, + accountStorageUpdates: make(map[types.Address]map[StorageAccess]bool), }, tracer, ) @@ -221,12 +223,14 @@ func TestStructTracerTxEnd(t *testing.T) { 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), - storageUpdates: make([][]StorageUpdate, 1), - accountStorageUpdates: make(map[types.Address][]StorageUpdate), + gasLimit: gasLimit, + consumedGas: gasLimit - gasLeft, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), + storageAccess: []map[StorageAccess]bool{ + make(map[StorageAccess]bool), + }, + accountStorageUpdates: make(map[types.Address]map[StorageAccess]bool), }, tracer, ) @@ -280,12 +284,14 @@ func TestStructTracerCallEnd(t *testing.T) { 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), - storageUpdates: make([][]StorageUpdate, 1), - accountStorageUpdates: make(map[types.Address][]StorageUpdate), + output: output, + err: err, + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), + storageAccess: []map[StorageAccess]bool{ + make(map[StorageAccess]bool), + }, + accountStorageUpdates: make(map[types.Address]map[StorageAccess]bool), }, }, { @@ -298,10 +304,12 @@ func TestStructTracerCallEnd(t *testing.T) { 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), - storageUpdates: make([][]StorageUpdate, 1), - accountStorageUpdates: make(map[types.Address][]StorageUpdate), + currentMemory: make([]([]byte), 1), + currentStack: make([]([]*big.Int), 1), + storageAccess: []map[StorageAccess]bool{ + make(map[StorageAccess]bool), + }, + accountStorageUpdates: make(map[types.Address]map[StorageAccess]bool), }, }, } @@ -416,6 +424,9 @@ func TestStructTracerCaptureState(t *testing.T) { storage: []map[types.Address]map[types.Hash]types.Hash{ make(map[types.Address]map[types.Hash]types.Hash), }, + storageAccess: []map[StorageAccess]bool{ + make(map[StorageAccess]bool), + }, }, memory: memory, stack: stack, @@ -444,6 +455,11 @@ func TestStructTracerCaptureState(t *testing.T) { }, }, }, + storageAccess: []map[StorageAccess]bool{ + { + {types.BytesToHash(big.NewInt(2).Bytes())}: true, + }, + }, }, expectedVMState: &mockState{}, }, @@ -456,8 +472,10 @@ func TestStructTracerCaptureState(t *testing.T) { storage: []map[types.Address]map[types.Hash]types.Hash{ make(map[types.Address]map[types.Hash]types.Hash), }, - storageUpdates: make([][]StorageUpdate, 1), - accountStorageUpdates: make(map[types.Address][]StorageUpdate), + storageAccess: []map[StorageAccess]bool{ + make(map[StorageAccess]bool), + }, + accountStorageUpdates: make(map[types.Address]map[StorageAccess]bool), }, memory: memory, stack: stack, @@ -479,12 +497,12 @@ func TestStructTracerCaptureState(t *testing.T) { }, }, }, - storageUpdates: [][]StorageUpdate{ + storageAccess: []map[StorageAccess]bool{ { - StorageUpdate{types.BytesToHash(big.NewInt(2).Bytes()), types.BytesToHash(big.NewInt(1).Bytes())}, + {types.BytesToHash(big.NewInt(2).Bytes())}: true, }, }, - accountStorageUpdates: make(map[types.Address][]StorageUpdate), + accountStorageUpdates: make(map[types.Address]map[StorageAccess]bool), }, expectedVMState: &mockState{}, }, @@ -932,20 +950,22 @@ func TestStructTracerGetResult(t *testing.T) { { name: "should return result", tracer: &StructTracer{ - Config: testEmptyConfig, - logs: logs, - consumedGas: consumedGas, - output: returnData, - storageUpdates: make([][]StorageUpdate, 1), - accountStorageUpdates: make(map[types.Address][]StorageUpdate), + Config: testEmptyConfig, + logs: logs, + consumedGas: consumedGas, + output: returnData, + storageAccess: []map[StorageAccess]bool{ + make(map[StorageAccess]bool), + }, + accountStorageUpdates: make(map[types.Address]map[StorageAccess]bool), }, expected: &StructTraceResult{ Account: "0x0000000000000000000000000000000000000000", Failed: false, Gas: consumedGas, ReturnValue: hex.EncodeToString(returnData), - StorageUpdates: map[types.Address][]StorageUpdate{ - {}: nil, + StorageUpdates: map[types.Address]map[StorageAccess]bool{ + {}: make(map[StorageAccess]bool), }, StructLogs: []StructLogRes{ { @@ -985,15 +1005,15 @@ func TestStructTracerGetResult(t *testing.T) { consumedGas: consumedGas, output: returnData, err: err, - storageUpdates: make([][]StorageUpdate, 1), - accountStorageUpdates: make(map[types.Address][]StorageUpdate), + storageAccess: make([]map[StorageAccess]bool, 1), + accountStorageUpdates: make(map[types.Address]map[StorageAccess]bool), }, expected: &StructTraceResult{ Failed: true, Gas: consumedGas, ReturnValue: "", Account: "0x0000000000000000000000000000000000000000", - StorageUpdates: map[types.Address][]StorageUpdate{ + StorageUpdates: map[types.Address]map[StorageAccess]bool{ {}: nil, }, StructLogs: []StructLogRes{ @@ -1029,11 +1049,13 @@ func TestStructTracerGetResult(t *testing.T) { { name: "should return error", tracer: &StructTracer{ - Config: testEmptyConfig, - reason: reason, - logs: logs, - storageUpdates: make([][]StorageUpdate, 1), - accountStorageUpdates: make(map[types.Address][]StorageUpdate), + Config: testEmptyConfig, + reason: reason, + logs: logs, + storageAccess: []map[StorageAccess]bool{ + make(map[StorageAccess]bool), + }, + accountStorageUpdates: make(map[types.Address]map[StorageAccess]bool), }, expected: nil, err: reason,