Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update prover storage data #23

Merged
merged 5 commits into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
atanmarko marked this conversation as resolved.
Show resolved Hide resolved
}, 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