diff --git a/.gitignore b/.gitignore index b117d3da3..72cd02150 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,4 @@ logs/ coverage.out coverage.txt tests/spec-tests/ +bin/ diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 36437c4f7..0d5f2c5ce 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -104,6 +104,7 @@ if one is set. Otherwise it prints the genesis from the datadir.`, utils.BlockReplicationTargetsFlag, utils.ReplicaEnableSpecimenFlag, utils.ReplicaEnableResultFlag, + utils.ReplicaEnableBlobFlag, }, utils.DatabaseFlags), Description: ` The import command imports blocks from an RLP-encoded form. The form can be one file diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 5e6b750d4..25eba5f49 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -149,6 +149,7 @@ var ( utils.BlockReplicationTargetsFlag, utils.ReplicaEnableResultFlag, utils.ReplicaEnableSpecimenFlag, + utils.ReplicaEnableBlobFlag, }, utils.NetworkFlags, utils.DatabaseFlags) rpcFlags = []cli.Flag{ diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 5b97664be..e1185feb9 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -694,6 +694,10 @@ var ( Name: "replica.result", Usage: "Enables export of fields that comprise a block-result", } + ReplicaEnableBlobFlag = &cli.BoolFlag{ + Name: "replica.blob", + Usage: "Enables export of fields that comprise a block-blob", + } BatchRequestLimit = &cli.IntFlag{ Name: "rpc.batch-request-limit", Usage: "Maximum number of requests in a batch", @@ -2188,8 +2192,11 @@ func setBlockReplicationTargets(ctx *cli.Context, cfg *eth.Config) { if ctx.Bool(ReplicaEnableResultFlag.Name) { cfg.ReplicaEnableResult = true } + if ctx.Bool(ReplicaEnableBlobFlag.Name) { + cfg.ReplicaEnableBlob = true + } } else { - Fatalf("--replication.targets flag is invalid without --replica.specimen and/or --replica.result") + Fatalf("--replication.targets flag is invalid without --replica.specimen and/or --replica.result, ONLY ADD --replica.blob with both replica.specimen AND replica.result flags for complete unified state capture)") } } diff --git a/core/block_replica.go b/core/block_replica.go index dbabccd15..9160faf1a 100644 --- a/core/block_replica.go +++ b/core/block_replica.go @@ -21,8 +21,23 @@ type BlockReplicationEvent struct { } func (bc *BlockChain) createBlockReplica(block *types.Block, replicaConfig *ReplicaConfig, chainConfig *params.ChainConfig, stateSpecimen *types.StateSpecimen) error { - //block replica - exportBlockReplica, err := bc.createReplica(block, replicaConfig, chainConfig, stateSpecimen) + + // blobs + var blobTxSidecars []*types.BlobTxSidecar + if replicaConfig.EnableBlob { + for sidecarData := range types.BlobTxSidecarChan { + if sidecarData.BlockNumber.Uint64() == block.NumberU64() { + log.Info("Consuming BlobTxSidecar Match From Chain Sync Channel", "Block Number:", sidecarData.BlockNumber.Uint64()) + blobTxSidecars = append(blobTxSidecars, sidecarData.Blobs) + } else { + log.Info("Failing BlobTxSidecar Match from Chain Sync Channel", "Block Number:", sidecarData.BlockNumber.Uint64()) + } + log.Info("BlobTxSidecar Header", "Block Number:", sidecarData.BlockNumber.Uint64()) + log.Info("Chain Sync Sidecar Channel", "Length:", len(types.BlobTxSidecarChan)) + } + } + //block replica with blobs + exportBlockReplica, err := bc.createReplica(block, replicaConfig, chainConfig, stateSpecimen, blobTxSidecars) if err != nil { return err } @@ -50,7 +65,7 @@ func (bc *BlockChain) createBlockReplica(block *types.Block, replicaConfig *Repl } } -func (bc *BlockChain) createReplica(block *types.Block, replicaConfig *ReplicaConfig, chainConfig *params.ChainConfig, stateSpecimen *types.StateSpecimen) (*types.ExportBlockReplica, error) { +func (bc *BlockChain) createReplica(block *types.Block, replicaConfig *ReplicaConfig, chainConfig *params.ChainConfig, stateSpecimen *types.StateSpecimen, blobSpecimen []*types.BlobTxSidecar) (*types.ExportBlockReplica, error) { bHash := block.Hash() bNum := block.NumberU64() @@ -117,55 +132,58 @@ func (bc *BlockChain) createReplica(block *types.Block, replicaConfig *ReplicaCo uncles := block.Uncles() //block replica export - if replicaConfig.EnableSpecimen && replicaConfig.EnableResult { + if replicaConfig.EnableSpecimen && replicaConfig.EnableResult && replicaConfig.EnableBlob { exportBlockReplica := &types.ExportBlockReplica{ - Type: "block-replica", - NetworkId: chainConfig.ChainID.Uint64(), - Hash: bHash, - TotalDiff: td, - Header: header, - Transactions: txsRlp, - Uncles: uncles, - Receipts: receiptsRlp, - Senders: senders, - State: stateSpecimen, - Withdrawals: withdrawalsRlp, + Type: "block-replica", + NetworkId: chainConfig.ChainID.Uint64(), + Hash: bHash, + TotalDiff: td, + Header: header, + Transactions: txsRlp, + Uncles: uncles, + Receipts: receiptsRlp, + Senders: senders, + State: stateSpecimen, + Withdrawals: withdrawalsRlp, + BlobTxSidecars: blobSpecimen, } - log.Debug("Exporting full block-replica") + log.Debug("Exporting full block-replica with blob-specimen") return exportBlockReplica, nil } else if replicaConfig.EnableSpecimen && !replicaConfig.EnableResult { exportBlockReplica := &types.ExportBlockReplica{ - Type: "block-specimen", - NetworkId: chainConfig.ChainID.Uint64(), - Hash: bHash, - TotalDiff: td, - Header: header, - Transactions: txsRlp, - Uncles: uncles, - Receipts: []*types.ReceiptExportRLP{}, - Senders: senders, - State: stateSpecimen, - Withdrawals: withdrawalsRlp, + Type: "block-specimen", + NetworkId: chainConfig.ChainID.Uint64(), + Hash: bHash, + TotalDiff: td, + Header: header, + Transactions: txsRlp, + Uncles: uncles, + Receipts: []*types.ReceiptExportRLP{}, + Senders: senders, + State: stateSpecimen, + Withdrawals: withdrawalsRlp, + BlobTxSidecars: []*types.BlobTxSidecar{}, } - log.Debug("Exporting block-specimen only") + log.Debug("Exporting block-specimen only (no blob specimens)") return exportBlockReplica, nil } else if !replicaConfig.EnableSpecimen && replicaConfig.EnableResult { exportBlockReplica := &types.ExportBlockReplica{ - Type: "block-result", - NetworkId: chainConfig.ChainID.Uint64(), - Hash: bHash, - TotalDiff: td, - Header: header, - Transactions: txsRlp, - Uncles: uncles, - Receipts: receiptsRlp, - Senders: senders, - State: &types.StateSpecimen{}, + Type: "block-result", + NetworkId: chainConfig.ChainID.Uint64(), + Hash: bHash, + TotalDiff: td, + Header: header, + Transactions: txsRlp, + Uncles: uncles, + Receipts: receiptsRlp, + Senders: senders, + State: &types.StateSpecimen{}, + BlobTxSidecars: []*types.BlobTxSidecar{}, } - log.Debug("Exporting block-result only") + log.Debug("Exporting block-result only (no blob specimens)") return exportBlockReplica, nil } else { - return nil, fmt.Errorf("--replication.targets flag is invalid without --replica.specimen and/or --replica.result") + return nil, fmt.Errorf("--replication.targets flag is invalid without --replica.specimen and/or --replica.result, ADD --replica.blob with both replica.specimen AND replica.result flags for complete unified state capture aka block-replica)") } } @@ -181,5 +199,8 @@ func (bc *BlockChain) SetBlockReplicaExports(replicaConfig *ReplicaConfig) bool if replicaConfig.EnableSpecimen { bc.ReplicaConfig.EnableSpecimen = true } + if replicaConfig.EnableBlob { + bc.ReplicaConfig.EnableBlob = true + } return true } diff --git a/core/blockchain.go b/core/blockchain.go index 84e51bac3..3436ef9d7 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -267,6 +267,7 @@ type BlockChain struct { type ReplicaConfig struct { EnableSpecimen bool EnableResult bool + EnableBlob bool HistoricalBlocksSynced *uint32 } @@ -315,6 +316,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis ReplicaConfig: &ReplicaConfig{ EnableSpecimen: false, EnableResult: false, + EnableBlob: false, HistoricalBlocksSynced: new(uint32), // Always set 0 for historical mode at start }, } @@ -1851,7 +1853,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) if !setHead { // Export Block Specimen - bc.createBlockReplica(block, bc.ReplicaConfig, bc.chainConfig, statedb.TakeStateSpecimen()) + if bc.ReplicaConfig.EnableSpecimen || bc.ReplicaConfig.EnableResult { + bc.createBlockReplica(block, bc.ReplicaConfig, bc.chainConfig, statedb.TakeStateSpecimen()) + } // After merge we expect few side chains. Simply count // all blocks the CL gives us for GC processing time bc.gcproc += proctime @@ -1865,7 +1869,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) "elapsed", common.PrettyDuration(time.Since(start)), "root", block.Root()) // Handle creation of block specimen for canonical blocks - bc.createBlockReplica(block, bc.ReplicaConfig, bc.chainConfig, statedb.TakeStateSpecimen()) + if bc.ReplicaConfig.EnableSpecimen || bc.ReplicaConfig.EnableResult { + bc.createBlockReplica(block, bc.ReplicaConfig, bc.chainConfig, statedb.TakeStateSpecimen()) + } lastCanon = block // Only count canonical blocks for GC processing time @@ -1887,7 +1893,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), "root", block.Root()) // Is impossible but keeping in line to be nice to our future selves we add this for now - bc.createBlockReplica(block, bc.ReplicaConfig, bc.chainConfig, statedb.TakeStateSpecimen()) + if bc.ReplicaConfig.EnableSpecimen || bc.ReplicaConfig.EnableResult { + bc.createBlockReplica(block, bc.ReplicaConfig, bc.chainConfig, statedb.TakeStateSpecimen()) + } } } diff --git a/core/types/block_export.go b/core/types/block_export.go index 8b9ba670a..06e90a9ca 100644 --- a/core/types/block_export.go +++ b/core/types/block_export.go @@ -8,17 +8,18 @@ import ( ) type ExportBlockReplica struct { - Type string - NetworkId uint64 - Hash common.Hash - TotalDiff *big.Int - Header *Header - Transactions []*TransactionExportRLP - Uncles []*Header - Receipts []*ReceiptExportRLP - Senders []common.Address - State *StateSpecimen - Withdrawals []*WithdrawalExportRLP + Type string + NetworkId uint64 + Hash common.Hash + TotalDiff *big.Int + Header *Header + Transactions []*TransactionExportRLP + Uncles []*Header + Receipts []*ReceiptExportRLP + Senders []common.Address + State *StateSpecimen + Withdrawals []*WithdrawalExportRLP + BlobTxSidecars []*BlobTxSidecar } type LogsExportRLP struct { @@ -71,8 +72,18 @@ type TransactionExportRLP struct { V *big.Int `json:"v" rlp:"nil"` R *big.Int `json:"r" rlp:"nil"` S *big.Int `json:"s" rlp:"nil"` + BlobFeeCap *big.Int `json:"blobFeeCap" rlp:"optional"` + BlobHashes []common.Hash `json:"blobHashes" rlp:"optional"` + BlobGas uint64 `json:"blobGas" rlp:"optional"` } +type BlobTxSidecarData struct { + Blobs *BlobTxSidecar + BlockNumber *big.Int +} + +var BlobTxSidecarChan = make(chan *BlobTxSidecarData, 100) + func (r *ReceiptForExport) ExportReceipt() *ReceiptExportRLP { enc := &ReceiptExportRLP{ PostStateOrStatus: (*Receipt)(r).statusEncoding(), @@ -105,21 +116,47 @@ func (tx *TransactionForExport) ExportTx(chainConfig *params.ChainConfig, blockN txData := tx.inner - return &TransactionExportRLP{ - AccountNonce: txData.nonce(), - Price: txData.effectiveGasPrice(&big.Int{}, baseFee), - GasLimit: txData.gas(), - Sender: &from, - Recipient: txData.to(), - Amount: txData.value(), - Payload: txData.data(), - Type: txData.txType(), - ChainId: txData.chainID(), - AccessList: txData.accessList(), - GasTipCap: txData.gasTipCap(), - GasFeeCap: txData.gasFeeCap(), - V: v, - R: r, - S: s, + if inner_tx.Type() == BlobTxType { + return &TransactionExportRLP{ + AccountNonce: txData.nonce(), + Price: txData.effectiveGasPrice(&big.Int{}, baseFee), + GasLimit: txData.gas(), + Sender: &from, + Recipient: txData.to(), + Amount: txData.value(), + Payload: txData.data(), + Type: txData.txType(), + ChainId: txData.chainID(), + AccessList: txData.accessList(), + GasTipCap: txData.gasTipCap(), + GasFeeCap: txData.gasFeeCap(), + V: v, + R: r, + S: s, + BlobFeeCap: inner_tx.BlobGasFeeCap(), + BlobHashes: inner_tx.BlobHashes(), + BlobGas: inner_tx.BlobGas(), + } + } else { + return &TransactionExportRLP{ + AccountNonce: txData.nonce(), + Price: txData.effectiveGasPrice(&big.Int{}, baseFee), + GasLimit: txData.gas(), + Sender: &from, + Recipient: txData.to(), + Amount: txData.value(), + Payload: txData.data(), + Type: txData.txType(), + ChainId: txData.chainID(), + AccessList: txData.accessList(), + GasTipCap: txData.gasTipCap(), + GasFeeCap: txData.gasFeeCap(), + V: v, + R: r, + S: s, + BlobFeeCap: &big.Int{}, + BlobHashes: make([]common.Hash, 0), + BlobGas: 0, + } } } diff --git a/eth/backend.go b/eth/backend.go index d858affbe..62419ffbd 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -177,6 +177,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { ReplicaConfig: &core.ReplicaConfig{ EnableSpecimen: config.ReplicaEnableSpecimen, EnableResult: config.ReplicaEnableResult, + EnableBlob: config.ReplicaEnableBlob, HistoricalBlocksSynced: new(uint32), // Always set 0 for historical mode at start }, } @@ -186,7 +187,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err != nil { return nil, err } - log.Info("Block replication started", "targets", targets, "network ID", config.NetworkId, "export block-specimen", eth.ReplicaConfig.EnableSpecimen, "export block-result", eth.ReplicaConfig.EnableResult) + log.Info("Block replication started", "targets", targets, "network ID", config.NetworkId, "export block-specimen", eth.ReplicaConfig.EnableSpecimen, "export block-result", eth.ReplicaConfig.EnableResult, "export blob-specimen", eth.ReplicaConfig.EnableBlob) eth.blockReplicators = append(eth.blockReplicators, replicator) } bcVersion := rawdb.ReadDatabaseVersion(chainDb) diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 456b4a8c8..c86a00f07 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -160,6 +160,7 @@ type Config struct { // Bools that make explicit types being exported ReplicaEnableResult bool ReplicaEnableSpecimen bool + ReplicaEnableBlob bool // OverrideCancun (TODO: remove after the fork) OverrideCancun *uint64 `toml:",omitempty"` diff --git a/miner/worker.go b/miner/worker.go index 9a3610623..95433153b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -80,6 +80,8 @@ var ( errBlockInterruptedByTimeout = errors.New("timeout while building block") ) +var enableBlobTxSidecar bool + // environment is the worker's current environment and holds all // information of the sealing block generation. type environment struct { @@ -113,8 +115,21 @@ func (env *environment) copy() *environment { cpy.txs = make([]*types.Transaction, len(env.txs)) copy(cpy.txs, env.txs) - cpy.sidecars = make([]*types.BlobTxSidecar, len(env.sidecars)) - copy(cpy.sidecars, env.sidecars) + if enableBlobTxSidecar { + cpy.sidecars = make([]*types.BlobTxSidecar, len(env.sidecars)) + copy(cpy.sidecars, env.sidecars) + types.BlobTxSidecarChan = make(chan *types.BlobTxSidecarData, 100) + go func() { + for sidecar := range env.sidecars { + types.BlobTxSidecarChan <- &types.BlobTxSidecarData{ + Blobs: env.sidecars[sidecar], + BlockNumber: env.header.Number, + } + } + log.Info("Closing Chain Sync BlobTxSidecar Channel For", "Block Number:", env.header.Number.Uint64(), "Length:", len(types.BlobTxSidecarChan)) + close(types.BlobTxSidecarChan) + }() + } return cpy } @@ -290,6 +305,10 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus } worker.newpayloadTimeout = newpayloadTimeout + if worker.chain.ReplicaConfig.EnableBlob { + enableBlobTxSidecar = true + } + worker.wg.Add(4) go worker.mainLoop() go worker.newWorkLoop(recommit) diff --git a/params/version.go b/params/version.go index 52e7ac5a5..f2dded576 100644 --- a/params/version.go +++ b/params/version.go @@ -29,7 +29,7 @@ const ( const ( BspVersionMajor = 1 // Major version component of the current release - BspVersionMinor = 6 // Minor version component of the current release + BspVersionMinor = 8 // Minor version component of the current release BspVersionPatch = 0 // Patch version component of the current release )