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

Align RPC with geth #1841

Merged
merged 8 commits into from
Mar 20, 2024
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
60 changes: 47 additions & 13 deletions go/common/gethencoding/geth_encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"github.com/ten-protocol/go-ten/go/enclave/crypto"

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ten-protocol/go-ten/go/common/errutil"
"github.com/ten-protocol/go-ten/go/common/gethapi"

gethcommon "github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -145,33 +144,68 @@ func ExtractAddress(param interface{}) (*gethcommon.Address, error) {
}

// ExtractOptionalBlockNumber defaults nil or empty block number params to latest block number
func ExtractOptionalBlockNumber(params []interface{}, idx int) (*gethrpc.BlockNumber, error) {
func ExtractOptionalBlockNumber(params []interface{}, idx int) (*gethrpc.BlockNumberOrHash, error) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the geth api can send either a block number or a hash.
We currently only support the former, but this change creates the plumbing for both

latest := gethrpc.BlockNumberOrHashWithNumber(gethrpc.LatestBlockNumber)
if len(params) <= idx {
return ExtractBlockNumber("latest")
return &latest, nil
}
if params[idx] == nil {
return ExtractBlockNumber("latest")
return &latest, nil
}
if emptyStr, ok := params[idx].(string); ok && len(strings.TrimSpace(emptyStr)) == 0 {
return ExtractBlockNumber("latest")
return &latest, nil
}

return ExtractBlockNumber(params[idx])
}

// ExtractBlockNumber returns a gethrpc.BlockNumber given an interface{}, errors if unexpected values are used
func ExtractBlockNumber(param interface{}) (*gethrpc.BlockNumber, error) {
func ExtractBlockNumber(param interface{}) (*gethrpc.BlockNumberOrHash, error) {
if param == nil {
return nil, errutil.ErrNotFound
latest := gethrpc.BlockNumberOrHashWithNumber(gethrpc.LatestBlockNumber)
return &latest, nil
}

blockNumber := gethrpc.BlockNumber(0)
err := blockNumber.UnmarshalJSON([]byte(param.(string)))
if err != nil {
return nil, fmt.Errorf("could not parse requested rollup number %s - %w", param.(string), err)
// when the param is a single string we try to convert it to a block number
blockString, ok := param.(string)
if ok {
blockNumber := gethrpc.BlockNumber(0)
err := blockNumber.UnmarshalJSON([]byte(blockString))
if err != nil {
return nil, fmt.Errorf("invalid block number %s - %w", blockString, err)
}
return &gethrpc.BlockNumberOrHash{BlockNumber: &blockNumber}, nil
}

var blockNo *gethrpc.BlockNumber
var blockHa *gethcommon.Hash
var reqCanon bool

blockAndHash, ok := param.(map[string]any)
if !ok {
return nil, fmt.Errorf("invalid block or hash parameter %s", param.(string))
}
if blockAndHash["blockNumber"] != nil {
b := blockAndHash["blockNumber"].(string)
blockNumber := gethrpc.BlockNumber(0)
err := blockNumber.UnmarshalJSON([]byte(b))
if err != nil {
return nil, fmt.Errorf("invalid block number %s - %w", b, err)
}
blockNo = &blockNumber
}
if blockAndHash["blockHash"] != nil {
bh := blockAndHash["blockHash"].(gethcommon.Hash)
blockHa = &bh
}
if blockAndHash["RequireCanonical"] != nil {
reqCanon = blockAndHash["RequireCanonical"].(bool)
}

return &blockNumber, err
return &gethrpc.BlockNumberOrHash{
BlockNumber: blockNo,
BlockHash: blockHa,
RequireCanonical: reqCanon,
}, nil
}

// ExtractEthCall extracts the eth_call gethapi.TransactionArgs from an interface{}
Expand Down
1 change: 1 addition & 0 deletions go/enclave/l2chain/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type ObscuroChain interface {
// For EOA - the actual address.
// For Contracts - the address of the deployer.
// Note - this might be subject to change if we implement a more flexible mechanism
// todo - support BlockNumberOrHash
AccountOwner(address gethcommon.Address, blockNumber *gethrpc.BlockNumber) (*gethcommon.Address, error)

// GetBalanceAtBlock - will return the balance of a specific address at the specific given block number (batch number).
Expand Down
7 changes: 2 additions & 5 deletions go/enclave/l2chain/l1_blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,8 @@ import (
)

const (
gethDir = "geth"
chainDataDir = "chaindata"
chainDataAncientDir = "chaindata/ancient"
trieCacheDir = "triecache"
ethashDir = "ethash"
gethDir = "geth"
chainDataDir = "chaindata"
// todo (#1471) - use a constant that makes sense outside of the simulation.
dataDirRoot = "../.build/simulations/gethDataDir"
)
Expand Down
3 changes: 2 additions & 1 deletion go/enclave/rpc/EstimateGas.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ func EstimateGasValidate(reqParams []any, builder *CallBuilder[CallParamsWithBlo
}

builder.From = callMsg.From
builder.Param = &CallParamsWithBlock{callMsg, blockNumber}
// todo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: What needs to be done here or can be this todo removed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to support retrieval by hash. Currently it only works by height

builder.Param = &CallParamsWithBlock{callMsg, blockNumber.BlockNumber}
return nil
}

Expand Down
6 changes: 3 additions & 3 deletions go/enclave/rpc/GetBalance.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

type BalanceReq struct {
Addr *common.Address
Block *rpc.BlockNumber
Block *rpc.BlockNumberOrHash
}

func GetBalanceValidate(reqParams []any, builder *CallBuilder[BalanceReq, hexutil.Big], _ *EncryptionManager) error {
Expand Down Expand Up @@ -41,7 +41,7 @@ func GetBalanceValidate(reqParams []any, builder *CallBuilder[BalanceReq, hexuti
}

func GetBalanceExecute(builder *CallBuilder[BalanceReq, hexutil.Big], rpc *EncryptionManager) error {
acctOwner, err := rpc.chain.AccountOwner(*builder.Param.Addr, builder.Param.Block)
acctOwner, err := rpc.chain.AccountOwner(*builder.Param.Addr, builder.Param.Block.BlockNumber)
if err != nil {
return err
}
Expand All @@ -53,7 +53,7 @@ func GetBalanceExecute(builder *CallBuilder[BalanceReq, hexutil.Big], rpc *Encry
return nil
}

balance, err := rpc.chain.GetBalanceAtBlock(*builder.Param.Addr, builder.Param.Block)
balance, err := rpc.chain.GetBalanceAtBlock(*builder.Param.Addr, builder.Param.Block.BlockNumber)
if err != nil {
return fmt.Errorf("unable to get balance - %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion go/enclave/rpc/GetTransaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func GetTransactionExecute(builder *CallBuilder[gethcommon.Hash, RpcTransaction]
// Unlike in the Geth impl, we hardcode the use of a London signer.
// todo (#1553) - once the enclave's genesis.json is set, retrieve the signer type using `types.MakeSigner`
signer := types.NewLondonSigner(tx.ChainId())
rpcTx := newRPCTransaction(tx, blockHash, blockNumber, index, gethcommon.Big0, signer)
rpcTx := newRPCTransaction(tx, blockHash, blockNumber, index, rpc.config.BaseFee, signer)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity.. do we want to have it configurable? Before it was hardcoded to 0?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently we have a static configured base fee.
Eventually, it needs to be dynamic.
The problem here was that this was returning 0

builder.ReturnValue = rpcTx
return nil
}
Expand Down
3 changes: 2 additions & 1 deletion go/enclave/rpc/GetTransactionCount.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ func GetTransactionCountValidate(reqParams []any, builder *CallBuilder[uint64, s
return nil
}

b, err := rpc.registry.GetBatchAtHeight(*tag)
// todo - support BlockNumberOrHash
b, err := rpc.registry.GetBatchAtHeight(*tag.BlockNumber)
if err != nil {
builder.Err = fmt.Errorf("cant retrieve batch for tag. Cause: %w", err)
return nil
Expand Down
57 changes: 53 additions & 4 deletions go/enclave/rpc/GetTransactionReceipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package rpc
import (
"errors"
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ten-protocol/go-ten/go/enclave/evm/ethchainadapter"

"github.com/ten-protocol/go-ten/go/enclave/core"

Expand All @@ -13,7 +17,7 @@ import (
"github.com/ten-protocol/go-ten/go/enclave/events"
)

func GetTransactionReceiptValidate(reqParams []any, builder *CallBuilder[gethcommon.Hash, types.Receipt], _ *EncryptionManager) error {
func GetTransactionReceiptValidate(reqParams []any, builder *CallBuilder[gethcommon.Hash, map[string]interface{}], _ *EncryptionManager) error {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the geth api actually returns a map when you ask for receipts.

// Parameters are [Hash]
if len(reqParams) < 1 {
builder.Err = fmt.Errorf("unexpected number of parameters")
Expand All @@ -30,12 +34,12 @@ func GetTransactionReceiptValidate(reqParams []any, builder *CallBuilder[gethcom
return nil
}

func GetTransactionReceiptExecute(builder *CallBuilder[gethcommon.Hash, types.Receipt], rpc *EncryptionManager) error {
func GetTransactionReceiptExecute(builder *CallBuilder[gethcommon.Hash, map[string]interface{}], rpc *EncryptionManager) error {
txHash := *builder.Param
// todo - optimise these calls. This can be done with a single sql
rpc.logger.Trace("Get receipt for ", log.TxKey, txHash)
// We retrieve the transaction.
tx, _, _, _, err := rpc.storage.GetTransaction(txHash) //nolint:dogsled
tx, blockHash, number, txIndex, err := rpc.storage.GetTransaction(txHash) //nolint:dogsled
if err != nil {
rpc.logger.Trace("error getting tx ", log.TxKey, txHash, log.ErrKey, err)
if errors.Is(err, errutil.ErrNotFound) {
Expand Down Expand Up @@ -78,6 +82,51 @@ func GetTransactionReceiptExecute(builder *CallBuilder[gethcommon.Hash, types.Re
}

rpc.logger.Trace("Successfully retrieved receipt for ", log.TxKey, txHash, "rec", txReceipt)
builder.ReturnValue = txReceipt
signer := types.MakeSigner(ethchainadapter.ChainParams(big.NewInt(rpc.config.ObscuroChainID)), big.NewInt(int64(number)), 0)
r := marshalReceipt(txReceipt, blockHash, number, signer, tx, int(txIndex))
builder.ReturnValue = &r
return nil
}

// marshalReceipt marshals a transaction receipt into a JSON object.
// taken from geth
func marshalReceipt(receipt *types.Receipt, blockHash gethcommon.Hash, blockNumber uint64, signer types.Signer, tx *types.Transaction, txIndex int) map[string]interface{} {
from, _ := types.Sender(signer, tx)

fields := map[string]interface{}{
"blockHash": blockHash,
"blockNumber": hexutil.Uint64(blockNumber),
"transactionHash": tx.Hash(),
"transactionIndex": hexutil.Uint64(txIndex),
"from": from,
"to": tx.To(),
"gasUsed": hexutil.Uint64(receipt.GasUsed),
"cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed),
"contractAddress": nil,
"logs": receipt.Logs,
"logsBloom": receipt.Bloom,
"type": hexutil.Uint(tx.Type()),
"effectiveGasPrice": (*hexutil.Big)(receipt.EffectiveGasPrice),
}

// Assign receipt status or post state.
if len(receipt.PostState) > 0 {
fields["root"] = hexutil.Bytes(receipt.PostState)
} else {
fields["status"] = hexutil.Uint(receipt.Status)
}
if receipt.Logs == nil {
fields["logs"] = []*types.Log{}
}

if tx.Type() == types.BlobTxType {
fields["blobGasUsed"] = hexutil.Uint64(receipt.BlobGasUsed)
fields["blobGasPrice"] = (*hexutil.Big)(receipt.BlobGasPrice)
}

// If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation
if receipt.ContractAddress != (gethcommon.Address{}) {
fields["contractAddress"] = receipt.ContractAddress
}
return fields
}
11 changes: 7 additions & 4 deletions go/enclave/rpc/TenEthCall.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import (
)

func TenCallValidate(reqParams []any, builder *CallBuilder[CallParamsWithBlock, string], _ *EncryptionManager) error {
// Parameters are [TransactionArgs, BlockNumber]
if len(reqParams) != 2 {
// Parameters are [TransactionArgs, BlockNumber, 2 more which we don't support yet]
if len(reqParams) < 2 && len(reqParams) > 4 {
builder.Err = fmt.Errorf("unexpected number of parameters")
return nil
}
Expand All @@ -36,7 +36,8 @@ func TenCallValidate(reqParams []any, builder *CallBuilder[CallParamsWithBlock,
}

builder.From = apiArgs.From
builder.Param = &CallParamsWithBlock{apiArgs, blkNumber}
// todo - support BlockNumberOrHash
builder.Param = &CallParamsWithBlock{apiArgs, blkNumber.BlockNumber}

return nil
}
Expand Down Expand Up @@ -71,8 +72,10 @@ func TenCallExecute(builder *CallBuilder[CallParamsWithBlock, string], rpc *Encr
var encodedResult string
if len(execResult.ReturnData) != 0 {
encodedResult = hexutil.Encode(execResult.ReturnData)
builder.ReturnValue = &encodedResult
} else {
builder.ReturnValue = nil
}
builder.ReturnValue = &encodedResult
return nil
}

Expand Down
3 changes: 2 additions & 1 deletion go/enclave/storage/enclavedb/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,8 @@ func ReadReceipt(db *sql.DB, hash common.L2TxHash, config *params.ChainConfig) (

batchhash := common.L2BatchHash{}
batchhash.SetBytes(batchHash)
if err = receipts.DeriveFields(config, batchhash, height, 0, big.NewInt(0), big.NewInt(0), transactions); err != nil {
// todo base fee
if err = receipts.DeriveFields(config, batchhash, height, 0, big.NewInt(1), big.NewInt(0), transactions); err != nil {
return nil, fmt.Errorf("failed to derive block receipts fields. hash = %s; number = %d; err = %w", hash, height, err)
}
return receipts[0], nil
Expand Down
Loading
Loading