Skip to content
This repository has been archived by the owner on Oct 31, 2024. It is now read-only.

Commit

Permalink
feat: update prover storage data (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
atanmarko authored Jul 6, 2023
1 parent 74441b2 commit 5e383e0
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 104 deletions.
89 changes: 66 additions & 23 deletions jsonrpc/eth_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ type Eth struct {

var (
ErrInsufficientFunds = errors.New("insufficient funds for execution")
EmptyCodeHash = hex.EncodeToHex([]byte{197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125,
//Empty code hash is 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
EmptyCodeHash = hex.EncodeToHex([]byte{197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125,
178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112})
)

Expand Down Expand Up @@ -732,6 +733,14 @@ func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) {
return nil, err
}

// 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
}

fullBlock, valid := e.store.GetBlockByHash(header.Hash, true)
if !valid {
return nil, fmt.Errorf("failed to get block by hash %s", header.Hash)
Expand All @@ -743,7 +752,7 @@ func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) {
return nil, err
}

// Trace the block
// Configure the tracer
tracer, _, err := NewTracer(&TraceConfig{
EnableMemory: true,
EnableReturnData: true,
Expand Down Expand Up @@ -774,8 +783,9 @@ func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) {
for _, accountStr := range accountsStr {
accountAddress := types.StringToAddress(accountStr)

// Get the full account nonce, balance, state root and code hash
acc, err := e.store.GetAccount(header.StateRoot, accountAddress)
// Get the full account nonce, balance, state root and code hash of the state before this
// block is executed
acc, err := e.store.GetAccount(previousHeader.StateRoot, accountAddress)
if err != nil {
return nil, err
}
Expand All @@ -788,21 +798,23 @@ func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) {
}
}

// Get storage data for all accounts from this block
// Learn 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
}

// Get the starting state storage merkle proof for each account and each slot
// 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 has code
// Account is smart contract (has code)
for _, storageChange := range storageChanges[account] {
storageMerkleProof, err := e.store.GetStorageProof(header.StateRoot,
storageMerkleProof, err := e.store.GetStorageProof(previousHeader.StateRoot,
types.StringToAddress(account), storageChange.Slot)
if err != nil {
return nil, err
Expand All @@ -813,8 +825,7 @@ func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) {
ss[i] = hex.EncodeToHex(s)
}

storageUpdates = append(storageUpdates, prover.StorageUpdate{
Value: storageChange.Value.String(),
storageAccesses = append(storageAccesses, prover.StorageAccess{
Slot: storageChange.Slot.String(),
MerkleProof: ss,
})
Expand All @@ -823,13 +834,17 @@ func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) {
storages = append(storages, prover.Storage{
Account: account,
StorageRoot: accountData.Root,
Storage: storageUpdates,
Storage: storageAccesses,
})
}
}

// All transactions in the block
transactions := fullBlock.Transactions
// All transactions in this block

transactions := make([]string, 0)
for _, transaction := range fullBlock.Transactions {
transactions = append(transactions, hex.EncodeToHex(transaction.MarshalRLP()))
}

// Receipts from this block
receipts, err := e.store.GetReceiptsByHash(header.Hash)
Expand All @@ -842,21 +857,24 @@ func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) {

for account, accountData := range accounts {
if accountData.CodeHash != EmptyCodeHash {
contractCode, err := e.store.GetCode(header.StateRoot, types.StringToAddress(account))
contractCode, err := e.store.GetCode(previousHeader.StateRoot, types.StringToAddress(account))
if err != nil {
return nil, err
}

codeHash := crypto.Keccak256(contractCode)
contractCodes[hex.EncodeToHex(codeHash)] = hex.EncodeToHex(contractCode)
} else {
// Add empty code hash
contractCodes[EmptyCodeHash] = "0x"
}
}

state := make([]prover.ProverAccountProof, 0)

// Get state Merkle proofs for all accounts
for account := range accounts {
accountProof, err := e.store.GetAccountProof(header.StateRoot, types.StringToAddress(account))
accountProof, err := e.store.GetAccountProof(previousHeader.StateRoot, types.StringToAddress(account))
if err != nil {
return nil, err
}
Expand All @@ -872,13 +890,38 @@ func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) {
})
}

// Add zero account (block beneficiary) to the state
zeroAccount := "0x0000000000000000000000000000000000000000"

zeroAccountProof, err := e.store.GetAccountProof(previousHeader.StateRoot, types.StringToAddress(zeroAccount))
if err != nil {
return nil, err
}

zeroAccountProofArray := make([]string, 0)
for _, proof := range zeroAccountProof {
zeroAccountProofArray = append(zeroAccountProofArray, hex.EncodeToHex(proof))
}

state = append(state, prover.ProverAccountProof{
Account: zeroAccount,
MerkleProof: zeroAccountProofArray,
})

chainID, err := e.ChainId()
if err != nil {
return nil, err
}

return &prover.ProverData{
BlockHeader: *header,
Accounts: accounts,
Storage: storages,
Transactions: transactions,
Receipts: receipts,
ContractCodes: contractCodes,
State: state,
ChainID: chainID,
BlockHeader: *header,
PreviousBlockHeader: *previousHeader,
Accounts: accounts,
PreviousStorage: storages,
Transactions: transactions,
Receipts: receipts,
ContractCodes: contractCodes,
PreviousState: state,
}, nil
}
29 changes: 16 additions & 13 deletions prover/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,15 @@ import (
"github.com/0xPolygon/polygon-edge/types"
)

type StorageUpdate struct {
type StorageAccess struct {
Slot string
Value string
MerkleProof []string
}

type Storage struct {
Account string
StorageRoot string
Storage []StorageUpdate
Storage []StorageAccess
}

type ProverAccount struct {
Expand All @@ -34,13 +33,15 @@ type ProverAccountProof struct {
}

type ProverData struct {
BlockHeader types.Header
Accounts interface{}
Storage interface{}
Transactions interface{}
Receipts interface{}
ContractCodes interface{}
State interface{}
ChainID interface{}
BlockHeader types.Header
PreviousBlockHeader types.Header
Accounts interface{}
PreviousStorage interface{}
Transactions interface{}
Receipts interface{}
ContractCodes interface{}
PreviousState interface{}
}

func ParseBlockAccounts(block *types.Block) ([]string, error) {
Expand Down Expand Up @@ -77,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)
Expand All @@ -87,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)
}
}
}

Expand Down
51 changes: 25 additions & 26 deletions state/runtime/tracer/structtracer/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -65,22 +64,24 @@ 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,
cancelLock: sync.RWMutex{},
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),
}
}

Expand Down Expand Up @@ -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) {
Expand All @@ -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:
Expand All @@ -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
}
}

Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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{
Expand Down
Loading

0 comments on commit 5e383e0

Please sign in to comment.