mirror of https://github.com/ethereum/go-ethereum
eth/catalyst: add catalyst API prototype (#22641)
This change adds the --catalyst flag, enabling an RPC API for eth2 integration. In this initial version, catalyst mode also disables all peer-to-peer networking. Co-authored-by: Mikhail Kalinin <noblesse.knight@gmail.com> Co-authored-by: Felix Lange <fjl@twurst.com>pull/22697/head
parent
4f3ba6742f
commit
f79cce5de9
@ -0,0 +1,302 @@ |
||||
// Copyright 2020 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Package catalyst implements the temporary eth1/eth2 RPC integration.
|
||||
package catalyst |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"math/big" |
||||
"time" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/core" |
||||
"github.com/ethereum/go-ethereum/core/state" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/eth" |
||||
"github.com/ethereum/go-ethereum/log" |
||||
"github.com/ethereum/go-ethereum/node" |
||||
chainParams "github.com/ethereum/go-ethereum/params" |
||||
"github.com/ethereum/go-ethereum/rpc" |
||||
"github.com/ethereum/go-ethereum/trie" |
||||
) |
||||
|
||||
// Register adds catalyst APIs to the node.
|
||||
func Register(stack *node.Node, backend *eth.Ethereum) error { |
||||
chainconfig := backend.BlockChain().Config() |
||||
if chainconfig.CatalystBlock == nil { |
||||
return errors.New("catalystBlock is not set in genesis config") |
||||
} else if chainconfig.CatalystBlock.Sign() != 0 { |
||||
return errors.New("catalystBlock of genesis config must be zero") |
||||
} |
||||
|
||||
log.Warn("Catalyst mode enabled") |
||||
stack.RegisterAPIs([]rpc.API{ |
||||
{ |
||||
Namespace: "consensus", |
||||
Version: "1.0", |
||||
Service: newConsensusAPI(backend), |
||||
Public: true, |
||||
}, |
||||
}) |
||||
return nil |
||||
} |
||||
|
||||
type consensusAPI struct { |
||||
eth *eth.Ethereum |
||||
} |
||||
|
||||
func newConsensusAPI(eth *eth.Ethereum) *consensusAPI { |
||||
return &consensusAPI{eth: eth} |
||||
} |
||||
|
||||
// blockExecutionEnv gathers all the data required to execute
|
||||
// a block, either when assembling it or when inserting it.
|
||||
type blockExecutionEnv struct { |
||||
chain *core.BlockChain |
||||
state *state.StateDB |
||||
tcount int |
||||
gasPool *core.GasPool |
||||
|
||||
header *types.Header |
||||
txs []*types.Transaction |
||||
receipts []*types.Receipt |
||||
} |
||||
|
||||
func (env *blockExecutionEnv) commitTransaction(tx *types.Transaction, coinbase common.Address) error { |
||||
vmconfig := *env.chain.GetVMConfig() |
||||
receipt, err := core.ApplyTransaction(env.chain.Config(), env.chain, &coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, vmconfig) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
env.txs = append(env.txs, tx) |
||||
env.receipts = append(env.receipts, receipt) |
||||
return nil |
||||
} |
||||
|
||||
func (api *consensusAPI) makeEnv(parent *types.Block, header *types.Header) (*blockExecutionEnv, error) { |
||||
state, err := api.eth.BlockChain().StateAt(parent.Root()) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
env := &blockExecutionEnv{ |
||||
chain: api.eth.BlockChain(), |
||||
state: state, |
||||
header: header, |
||||
gasPool: new(core.GasPool).AddGas(header.GasLimit), |
||||
} |
||||
return env, nil |
||||
} |
||||
|
||||
// AssembleBlock creates a new block, inserts it into the chain, and returns the "execution
|
||||
// data" required for eth2 clients to process the new block.
|
||||
func (api *consensusAPI) AssembleBlock(params assembleBlockParams) (*executableData, error) { |
||||
log.Info("Producing block", "parentHash", params.ParentHash) |
||||
|
||||
bc := api.eth.BlockChain() |
||||
parent := bc.GetBlockByHash(params.ParentHash) |
||||
pool := api.eth.TxPool() |
||||
|
||||
if parent.Time() >= params.Timestamp { |
||||
return nil, fmt.Errorf("child timestamp lower than parent's: %d >= %d", parent.Time(), params.Timestamp) |
||||
} |
||||
if now := uint64(time.Now().Unix()); params.Timestamp > now+1 { |
||||
wait := time.Duration(params.Timestamp-now) * time.Second |
||||
log.Info("Producing block too far in the future", "wait", common.PrettyDuration(wait)) |
||||
time.Sleep(wait) |
||||
} |
||||
|
||||
pending, err := pool.Pending() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
coinbase, err := api.eth.Etherbase() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
num := parent.Number() |
||||
header := &types.Header{ |
||||
ParentHash: parent.Hash(), |
||||
Number: num.Add(num, common.Big1), |
||||
Coinbase: coinbase, |
||||
GasLimit: parent.GasLimit(), // Keep the gas limit constant in this prototype
|
||||
Extra: []byte{}, |
||||
Time: params.Timestamp, |
||||
} |
||||
err = api.eth.Engine().Prepare(bc, header) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
env, err := api.makeEnv(parent, header) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
var ( |
||||
signer = types.MakeSigner(bc.Config(), header.Number) |
||||
txHeap = types.NewTransactionsByPriceAndNonce(signer, pending) |
||||
transactions []*types.Transaction |
||||
) |
||||
for { |
||||
if env.gasPool.Gas() < chainParams.TxGas { |
||||
log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", chainParams.TxGas) |
||||
break |
||||
} |
||||
tx := txHeap.Peek() |
||||
if tx == nil { |
||||
break |
||||
} |
||||
|
||||
// The sender is only for logging purposes, and it doesn't really matter if it's correct.
|
||||
from, _ := types.Sender(signer, tx) |
||||
|
||||
// Execute the transaction
|
||||
env.state.Prepare(tx.Hash(), common.Hash{}, env.tcount) |
||||
err = env.commitTransaction(tx, coinbase) |
||||
switch err { |
||||
case core.ErrGasLimitReached: |
||||
// Pop the current out-of-gas transaction without shifting in the next from the account
|
||||
log.Trace("Gas limit exceeded for current block", "sender", from) |
||||
txHeap.Pop() |
||||
|
||||
case core.ErrNonceTooLow: |
||||
// New head notification data race between the transaction pool and miner, shift
|
||||
log.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Nonce()) |
||||
txHeap.Shift() |
||||
|
||||
case core.ErrNonceTooHigh: |
||||
// Reorg notification data race between the transaction pool and miner, skip account =
|
||||
log.Trace("Skipping account with high nonce", "sender", from, "nonce", tx.Nonce()) |
||||
txHeap.Pop() |
||||
|
||||
case nil: |
||||
// Everything ok, collect the logs and shift in the next transaction from the same account
|
||||
env.tcount++ |
||||
txHeap.Shift() |
||||
transactions = append(transactions, tx) |
||||
|
||||
default: |
||||
// Strange error, discard the transaction and get the next in line (note, the
|
||||
// nonce-too-high clause will prevent us from executing in vain).
|
||||
log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err) |
||||
txHeap.Shift() |
||||
} |
||||
} |
||||
|
||||
// Create the block.
|
||||
block, err := api.eth.Engine().FinalizeAndAssemble(bc, header, env.state, transactions, nil /* uncles */, env.receipts) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return &executableData{ |
||||
BlockHash: block.Hash(), |
||||
ParentHash: block.ParentHash(), |
||||
Miner: block.Coinbase(), |
||||
StateRoot: block.Root(), |
||||
Number: block.NumberU64(), |
||||
GasLimit: block.GasLimit(), |
||||
GasUsed: block.GasUsed(), |
||||
Timestamp: block.Time(), |
||||
ReceiptRoot: block.ReceiptHash(), |
||||
LogsBloom: block.Bloom().Bytes(), |
||||
Transactions: encodeTransactions(block.Transactions()), |
||||
}, nil |
||||
} |
||||
|
||||
func encodeTransactions(txs []*types.Transaction) [][]byte { |
||||
var enc = make([][]byte, len(txs)) |
||||
for i, tx := range txs { |
||||
enc[i], _ = tx.MarshalBinary() |
||||
} |
||||
return enc |
||||
} |
||||
|
||||
func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) { |
||||
var txs = make([]*types.Transaction, len(enc)) |
||||
for i, encTx := range enc { |
||||
var tx types.Transaction |
||||
if err := tx.UnmarshalBinary(encTx); err != nil { |
||||
return nil, fmt.Errorf("invalid transaction %d: %v", i, err) |
||||
} |
||||
txs[i] = &tx |
||||
} |
||||
return txs, nil |
||||
} |
||||
|
||||
func insertBlockParamsToBlock(params executableData) (*types.Block, error) { |
||||
txs, err := decodeTransactions(params.Transactions) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
number := big.NewInt(0) |
||||
number.SetUint64(params.Number) |
||||
header := &types.Header{ |
||||
ParentHash: params.ParentHash, |
||||
UncleHash: types.EmptyUncleHash, |
||||
Coinbase: params.Miner, |
||||
Root: params.StateRoot, |
||||
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), |
||||
ReceiptHash: params.ReceiptRoot, |
||||
Bloom: types.BytesToBloom(params.LogsBloom), |
||||
Difficulty: big.NewInt(1), |
||||
Number: number, |
||||
GasLimit: params.GasLimit, |
||||
GasUsed: params.GasUsed, |
||||
Time: params.Timestamp, |
||||
} |
||||
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */) |
||||
return block, nil |
||||
} |
||||
|
||||
// NewBlock creates an Eth1 block, inserts it in the chain, and either returns true,
|
||||
// or false + an error. This is a bit redundant for go, but simplifies things on the
|
||||
// eth2 side.
|
||||
func (api *consensusAPI) NewBlock(params executableData) (*newBlockResponse, error) { |
||||
parent := api.eth.BlockChain().GetBlockByHash(params.ParentHash) |
||||
if parent == nil { |
||||
return &newBlockResponse{false}, fmt.Errorf("could not find parent %x", params.ParentHash) |
||||
} |
||||
block, err := insertBlockParamsToBlock(params) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
_, err = api.eth.BlockChain().InsertChainWithoutSealVerification(block) |
||||
return &newBlockResponse{err == nil}, err |
||||
} |
||||
|
||||
// Used in tests to add a the list of transactions from a block to the tx pool.
|
||||
func (api *consensusAPI) addBlockTxs(block *types.Block) error { |
||||
for _, tx := range block.Transactions() { |
||||
api.eth.TxPool().AddLocal(tx) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// FinalizeBlock is called to mark a block as synchronized, so
|
||||
// that data that is no longer needed can be removed.
|
||||
func (api *consensusAPI) FinalizeBlock(blockHash common.Hash) (*genericResponse, error) { |
||||
return &genericResponse{true}, nil |
||||
} |
||||
|
||||
// SetHead is called to perform a force choice.
|
||||
func (api *consensusAPI) SetHead(newHead common.Hash) (*genericResponse, error) { |
||||
return &genericResponse{true}, nil |
||||
} |
@ -0,0 +1,229 @@ |
||||
// Copyright 2020 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package catalyst |
||||
|
||||
import ( |
||||
"math/big" |
||||
"testing" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/consensus/ethash" |
||||
"github.com/ethereum/go-ethereum/core" |
||||
"github.com/ethereum/go-ethereum/core/rawdb" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/crypto" |
||||
"github.com/ethereum/go-ethereum/eth" |
||||
"github.com/ethereum/go-ethereum/eth/ethconfig" |
||||
"github.com/ethereum/go-ethereum/node" |
||||
"github.com/ethereum/go-ethereum/params" |
||||
) |
||||
|
||||
var ( |
||||
// testKey is a private key to use for funding a tester account.
|
||||
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") |
||||
|
||||
// testAddr is the Ethereum address of the tester account.
|
||||
testAddr = crypto.PubkeyToAddress(testKey.PublicKey) |
||||
|
||||
testBalance = big.NewInt(2e10) |
||||
) |
||||
|
||||
func generateTestChain() (*core.Genesis, []*types.Block) { |
||||
db := rawdb.NewMemoryDatabase() |
||||
config := params.AllEthashProtocolChanges |
||||
genesis := &core.Genesis{ |
||||
Config: config, |
||||
Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}}, |
||||
ExtraData: []byte("test genesis"), |
||||
Timestamp: 9000, |
||||
} |
||||
generate := func(i int, g *core.BlockGen) { |
||||
g.OffsetTime(5) |
||||
g.SetExtra([]byte("test")) |
||||
} |
||||
gblock := genesis.ToBlock(db) |
||||
engine := ethash.NewFaker() |
||||
blocks, _ := core.GenerateChain(config, gblock, engine, db, 10, generate) |
||||
blocks = append([]*types.Block{gblock}, blocks...) |
||||
return genesis, blocks |
||||
} |
||||
|
||||
func generateTestChainWithFork(n int, fork int) (*core.Genesis, []*types.Block, []*types.Block) { |
||||
if fork >= n { |
||||
fork = n - 1 |
||||
} |
||||
db := rawdb.NewMemoryDatabase() |
||||
//nolint:composites
|
||||
config := ¶ms.ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, big.NewInt(0), new(params.EthashConfig), nil} |
||||
genesis := &core.Genesis{ |
||||
Config: config, |
||||
Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}}, |
||||
ExtraData: []byte("test genesis"), |
||||
Timestamp: 9000, |
||||
} |
||||
generate := func(i int, g *core.BlockGen) { |
||||
g.OffsetTime(5) |
||||
g.SetExtra([]byte("test")) |
||||
} |
||||
generateFork := func(i int, g *core.BlockGen) { |
||||
g.OffsetTime(5) |
||||
g.SetExtra([]byte("testF")) |
||||
} |
||||
gblock := genesis.ToBlock(db) |
||||
engine := ethash.NewFaker() |
||||
blocks, _ := core.GenerateChain(config, gblock, engine, db, n, generate) |
||||
blocks = append([]*types.Block{gblock}, blocks...) |
||||
forkedBlocks, _ := core.GenerateChain(config, blocks[fork], engine, db, n-fork, generateFork) |
||||
return genesis, blocks, forkedBlocks |
||||
} |
||||
|
||||
func TestEth2AssembleBlock(t *testing.T) { |
||||
genesis, blocks := generateTestChain() |
||||
n, ethservice := startEthService(t, genesis, blocks[1:9]) |
||||
defer n.Close() |
||||
|
||||
api := newConsensusAPI(ethservice) |
||||
signer := types.NewEIP155Signer(ethservice.BlockChain().Config().ChainID) |
||||
tx, err := types.SignTx(types.NewTransaction(0, blocks[8].Coinbase(), big.NewInt(1000), params.TxGas, nil, nil), signer, testKey) |
||||
if err != nil { |
||||
t.Fatalf("error signing transaction, err=%v", err) |
||||
} |
||||
ethservice.TxPool().AddLocal(tx) |
||||
blockParams := assembleBlockParams{ |
||||
ParentHash: blocks[8].ParentHash(), |
||||
Timestamp: blocks[8].Time(), |
||||
} |
||||
execData, err := api.AssembleBlock(blockParams) |
||||
|
||||
if err != nil { |
||||
t.Fatalf("error producing block, err=%v", err) |
||||
} |
||||
|
||||
if len(execData.Transactions) != 1 { |
||||
t.Fatalf("invalid number of transactions %d != 1", len(execData.Transactions)) |
||||
} |
||||
} |
||||
|
||||
func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { |
||||
genesis, blocks := generateTestChain() |
||||
n, ethservice := startEthService(t, genesis, blocks[1:9]) |
||||
defer n.Close() |
||||
|
||||
api := newConsensusAPI(ethservice) |
||||
|
||||
// Put the 10th block's tx in the pool and produce a new block
|
||||
api.addBlockTxs(blocks[9]) |
||||
blockParams := assembleBlockParams{ |
||||
ParentHash: blocks[9].ParentHash(), |
||||
Timestamp: blocks[9].Time(), |
||||
} |
||||
execData, err := api.AssembleBlock(blockParams) |
||||
if err != nil { |
||||
t.Fatalf("error producing block, err=%v", err) |
||||
} |
||||
|
||||
if len(execData.Transactions) != blocks[9].Transactions().Len() { |
||||
t.Fatalf("invalid number of transactions %d != 1", len(execData.Transactions)) |
||||
} |
||||
} |
||||
|
||||
func TestEth2NewBlock(t *testing.T) { |
||||
genesis, blocks, forkedBlocks := generateTestChainWithFork(10, 4) |
||||
n, ethservice := startEthService(t, genesis, blocks[1:5]) |
||||
defer n.Close() |
||||
|
||||
api := newConsensusAPI(ethservice) |
||||
for i := 5; i < 10; i++ { |
||||
p := executableData{ |
||||
ParentHash: ethservice.BlockChain().CurrentBlock().Hash(), |
||||
Miner: blocks[i].Coinbase(), |
||||
StateRoot: blocks[i].Root(), |
||||
GasLimit: blocks[i].GasLimit(), |
||||
GasUsed: blocks[i].GasUsed(), |
||||
Transactions: encodeTransactions(blocks[i].Transactions()), |
||||
ReceiptRoot: blocks[i].ReceiptHash(), |
||||
LogsBloom: blocks[i].Bloom().Bytes(), |
||||
BlockHash: blocks[i].Hash(), |
||||
Timestamp: blocks[i].Time(), |
||||
Number: uint64(i), |
||||
} |
||||
success, err := api.NewBlock(p) |
||||
if err != nil || !success.Valid { |
||||
t.Fatalf("Failed to insert block: %v", err) |
||||
} |
||||
} |
||||
|
||||
exp := ethservice.BlockChain().CurrentBlock().Hash() |
||||
|
||||
// Introduce the fork point.
|
||||
lastBlockNum := blocks[4].Number() |
||||
lastBlock := blocks[4] |
||||
for i := 0; i < 4; i++ { |
||||
lastBlockNum.Add(lastBlockNum, big.NewInt(1)) |
||||
p := executableData{ |
||||
ParentHash: lastBlock.Hash(), |
||||
Miner: forkedBlocks[i].Coinbase(), |
||||
StateRoot: forkedBlocks[i].Root(), |
||||
Number: lastBlockNum.Uint64(), |
||||
GasLimit: forkedBlocks[i].GasLimit(), |
||||
GasUsed: forkedBlocks[i].GasUsed(), |
||||
Transactions: encodeTransactions(blocks[i].Transactions()), |
||||
ReceiptRoot: forkedBlocks[i].ReceiptHash(), |
||||
LogsBloom: forkedBlocks[i].Bloom().Bytes(), |
||||
BlockHash: forkedBlocks[i].Hash(), |
||||
Timestamp: forkedBlocks[i].Time(), |
||||
} |
||||
success, err := api.NewBlock(p) |
||||
if err != nil || !success.Valid { |
||||
t.Fatalf("Failed to insert forked block #%d: %v", i, err) |
||||
} |
||||
lastBlock, err = insertBlockParamsToBlock(p) |
||||
if err != nil { |
||||
t.Fatal(err) |
||||
} |
||||
} |
||||
|
||||
if ethservice.BlockChain().CurrentBlock().Hash() != exp { |
||||
t.Fatalf("Wrong head after inserting fork %x != %x", exp, ethservice.BlockChain().CurrentBlock().Hash()) |
||||
} |
||||
} |
||||
|
||||
// startEthService creates a full node instance for testing.
|
||||
func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) (*node.Node, *eth.Ethereum) { |
||||
t.Helper() |
||||
|
||||
n, err := node.New(&node.Config{}) |
||||
if err != nil { |
||||
t.Fatal("can't create node:", err) |
||||
} |
||||
|
||||
ethcfg := ðconfig.Config{Genesis: genesis, Ethash: ethash.Config{PowMode: ethash.ModeFake}} |
||||
ethservice, err := eth.New(n, ethcfg) |
||||
if err != nil { |
||||
t.Fatal("can't create eth service:", err) |
||||
} |
||||
if err := n.Start(); err != nil { |
||||
t.Fatal("can't start node:", err) |
||||
} |
||||
if _, err := ethservice.BlockChain().InsertChain(blocks); err != nil { |
||||
n.Close() |
||||
t.Fatal("can't import test blocks:", err) |
||||
} |
||||
ethservice.SetEtherbase(testAddr) |
||||
|
||||
return n, ethservice |
||||
} |
@ -0,0 +1,70 @@ |
||||
// Copyright 2020 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package catalyst |
||||
|
||||
import ( |
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/common/hexutil" |
||||
) |
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type assembleBlockParams -field-override assembleBlockParamsMarshaling -out gen_blockparams.go
|
||||
|
||||
// Structure described at https://hackmd.io/T9x2mMA4S7us8tJwEB3FDQ
|
||||
type assembleBlockParams struct { |
||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"` |
||||
Timestamp uint64 `json:"timestamp" gencodec:"required"` |
||||
} |
||||
|
||||
// JSON type overrides for assembleBlockParams.
|
||||
type assembleBlockParamsMarshaling struct { |
||||
Timestamp hexutil.Uint64 |
||||
} |
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type executableData -field-override executableDataMarshaling -out gen_ed.go
|
||||
|
||||
// Structure described at https://notes.ethereum.org/@n0ble/rayonism-the-merge-spec#Parameters1
|
||||
type executableData struct { |
||||
BlockHash common.Hash `json:"blockHash" gencodec:"required"` |
||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"` |
||||
Miner common.Address `json:"miner" gencodec:"required"` |
||||
StateRoot common.Hash `json:"stateRoot" gencodec:"required"` |
||||
Number uint64 `json:"number" gencodec:"required"` |
||||
GasLimit uint64 `json:"gasLimit" gencodec:"required"` |
||||
GasUsed uint64 `json:"gasUsed" gencodec:"required"` |
||||
Timestamp uint64 `json:"timestamp" gencodec:"required"` |
||||
ReceiptRoot common.Hash `json:"receiptsRoot" gencodec:"required"` |
||||
LogsBloom []byte `json:"logsBloom" gencodec:"required"` |
||||
Transactions [][]byte `json:"transactions" gencodec:"required"` |
||||
} |
||||
|
||||
// JSON type overrides for executableData.
|
||||
type executableDataMarshaling struct { |
||||
Number hexutil.Uint64 |
||||
GasLimit hexutil.Uint64 |
||||
GasUsed hexutil.Uint64 |
||||
Timestamp hexutil.Uint64 |
||||
LogsBloom hexutil.Bytes |
||||
Transactions []hexutil.Bytes |
||||
} |
||||
|
||||
type newBlockResponse struct { |
||||
Valid bool `json:"valid"` |
||||
} |
||||
|
||||
type genericResponse struct { |
||||
Success bool `json:"success"` |
||||
} |
@ -0,0 +1,46 @@ |
||||
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||
|
||||
package catalyst |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/common/hexutil" |
||||
) |
||||
|
||||
var _ = (*assembleBlockParamsMarshaling)(nil) |
||||
|
||||
// MarshalJSON marshals as JSON.
|
||||
func (a assembleBlockParams) MarshalJSON() ([]byte, error) { |
||||
type assembleBlockParams struct { |
||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"` |
||||
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"` |
||||
} |
||||
var enc assembleBlockParams |
||||
enc.ParentHash = a.ParentHash |
||||
enc.Timestamp = hexutil.Uint64(a.Timestamp) |
||||
return json.Marshal(&enc) |
||||
} |
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (a *assembleBlockParams) UnmarshalJSON(input []byte) error { |
||||
type assembleBlockParams struct { |
||||
ParentHash *common.Hash `json:"parentHash" gencodec:"required"` |
||||
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"` |
||||
} |
||||
var dec assembleBlockParams |
||||
if err := json.Unmarshal(input, &dec); err != nil { |
||||
return err |
||||
} |
||||
if dec.ParentHash == nil { |
||||
return errors.New("missing required field 'parentHash' for assembleBlockParams") |
||||
} |
||||
a.ParentHash = *dec.ParentHash |
||||
if dec.Timestamp == nil { |
||||
return errors.New("missing required field 'timestamp' for assembleBlockParams") |
||||
} |
||||
a.Timestamp = uint64(*dec.Timestamp) |
||||
return nil |
||||
} |
@ -0,0 +1,117 @@ |
||||
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||
|
||||
package catalyst |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/common/hexutil" |
||||
) |
||||
|
||||
var _ = (*executableDataMarshaling)(nil) |
||||
|
||||
// MarshalJSON marshals as JSON.
|
||||
func (e executableData) MarshalJSON() ([]byte, error) { |
||||
type executableData struct { |
||||
BlockHash common.Hash `json:"blockHash" gencodec:"required"` |
||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"` |
||||
Miner common.Address `json:"miner" gencodec:"required"` |
||||
StateRoot common.Hash `json:"stateRoot" gencodec:"required"` |
||||
Number hexutil.Uint64 `json:"number" gencodec:"required"` |
||||
GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` |
||||
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` |
||||
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"` |
||||
ReceiptRoot common.Hash `json:"receiptsRoot" gencodec:"required"` |
||||
LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"` |
||||
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` |
||||
} |
||||
var enc executableData |
||||
enc.BlockHash = e.BlockHash |
||||
enc.ParentHash = e.ParentHash |
||||
enc.Miner = e.Miner |
||||
enc.StateRoot = e.StateRoot |
||||
enc.Number = hexutil.Uint64(e.Number) |
||||
enc.GasLimit = hexutil.Uint64(e.GasLimit) |
||||
enc.GasUsed = hexutil.Uint64(e.GasUsed) |
||||
enc.Timestamp = hexutil.Uint64(e.Timestamp) |
||||
enc.ReceiptRoot = e.ReceiptRoot |
||||
enc.LogsBloom = e.LogsBloom |
||||
if e.Transactions != nil { |
||||
enc.Transactions = make([]hexutil.Bytes, len(e.Transactions)) |
||||
for k, v := range e.Transactions { |
||||
enc.Transactions[k] = v |
||||
} |
||||
} |
||||
return json.Marshal(&enc) |
||||
} |
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (e *executableData) UnmarshalJSON(input []byte) error { |
||||
type executableData struct { |
||||
BlockHash *common.Hash `json:"blockHash" gencodec:"required"` |
||||
ParentHash *common.Hash `json:"parentHash" gencodec:"required"` |
||||
Miner *common.Address `json:"miner" gencodec:"required"` |
||||
StateRoot *common.Hash `json:"stateRoot" gencodec:"required"` |
||||
Number *hexutil.Uint64 `json:"number" gencodec:"required"` |
||||
GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` |
||||
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` |
||||
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"` |
||||
ReceiptRoot *common.Hash `json:"receiptsRoot" gencodec:"required"` |
||||
LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"` |
||||
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` |
||||
} |
||||
var dec executableData |
||||
if err := json.Unmarshal(input, &dec); err != nil { |
||||
return err |
||||
} |
||||
if dec.BlockHash == nil { |
||||
return errors.New("missing required field 'blockHash' for executableData") |
||||
} |
||||
e.BlockHash = *dec.BlockHash |
||||
if dec.ParentHash == nil { |
||||
return errors.New("missing required field 'parentHash' for executableData") |
||||
} |
||||
e.ParentHash = *dec.ParentHash |
||||
if dec.Miner == nil { |
||||
return errors.New("missing required field 'miner' for executableData") |
||||
} |
||||
e.Miner = *dec.Miner |
||||
if dec.StateRoot == nil { |
||||
return errors.New("missing required field 'stateRoot' for executableData") |
||||
} |
||||
e.StateRoot = *dec.StateRoot |
||||
if dec.Number == nil { |
||||
return errors.New("missing required field 'number' for executableData") |
||||
} |
||||
e.Number = uint64(*dec.Number) |
||||
if dec.GasLimit == nil { |
||||
return errors.New("missing required field 'gasLimit' for executableData") |
||||
} |
||||
e.GasLimit = uint64(*dec.GasLimit) |
||||
if dec.GasUsed == nil { |
||||
return errors.New("missing required field 'gasUsed' for executableData") |
||||
} |
||||
e.GasUsed = uint64(*dec.GasUsed) |
||||
if dec.Timestamp == nil { |
||||
return errors.New("missing required field 'timestamp' for executableData") |
||||
} |
||||
e.Timestamp = uint64(*dec.Timestamp) |
||||
if dec.ReceiptRoot == nil { |
||||
return errors.New("missing required field 'receiptsRoot' for executableData") |
||||
} |
||||
e.ReceiptRoot = *dec.ReceiptRoot |
||||
if dec.LogsBloom == nil { |
||||
return errors.New("missing required field 'logsBloom' for executableData") |
||||
} |
||||
e.LogsBloom = *dec.LogsBloom |
||||
if dec.Transactions == nil { |
||||
return errors.New("missing required field 'transactions' for executableData") |
||||
} |
||||
e.Transactions = make([][]byte, len(dec.Transactions)) |
||||
for k, v := range dec.Transactions { |
||||
e.Transactions[k] = v |
||||
} |
||||
return nil |
||||
} |
Loading…
Reference in new issue