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

Commit

Permalink
feat: add get prover data api function (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
atanmarko committed Sep 7, 2023
1 parent 3531d37 commit 99814a7
Show file tree
Hide file tree
Showing 13 changed files with 803 additions and 31 deletions.
2 changes: 1 addition & 1 deletion command/server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type Config struct {
JSONRPCBlockRangeLimit uint64 `json:"json_rpc_block_range_limit" yaml:"json_rpc_block_range_limit"`
JSONLogFormat bool `json:"json_log_format" yaml:"json_log_format"`
CorsAllowedOrigins []string `json:"cors_allowed_origins" yaml:"cors_allowed_origins"`
ToposSequencerAddr string `json:"topos_sequencer_addr" yaml:"topos_sequencer_addr"`
ToposSequencerAddr string `json:"topos_sequencer_addr" yaml:"topos_sequencer_addr"`

Relayer bool `json:"relayer" yaml:"relayer"`
NumBlockConfirmations uint64 `json:"num_block_confirmations" yaml:"num_block_confirmations"`
Expand Down
10 changes: 5 additions & 5 deletions jsonrpc/debug_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func (d *Debug) TraceTransaction(
return nil, ErrTraceGenesisBlock
}

tracer, cancel, err := newTracer(config)
tracer, cancel, err := NewTracer(config)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -165,7 +165,7 @@ func (d *Debug) TraceCall(
tx.Gas = header.GasLimit
}

tracer, cancel, err := newTracer(config)
tracer, cancel, err := NewTracer(config)
defer cancel()

if err != nil {
Expand All @@ -183,7 +183,7 @@ func (d *Debug) traceBlock(
return nil, ErrTraceGenesisBlock
}

tracer, cancel, err := newTracer(config)
tracer, cancel, err := NewTracer(config)
defer cancel()

if err != nil {
Expand All @@ -193,8 +193,8 @@ func (d *Debug) traceBlock(
return d.store.TraceBlock(block, tracer)
}

// newTracer creates new tracer by config
func newTracer(config *TraceConfig) (
// NewTracer creates new tracer by config
func NewTracer(config *TraceConfig) (
tracer.Tracer,
context.CancelFunc,
error,
Expand Down
10 changes: 5 additions & 5 deletions jsonrpc/debug_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -694,13 +694,13 @@ func TestTraceCall(t *testing.T) {
}
}

func Test_newTracer(t *testing.T) {
func Test_NewTracer(t *testing.T) {
t.Parallel()

t.Run("should create tracer", func(t *testing.T) {
t.Parallel()

tracer, cancel, err := newTracer(&TraceConfig{
tracer, cancel, err := NewTracer(&TraceConfig{
EnableMemory: true,
EnableReturnData: true,
DisableStack: false,
Expand All @@ -718,7 +718,7 @@ func Test_newTracer(t *testing.T) {
t.Run("should return error if arg is nil", func(t *testing.T) {
t.Parallel()

tracer, cancel, err := newTracer(nil)
tracer, cancel, err := NewTracer(nil)

assert.Nil(t, tracer)
assert.Nil(t, cancel)
Expand All @@ -729,7 +729,7 @@ func Test_newTracer(t *testing.T) {
t.Parallel()

timeout := "0s"
tracer, cancel, err := newTracer(&TraceConfig{
tracer, cancel, err := NewTracer(&TraceConfig{
EnableMemory: true,
EnableReturnData: true,
DisableStack: false,
Expand All @@ -755,7 +755,7 @@ func Test_newTracer(t *testing.T) {
t.Parallel()

timeout := "5s"
tracer, cancel, err := newTracer(&TraceConfig{
tracer, cancel, err := NewTracer(&TraceConfig{
EnableMemory: true,
EnableReturnData: true,
DisableStack: false,
Expand Down
221 changes: 218 additions & 3 deletions jsonrpc/eth_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ import (
"github.com/hashicorp/go-hclog"

"github.com/0xPolygon/polygon-edge/chain"
"github.com/0xPolygon/polygon-edge/gasprice"
"github.com/0xPolygon/polygon-edge/crypto"
"github.com/0xPolygon/polygon-edge/helper/common"
"github.com/0xPolygon/polygon-edge/helper/hex"
"github.com/0xPolygon/polygon-edge/helper/progress"
"github.com/0xPolygon/polygon-edge/prover"
"github.com/0xPolygon/polygon-edge/state"
"github.com/0xPolygon/polygon-edge/state/runtime"
"github.com/0xPolygon/polygon-edge/state/runtime/tracer"
"github.com/0xPolygon/polygon-edge/types"
)

Expand All @@ -29,13 +32,17 @@ type ethTxPoolStore interface {
}

type Account struct {
Balance *big.Int
Nonce uint64
Balance *big.Int
Nonce uint64
Root types.Hash
CodeHash []byte
}

type ethStateStore interface {
GetAccount(root types.Hash, addr types.Address) (*Account, error)
GetAccountProof(root types.Hash, addr types.Address) ([][]byte, error)
GetStorage(root types.Hash, addr types.Address, slot types.Hash) ([]byte, error)
GetStorageProof(stateRoot types.Hash, addr types.Address, slot types.Hash) ([][]byte, error)
GetForksInTime(blockNumber uint64) chain.ForksInTime
GetCode(root types.Hash, addr types.Address) ([]byte, error)
}
Expand Down Expand Up @@ -74,13 +81,18 @@ type ethFilter interface {
FilterExtra(extra []byte) ([]byte, error)
}

type ethTracing interface {
TraceBlock(block *types.Block, tracer tracer.Tracer) ([]interface{}, error)
}

// ethStore provides access to the methods needed by eth endpoint
type ethStore interface {
ethTxPoolStore
ethStateStore
ethBlockchainStore
ethFilter
gasprice.GasStore
ethTracing
}

// Eth is the eth jsonrpc endpoint
Expand All @@ -94,6 +106,9 @@ type Eth struct {

var (
ErrInsufficientFunds = errors.New("insufficient funds for execution")
//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})
)

// ChainId returns the chain id of the client
Expand Down Expand Up @@ -839,3 +854,203 @@ func (e *Eth) FeeHistory(blockCount argUint64, newestBlock BlockNumber,

return result, nil
}

func (e *Eth) GetProverData(block BlockNumberOrHash) (interface{}, error) {
// Get block metadata
header, err := GetHeaderFromBlockNumberOrHash(block, e.store)
if err != nil {
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)
}

// Parse to/from accounts
accountsStr, err := prover.ParseBlockAccounts(fullBlock)
if err != nil {
return nil, err
}

// Configure the tracer
tracer, _, err := NewTracer(&TraceConfig{
EnableMemory: true,
EnableReturnData: true,
DisableStack: false,
DisableStorage: false,
})
if err != nil {
return nil, err
}

// Run tracer on the current block
tracesJSON, err := e.store.TraceBlock(fullBlock, tracer)
if err != nil {
return nil, err
}

// Parse contract accounts called from smart contract execution
contractAccounts, err := prover.ParseContractCodeForAccounts(tracesJSON)
if err != nil {
return nil, err
}

accountsStr = append(accountsStr, contractAccounts...)

accounts := make(map[string]*prover.ProverAccount)

// Get all the data for the accounts
for _, accountStr := range accountsStr {
accountAddress := types.StringToAddress(accountStr)

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

accounts[accountAddress.String()] = &prover.ProverAccount{
Nonce: acc.Nonce,
Balance: acc.Balance,
Root: acc.Root.String(),
CodeHash: hex.EncodeToHex(acc.CodeHash),
}
}

// Learn of the storage changes in this block
storages := make([]prover.Storage, 0)

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 {
storageAccesses := make([]prover.StorageAccess, 0)

// Account is smart contract (has code)
for _, storageChange := range storageChanges[account] {
storageMerkleProof, err := e.store.GetStorageProof(previousHeader.StateRoot,
types.StringToAddress(account), storageChange.Slot)
if err != nil {
return nil, err
}

ss := make([]string, len(storageMerkleProof))
for i, s := range storageMerkleProof {
ss[i] = hex.EncodeToHex(s)
}

storageAccesses = append(storageAccesses, prover.StorageAccess{
Slot: storageChange.Slot.String(),
MerkleProof: ss,
})
}

storages = append(storages, prover.Storage{
Account: account,
StorageRoot: accountData.Root,
Storage: storageAccesses,
})
}
}

// 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)
if err != nil {
return nil, err
}

// Contract code map CodeHash -> ContractCode
contractCodes := make(map[string]string)

for account, accountData := range accounts {
if accountData.CodeHash != EmptyCodeHash {
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(previousHeader.StateRoot, types.StringToAddress(account))
if err != nil {
return nil, err
}

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

state = append(state, prover.ProverAccountProof{
Account: account,
MerkleProof: aa,
})
}

// 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{
ChainID: chainID,
BlockHeader: *header,
PreviousBlockHeader: *previousHeader,
Accounts: accounts,
PreviousStorage: storages,
Transactions: transactions,
Receipts: receipts,
ContractCodes: contractCodes,
PreviousState: state,
}, nil
}
Loading

0 comments on commit 99814a7

Please sign in to comment.