diff --git a/cmd/hack/hack.go b/cmd/hack/hack.go index 28724af336c..20a7eaaf16c 100644 --- a/cmd/hack/hack.go +++ b/cmd/hack/hack.go @@ -3774,10 +3774,11 @@ func runBlock(ibs *state.IntraBlockState, txnWriter state.StateWriter, blockWrit if !vmConfig.ReadOnly { // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) - if _, err := engine.FinalizeAndAssemble(chainConfig, header, ibs, block.Transactions(), block.Uncles(), receipts, nil, nil, nil, nil); err != nil { + txs := block.Transactions() + if _, err := engine.FinalizeAndAssemble(chainConfig, header, ibs, &txs, block.Uncles(), &receipts, nil, nil, nil, nil); err != nil { return nil, fmt.Errorf("finalize of block %d failed: %w", block.NumberU64(), err) } - + block = types.NewBlock(block.Header(), txs, block.Uncles(), receipts) if err := ibs.CommitBlock(rules, blockWriter); err != nil { return nil, fmt.Errorf("committing block %d failed: %w", block.NumberU64(), err) } diff --git a/cmd/state/commands/opcode_tracer.go b/cmd/state/commands/opcode_tracer.go index 7dcde0234eb..af76aa84944 100644 --- a/cmd/state/commands/opcode_tracer.go +++ b/cmd/state/commands/opcode_tracer.go @@ -698,7 +698,8 @@ func runBlock(ibs *state.IntraBlockState, txnWriter state.StateWriter, blockWrit if !vmConfig.ReadOnly { // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) - if _, err := engine.FinalizeAndAssemble(chainConfig, header, ibs, block.Transactions(), block.Uncles(), receipts, nil, nil, nil, nil); err != nil { + tx := block.Transactions() + if _, err := engine.FinalizeAndAssemble(chainConfig, header, ibs, &tx, block.Uncles(), &receipts, nil, nil, nil, nil); err != nil { return nil, fmt.Errorf("finalize of block %d failed: %w", block.NumberU64(), err) } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ab0fef907e8..38ac1773316 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -32,11 +32,14 @@ import ( "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/txpool" - "github.com/ledgerwatch/erigon/eth/protocols/eth" "github.com/spf13/cobra" "github.com/spf13/pflag" "github.com/urfave/cli" + "github.com/ledgerwatch/erigon/eth/protocols/eth" + + "github.com/ledgerwatch/log/v3" + "github.com/ledgerwatch/erigon/common" "github.com/ledgerwatch/erigon/common/paths" "github.com/ledgerwatch/erigon/consensus/ethash" @@ -52,7 +55,6 @@ import ( "github.com/ledgerwatch/erigon/p2p/nat" "github.com/ledgerwatch/erigon/p2p/netutil" "github.com/ledgerwatch/erigon/params" - "github.com/ledgerwatch/log/v3" ) func init() { @@ -595,12 +597,14 @@ func setNodeUserIdentCobra(f *pflag.FlagSet, cfg *node.Config) { // setBootstrapNodes creates a list of bootstrap nodes from the command line // flags, reverting to pre-configured ones if none have been specified. func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { - urls := params.MainnetBootnodes + var urls []string if ctx.GlobalIsSet(BootnodesFlag.Name) { urls = SplitAndTrim(ctx.GlobalString(BootnodesFlag.Name)) } else { chain := ctx.GlobalString(ChainFlag.Name) switch chain { + case params.MainnetChainName: + urls = params.MainnetBootnodes case params.RopstenChainName: urls = params.RopstenBootnodes case params.RinkebyChainName: @@ -634,13 +638,14 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { // setBootstrapNodesV5 creates a list of bootstrap nodes from the command line // flags, reverting to pre-configured ones if none have been specified. func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) { - urls := params.MainnetBootnodes + var urls []string if ctx.GlobalIsSet(BootnodesFlag.Name) { urls = SplitAndTrim(ctx.GlobalString(BootnodesFlag.Name)) } else { - chain := ctx.GlobalString(ChainFlag.Name) switch chain { + case params.MainnetChainName: + urls = params.MainnetBootnodes case params.RopstenChainName: urls = params.RopstenBootnodes case params.RinkebyChainName: @@ -855,9 +860,15 @@ func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) { setSigKey(ctx, cfg) } - if ctx.GlobalString(ChainFlag.Name) == params.FermionChainName { + chainsWithValidatorMode := map[string]bool{ + params.FermionChainName: true, + params.BSCChainName: true, + params.RialtoChainName: true, + params.ChapelChainName: true, + } + if _, ok := chainsWithValidatorMode[ctx.GlobalString(ChainFlag.Name)]; ok { if ctx.GlobalIsSet(MiningEnabledFlag.Name) && !ctx.GlobalIsSet(MinerSigningKeyFileFlag.Name) { - panic(fmt.Sprintf("Flag --%s is required in %s chain with --%s flag", MinerSigningKeyFileFlag.Name, params.FermionChainName, MiningEnabledFlag.Name)) + panic(fmt.Sprintf("Flag --%s is required in %s chain with --%s flag", MinerSigningKeyFileFlag.Name, ChainFlag.Name, MiningEnabledFlag.Name)) } setSigKey(ctx, cfg) if cfg.Miner.SigKey != nil { @@ -902,13 +913,13 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config, nodeName, dataDir string) { cfg.NetRestrict = list } - if ctx.GlobalString(ChainFlag.Name) == params.DevChainName { - // --dev mode can't use p2p networking. - // cfg.MaxPeers = 0 // It can have peers otherwise local sync is not possible - cfg.ListenAddr = ":0" - cfg.NoDiscovery = true - cfg.DiscoveryV5 = false - } + //if ctx.GlobalString(ChainFlag.Name) == params.DevChainName { + // --dev mode can't use p2p networking. + // cfg.MaxPeers = 0 // It can have peers otherwise local sync is not possible + //cfg.ListenAddr = ":0" + //cfg.NoDiscovery = true + //cfg.DiscoveryV5 = false + //} } // SetNodeConfig applies node-related command line flags to the config. @@ -1369,8 +1380,11 @@ func SetEthConfig(ctx *cli.Context, nodeConfig *node.Config, cfg *ethconfig.Conf log.Info("Using developer account", "address", developer) // Create a new developer genesis block or reuse existing one - cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer) - log.Info("Using custom developer period", "seconds", cfg.Genesis.Config.Clique.Period) + cfg.Genesis = core.DefaultChapelGenesisBlock() + extraData := make([]byte, 32+20+65) + copy(extraData[32:], developer[:]) + cfg.Genesis.ExtraData = extraData + log.Info("Using custom developer period", "seconds", cfg.Genesis.Config.Parlia.Period) if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) { cfg.Miner.GasPrice = big.NewInt(1) } diff --git a/consensus/aura/aura.go b/consensus/aura/aura.go index 83238f94d4a..70c42b0db87 100644 --- a/consensus/aura/aura.go +++ b/consensus/aura/aura.go @@ -727,7 +727,7 @@ func (c *AuRa) VerifySeal(chain consensus.ChainHeaderReader, header *types.Heade // Prepare implements consensus.Engine, preparing all the consensus fields of the // header for running the transactions on top. -func (c *AuRa) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { +func (c *AuRa) Prepare(chain consensus.ChainHeaderReader, header *types.Header, state *state.IntraBlockState) error { return nil /// If the block isn't a checkpoint, cast a random vote (good enough for now) //header.Coinbase = common.Address{} @@ -833,7 +833,7 @@ func (c *AuRa) Initialize(config *params.ChainConfig, chain consensus.ChainHeade } //word `signal epoch` == word `pending epoch` -func (c *AuRa) Finalize(config *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs []types.Transaction, uncles []*types.Header, r types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall) error { +func (c *AuRa) Finalize(config *params.ChainConfig, header *types.Header, state *state.IntraBlockState, _ *types.Transactions, uncles []*types.Header, receipts *types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall) error { // accumulateRewards retrieves rewards for a block and applies them to the coinbase accounts for miner and uncle miners beneficiaries, _, rewards, err := AccumulateRewards(config, c, header, uncles, syscall) if err != nil { @@ -846,15 +846,15 @@ func (c *AuRa) Finalize(config *params.ChainConfig, header *types.Header, state // check_and_lock_block -> check_epoch_end_signal (after enact) if header.Number.Uint64() >= DEBUG_LOG_FROM { - fmt.Printf("finalize1: %d,%d\n", header.Number.Uint64(), len(r)) + fmt.Printf("finalize1: %d,%d\n", header.Number.Uint64(), len(*receipts)) } - pendingTransitionProof, err := c.cfg.Validators.signalEpochEnd(header.Number.Uint64() == 0, header, r) + pendingTransitionProof, err := c.cfg.Validators.signalEpochEnd(header.Number.Uint64() == 0, header, *receipts) if err != nil { return err } if pendingTransitionProof != nil { if header.Number.Uint64() >= DEBUG_LOG_FROM { - fmt.Printf("insert_pending_trancition: %d,receipts=%d, lenProof=%d\n", header.Number.Uint64(), len(r), len(pendingTransitionProof)) + fmt.Printf("insert_pending_trancition: %d,receipts=%d, lenProof=%d\n", header.Number.Uint64(), len(*receipts), len(pendingTransitionProof)) } if err = e.PutPendingEpoch(header.Hash(), header.Number.Uint64(), pendingTransitionProof); err != nil { return err @@ -976,12 +976,12 @@ func allHeadersUntil(chain consensus.ChainHeaderReader, from *types.Header, to c //} // FinalizeAndAssemble implements consensus.Engine -func (c *AuRa) FinalizeAndAssemble(chainConfig *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs []types.Transaction, uncles []*types.Header, r types.Receipts, +func (c *AuRa) FinalizeAndAssemble(chainConfig *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs *types.Transactions, uncles []*types.Header, receipts *types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall, call consensus.Call) (*types.Block, error) { - c.Finalize(chainConfig, header, state, txs, uncles, r, e, chain, syscall) + c.Finalize(chainConfig, header, state, txs, uncles, receipts, e, chain, syscall) // Assemble and return the final block for sealing - return types.NewBlock(header, txs, uncles, r), nil + return types.NewBlock(header, *txs, uncles, *receipts), nil } // Authorize injects a private key into the consensus engine to mint new blocks diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index e9ddd78d100..4fed515ba4a 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -297,7 +297,7 @@ func (c *Clique) VerifySeal(chain consensus.ChainHeaderReader, header *types.Hea // Prepare implements consensus.Engine, preparing all the consensus fields of the // header for running the transactions on top. -func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { +func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header, state *state.IntraBlockState) error { // If the block isn't a checkpoint, cast a random vote (good enough for now) header.Coinbase = common.Address{} @@ -369,7 +369,7 @@ func (c *Clique) Initialize(config *params.ChainConfig, chain consensus.ChainHea // Finalize implements consensus.Engine, ensuring no uncles are set, nor block // rewards given. -func (c *Clique) Finalize(config *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs []types.Transaction, uncles []*types.Header, r types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall) error { +func (c *Clique) Finalize(config *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs *types.Transactions, uncles []*types.Header, r *types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall) error { // No block rewards in PoA, so the state remains as is and uncles are dropped header.UncleHash = types.CalcUncleHash(nil) return nil @@ -377,13 +377,13 @@ func (c *Clique) Finalize(config *params.ChainConfig, header *types.Header, stat // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, // nor block rewards given, and returns the final block. -func (c *Clique) FinalizeAndAssemble(chainConfig *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs []types.Transaction, uncles []*types.Header, receipts types.Receipts, +func (c *Clique) FinalizeAndAssemble(chainConfig *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs *types.Transactions, uncles []*types.Header, receipts *types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall, call consensus.Call) (*types.Block, error) { // No block rewards in PoA, so the state remains as is and uncles are dropped header.UncleHash = types.CalcUncleHash(nil) // Assemble and return the final block for sealing - return types.NewBlock(header, txs, nil, receipts), nil + return types.NewBlock(header, *txs, nil, *receipts), nil } // Authorize injects a private key into the consensus engine to mint new blocks diff --git a/consensus/consensus.go b/consensus/consensus.go index 42a92934ddc..163a4d3d764 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -94,7 +94,7 @@ type Engine interface { // Prepare initializes the consensus fields of a block header according to the // rules of a particular engine. The changes are executed inline. - Prepare(chain ChainHeaderReader, header *types.Header) error + Prepare(chain ChainHeaderReader, header *types.Header, state *state.IntraBlockState) error // Initialize runs any pre-transaction state modifications (e.g. epoch start) Initialize(config *params.ChainConfig, chain ChainHeaderReader, e EpochReader, header *types.Header, txs []types.Transaction, uncles []*types.Header, syscall SystemCall) @@ -104,15 +104,15 @@ type Engine interface { // // Note: The block header and state database might be updated to reflect any // consensus rules that happen at finalization (e.g. block rewards). - Finalize(config *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs []types.Transaction, uncles []*types.Header, r types.Receipts, e EpochReader, chain ChainHeaderReader, syscall SystemCall) error + Finalize(config *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs *types.Transactions, uncles []*types.Header, receipts *types.Receipts, e EpochReader, chain ChainHeaderReader, syscall SystemCall) error // FinalizeAndAssemble runs any post-transaction state modifications (e.g. block // rewards) and assembles the final block. // // Note: The block header and state database might be updated to reflect any // consensus rules that happen at finalization (e.g. block rewards). - FinalizeAndAssemble(config *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs []types.Transaction, - uncles []*types.Header, receipts types.Receipts, e EpochReader, chain ChainHeaderReader, syscall SystemCall, call Call) (*types.Block, error) + FinalizeAndAssemble(config *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs *types.Transactions, + uncles []*types.Header, receipts *types.Receipts, e EpochReader, chain ChainHeaderReader, syscall SystemCall, call Call) (*types.Block, error) // Seal generates a new sealing request for the given input block and pushes // the result into the given channel. diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index fea876d5f3d..06a1d416c13 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -594,7 +594,7 @@ func (ethash *Ethash) verifySeal(header *types.Header, fulldag bool) error { //n // Prepare implements consensus.Engine, initializing the difficulty field of a // header to conform to the ethash protocol. The changes are done inline. -func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { +func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.Header, state *state.IntraBlockState) error { parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) if parent == nil { return consensus.ErrUnknownAncestor @@ -608,7 +608,7 @@ func (ethash *Ethash) Initialize(config *params.ChainConfig, chain consensus.Cha // Finalize implements consensus.Engine, accumulating the block and uncle rewards, // setting the final state on the header -func (ethash *Ethash) Finalize(config *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs []types.Transaction, uncles []*types.Header, r types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall) error { +func (ethash *Ethash) Finalize(config *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs *types.Transactions, uncles []*types.Header, r *types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall) error { // Accumulate any block and uncle rewards and commit the final state root accumulateRewards(config, state, header, uncles) return nil @@ -616,13 +616,13 @@ func (ethash *Ethash) Finalize(config *params.ChainConfig, header *types.Header, // FinalizeAndAssemble implements consensus.Engine, accumulating the block and // uncle rewards, setting the final state and assembling the block. -func (ethash *Ethash) FinalizeAndAssemble(chainConfig *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs []types.Transaction, uncles []*types.Header, r types.Receipts, +func (ethash *Ethash) FinalizeAndAssemble(chainConfig *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs *types.Transactions, uncles []*types.Header, r *types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall, call consensus.Call) (*types.Block, error) { // Finalize block - ethash.Finalize(chainConfig, header, state, txs, uncles, r, e, chain, syscall) + _ = ethash.Finalize(chainConfig, header, state, txs, uncles, r, e, chain, syscall) // Header seems complete, assemble into a block and return - return types.NewBlock(header, txs, uncles, r), nil + return types.NewBlock(header, *txs, uncles, *r), nil } // SealHash returns the hash of a block prior to it being sealed. diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 7b41b9d36d8..cd83f4acf68 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "math/big" + "os" "sort" "strings" "sync" @@ -30,7 +31,6 @@ import ( "github.com/ledgerwatch/erigon/core/state" "github.com/ledgerwatch/erigon/core/systemcontracts" "github.com/ledgerwatch/erigon/core/types" - "github.com/ledgerwatch/erigon/core/types/accounts" "github.com/ledgerwatch/erigon/core/vm" "github.com/ledgerwatch/erigon/crypto" "github.com/ledgerwatch/erigon/params" @@ -136,14 +136,11 @@ var ( // errRecentlySigned is returned if a header is signed by an authorized entity // that already signed a header recently, thus is temporarily not allowed to. errRecentlySigned = errors.New("recently signed") - - errNotSupported = errors.New("validator mode is not supported") ) -// SignerFn is a signer callback function to request a header to be signed by a +// SignFn is a signer callback function to request a header to be signed by a // backing account. -type SignerFn func(accounts.Account, string, []byte) ([]byte, error) -type SignerTxFn func(accounts.Account, *types.Transaction, *big.Int) (*types.Transaction, error) +type SignFn func(validator common.Address, payload []byte, chainId *big.Int) ([]byte, error) // ecrecover extracts the Ethereum account address from a signed header. func ecrecover(header *types.Header, sigCache *lru.ARCCache, chainId *big.Int) (common.Address, error) { @@ -202,14 +199,14 @@ func encodeSigHeader(w io.Writer, header *types.Header, chainId *big.Int) { } } -// ParliaRLP returns the rlp bytes which needs to be signed for the parlia +// parliaRLP returns the rlp bytes which needs to be signed for the parlia // sealing. The RLP to sign consists of the entire header apart from the 65 byte signature // contained at the end of the extra data. // // Note, the method requires the extra data to be at least 65 bytes, otherwise it // panics. This is done to avoid accidentally using both forms (signature present // or not), which could be abused to produce different hashes for the same header. -func ParliaRLP(header *types.Header, chainId *big.Int) []byte { +func parliaRLP(header *types.Header, chainId *big.Int) []byte { b := new(bytes.Buffer) encodeSigHeader(b, header, chainId) return b.Bytes() @@ -226,9 +223,8 @@ type Parlia struct { signer *types.Signer - val common.Address // Ethereum address of the signing key - signFn SignerFn // Signer function to authorize hashes with - signTxFn SignerTxFn + val common.Address // Ethereum address of the signing key + signFn SignFn // Signer function to authorize hashes with lock sync.RWMutex // Protects the signer fields @@ -582,15 +578,63 @@ func (p *Parlia) VerifyUncles(chain consensus.ChainReader, header *types.Header, // Prepare initializes the consensus fields of a block header according to the // rules of a particular engine. The changes are executed inline. -func (p *Parlia) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { - return errNotSupported +func (p *Parlia) Prepare(chain consensus.ChainHeaderReader, header *types.Header, ibs *state.IntraBlockState) error { + header.Coinbase = p.val + header.Nonce = types.BlockNonce{} + + number := header.Number.Uint64() + snap, err := p.snapshot(chain, number-1, header.ParentHash, nil) + if err != nil { + return err + } + + // Set the correct difficulty + header.Difficulty = CalcDifficulty(snap, p.val) + + // Ensure the extra data has all it's components + if len(header.Extra) < extraVanity-nextForkHashSize { + header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-nextForkHashSize-len(header.Extra))...) + } + header.Extra = header.Extra[:extraVanity-nextForkHashSize] + nextForkHash := forkid.NextForkHash(p.chainConfig, p.genesisHash, number) + header.Extra = append(header.Extra, nextForkHash[:]...) + + parent := chain.GetHeader(header.ParentHash, number-1) + if parent == nil { + return consensus.ErrUnknownAncestor + } + + if number%p.config.Epoch == 0 { + newValidators, err := p.getCurrentValidators(parent, ibs) + if err != nil { + return err + } + // sort validator by address + sort.Sort(validatorsAscending(newValidators)) + for _, validator := range newValidators { + header.Extra = append(header.Extra, validator.Bytes()...) + } + } + + // add extra seal space + header.Extra = append(header.Extra, make([]byte, extraSeal)...) + + // Mix digest is reserved for now, set to empty + header.MixDigest = common.Hash{} + + // Ensure the timestamp has the correct delay + header.Time = p.blockTimeForRamanujanFork(snap, header, parent) + if header.Time < uint64(time.Now().Unix()) { + header.Time = uint64(time.Now().Unix()) + } + return nil } // Initialize runs any pre-transaction state modifications (e.g. epoch start) func (p *Parlia) Initialize(config *params.ChainConfig, chain consensus.ChainHeaderReader, e consensus.EpochReader, header *types.Header, txs []types.Transaction, uncles []*types.Header, syscall consensus.SystemCall) { } -func (p *Parlia) splitTxs(txs []types.Transaction, header *types.Header) (userTxs []types.Transaction, systemTxs []types.Transaction, err error) { +func (p *Parlia) splitTxs(txs types.Transactions, header *types.Header) (userTxs types.Transactions, systemTxs types.Transactions, err error) { for _, tx := range txs { isSystemTx, err2 := p.IsSystemTransaction(tx, header) if err2 != nil { @@ -603,6 +647,12 @@ func (p *Parlia) splitTxs(txs []types.Transaction, header *types.Header) (userTx userTxs = append(userTxs, tx) } } + if userTxs == nil { + userTxs = types.Transactions{} + } + if systemTxs == nil { + systemTxs = types.Transactions{} + } return } @@ -611,15 +661,16 @@ func (p *Parlia) splitTxs(txs []types.Transaction, header *types.Header) (userTx // // Note: The block header and state database might be updated to reflect any // consensus rules that happen at finalization (e.g. block rewards). -func (p *Parlia) Finalize(_ *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs []types.Transaction, _ []*types.Header, receipts types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall) error { - return p.finalize(header, state, txs, &receipts, chain) +func (p *Parlia) Finalize(_ *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs *types.Transactions, _ []*types.Header, receipts *types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall) error { + return p.finalize(header, state, txs, receipts, chain, false) } -func (p *Parlia) finalize(header *types.Header, state *state.IntraBlockState, txs []types.Transaction, receipts *types.Receipts, chain consensus.ChainHeaderReader) error { - txs, systemTxs, err := p.splitTxs(txs, header) +func (p *Parlia) finalize(header *types.Header, state *state.IntraBlockState, txs *types.Transactions, receipts *types.Receipts, chain consensus.ChainHeaderReader, mining bool) error { + userTxs, systemTxs, err := p.splitTxs(*txs, header) if err != nil { return err } + *txs = userTxs // warn if not in majority fork number := header.Number.Uint64() snap, err := p.snapshot(chain, number-1, header.ParentHash, nil) @@ -652,9 +703,10 @@ func (p *Parlia) finalize(header *types.Header, state *state.IntraBlockState, tx } // No block rewards in PoA, so the state remains as is and uncles are dropped if header.Number.Cmp(common.Big1) == 0 { - err := p.initContract(state, header, &txs, receipts, &systemTxs, &header.GasUsed, false) + err := p.initContract(state, header, txs, receipts, &systemTxs, &header.GasUsed, mining) if err != nil { - log.Error("init contract failed") + log.Error("init contract failed: %+v", err) + os.Exit(1) } } if header.Difficulty.Cmp(diffInTurn) != 0 { @@ -668,7 +720,7 @@ func (p *Parlia) finalize(header *types.Header, state *state.IntraBlockState, tx } if !signedRecently { log.Trace("slash validator", "block hash", header.Hash(), "address", spoiledVal) - err = p.slash(spoiledVal, state, header, &txs, receipts, &systemTxs, &header.GasUsed, false) + err = p.slash(spoiledVal, state, header, txs, receipts, &systemTxs, &header.GasUsed, mining) if err != nil { // it is possible that slash validator failed because of the slash channel is disabled. log.Error("slash validator failed", "block hash", header.Hash(), "address", spoiledVal) @@ -676,7 +728,7 @@ func (p *Parlia) finalize(header *types.Header, state *state.IntraBlockState, tx } } val := header.Coinbase - err = p.distributeIncoming(val, state, header, &txs, receipts, &systemTxs, &header.GasUsed, false) + err = p.distributeIncoming(val, state, header, txs, receipts, &systemTxs, &header.GasUsed, mining) if err != nil { return err } @@ -691,23 +743,22 @@ func (p *Parlia) finalize(header *types.Header, state *state.IntraBlockState, tx // // Note: The block header and state database might be updated to reflect any // consensus rules that happen at finalization (e.g. block rewards). -func (p *Parlia) FinalizeAndAssemble(_ *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs []types.Transaction, _ []*types.Header, receipts types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall, call consensus.Call) (*types.Block, error) { - err := p.finalize(header, state, txs, &receipts, chain) +func (p *Parlia) FinalizeAndAssemble(_ *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs *types.Transactions, _ []*types.Header, receipts *types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall, call consensus.Call) (*types.Block, error) { + err := p.finalize(header, state, txs, receipts, chain, true) if err != nil { return nil, err } - return types.NewBlock(header, txs, nil, receipts), nil + return types.NewBlock(header, *txs, nil, *receipts), nil } // Authorize injects a private key into the consensus engine to mint new blocks // with. -func (p *Parlia) Authorize(val common.Address, signFn SignerFn, signTxFn SignerTxFn) { +func (p *Parlia) Authorize(val common.Address, signFn SignFn) { p.lock.Lock() defer p.lock.Unlock() p.val = val p.signFn = signFn - p.signTxFn = signTxFn } // Seal generates a new sealing request for the given input block and pushes @@ -716,7 +767,83 @@ func (p *Parlia) Authorize(val common.Address, signFn SignerFn, signTxFn SignerT // Note, the method returns immediately and will send the result async. More // than one result may also be returned depending on the consensus algorithm. func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { - return errNotSupported + header := block.Header() + + // Sealing the genesis block is not supported + number := header.Number.Uint64() + if number == 0 { + return errUnknownBlock + } + // For 0-period chains, refuse to seal empty blocks (no reward but would spin sealing) + if p.config.Period == 0 && len(block.Transactions()) == 0 { + log.Info("Sealing paused, waiting for transactions") + return nil + } + // Don't hold the val fields for the entire sealing procedure + p.lock.RLock() + val, signFn := p.val, p.signFn + p.lock.RUnlock() + + snap, err := p.snapshot(chain, number-1, header.ParentHash, nil) + if err != nil { + return err + } + + // Bail out if we're unauthorized to sign a block + if _, authorized := snap.Validators[val]; !authorized { + return errUnauthorizedValidator + } + + // If we're amongst the recent signers, wait for the next block + for seen, recent := range snap.Recents { + if recent == val { + // Signer is among recent, only wait if the current block doesn't shift it out + if limit := uint64(len(snap.Validators)/2 + 1); number < limit || seen > number-limit { + log.Info("Signed recently, must wait for others") + return nil + } + } + } + + // Sweet, the protocol permits us to sign the block, wait for our time + delay := p.delayForRamanujanFork(snap, header) + + log.Info("Sealing block with", "number", number, "delay", delay, "headerDifficulty", header.Difficulty, "val", val.Hex()) + + // Sign all the things! + sig, err := signFn(val, crypto.Keccak256(parliaRLP(header, p.chainConfig.ChainID)), p.chainConfig.ChainID) + if err != nil { + return err + } + copy(header.Extra[len(header.Extra)-extraSeal:], sig) + + // Wait until sealing is terminated or delay timeout. + log.Trace("Waiting for slot to sign and propagate", "delay", common.PrettyDuration(delay)) + go func() { + select { + case <-stop: + return + case <-time.After(delay): + } + if p.shouldWaitForCurrentBlockProcess(chain, header, snap) { + log.Info("Waiting for received in turn block to process") + select { + case <-stop: + log.Info("Received block process finished, abort block seal") + return + case <-time.After(time.Duration(processBackOffTime) * time.Second): + log.Info("Process backoff time exhausted, start to seal block") + } + } + + select { + case results <- block.WithSeal(header): + default: + log.Warn("Sealing result is not read by miner", "sealhash", SealHash(header, p.chainConfig.ChainID)) + } + }() + + return nil } // SealHash returns the hash of a block prior to it being sealed. @@ -784,6 +911,22 @@ func (p *Parlia) IsSystemContract(to *common.Address) bool { return isToSystemContract(*to) } +func (p *Parlia) shouldWaitForCurrentBlockProcess(chain consensus.ChainHeaderReader, header *types.Header, snap *Snapshot) bool { + if header.Difficulty.Cmp(diffInTurn) == 0 { + return false + } + + highestVerifiedHeader := chain.CurrentHeader() + if highestVerifiedHeader == nil { + return false + } + + if header.ParentHash == highestVerifiedHeader.ParentHash { + return true + } + return false +} + func (p *Parlia) EnoughDistance(chain consensus.ChainReader, header *types.Header) bool { snap, err := p.snapshot(chain, header.Number.Uint64()-1, header.ParentHash, nil) if err != nil { @@ -815,7 +958,7 @@ func (p *Parlia) Close() error { // ========================== interaction with contract/account ========= // getCurrentValidators get current validators -func (p *Parlia) getCurrentValidators(header *types.Header, state *state.IntraBlockState) ([]common.Address, error) { +func (p *Parlia) getCurrentValidators(header *types.Header, ibs *state.IntraBlockState) ([]common.Address, error) { // method method := "getValidators" data, err := p.validatorSetABI.Pack(method) @@ -826,7 +969,7 @@ func (p *Parlia) getCurrentValidators(header *types.Header, state *state.IntraBl // call msgData := (hexutil.Bytes)(data) toAddress := common.HexToAddress(systemcontracts.ValidatorContract) - _, returnData, err := systemCall(header.Coinbase, toAddress, msgData[:], *p.chainConfig, state, header, p, u256.Num0) + _, returnData, err := p.systemCall(header.Coinbase, toAddress, msgData[:], ibs, header, u256.Num0) if err != nil { return nil, err } @@ -843,7 +986,7 @@ func (p *Parlia) getCurrentValidators(header *types.Header, state *state.IntraBl } // slash spoiled validators -func (p *Parlia) distributeIncoming(val common.Address, state *state.IntraBlockState, header *types.Header, txs *[]types.Transaction, receipts *types.Receipts, receivedTxs *[]types.Transaction, usedGas *uint64, mining bool) error { +func (p *Parlia) distributeIncoming(val common.Address, state *state.IntraBlockState, header *types.Header, txs *types.Transactions, receipts *types.Receipts, receivedTxs *types.Transactions, usedGas *uint64, mining bool) error { coinbase := header.Coinbase balance := state.GetBalance(consensus.SystemAddress).Clone() if balance.Cmp(u256.Num0) <= 0 { @@ -870,7 +1013,7 @@ func (p *Parlia) distributeIncoming(val common.Address, state *state.IntraBlockS } // slash spoiled validators -func (p *Parlia) slash(spoiledVal common.Address, state *state.IntraBlockState, header *types.Header, txs *[]types.Transaction, receipts *types.Receipts, receivedTxs *[]types.Transaction, usedGas *uint64, mining bool) error { +func (p *Parlia) slash(spoiledVal common.Address, state *state.IntraBlockState, header *types.Header, txs *types.Transactions, receipts *types.Receipts, receivedTxs *types.Transactions, usedGas *uint64, mining bool) error { // method method := "slash" @@ -887,7 +1030,7 @@ func (p *Parlia) slash(spoiledVal common.Address, state *state.IntraBlockState, } // init contract -func (p *Parlia) initContract(state *state.IntraBlockState, header *types.Header, txs *[]types.Transaction, receipts *types.Receipts, receivedTxs *[]types.Transaction, usedGas *uint64, mining bool) error { +func (p *Parlia) initContract(state *state.IntraBlockState, header *types.Header, txs *types.Transactions, receipts *types.Receipts, receivedTxs *types.Transactions, usedGas *uint64, mining bool) error { // method method := "init" // contracts @@ -908,8 +1051,7 @@ func (p *Parlia) initContract(state *state.IntraBlockState, header *types.Header } for _, c := range contracts { log.Info("init contract", "block hash", header.Hash(), "contract", c) - err = p.applyTransaction(header.Coinbase, common.HexToAddress(c), u256.Num0, data, - state, header, txs, receipts, receivedTxs, usedGas, mining) + err = p.applyTransaction(header.Coinbase, common.HexToAddress(c), u256.Num0, data, state, header, txs, receipts, receivedTxs, usedGas, mining) if err != nil { return err } @@ -917,15 +1059,13 @@ func (p *Parlia) initContract(state *state.IntraBlockState, header *types.Header return nil } -func (p *Parlia) distributeToSystem(amount *uint256.Int, state *state.IntraBlockState, header *types.Header, txs *[]types.Transaction, receipts *types.Receipts, receivedTxs *[]types.Transaction, usedGas *uint64, mining bool) error { +func (p *Parlia) distributeToSystem(amount *uint256.Int, state *state.IntraBlockState, header *types.Header, txs *types.Transactions, receipts *types.Receipts, receivedTxs *types.Transactions, usedGas *uint64, mining bool) error { // apply message - return p.applyTransaction( - header.Coinbase, common.HexToAddress(systemcontracts.SystemRewardContract), amount, nil, - state, header, txs, receipts, receivedTxs, usedGas, mining) + return p.applyTransaction(header.Coinbase, common.HexToAddress(systemcontracts.SystemRewardContract), amount, nil, state, header, txs, receipts, receivedTxs, usedGas, mining) } // slash spoiled validators -func (p *Parlia) distributeToValidator(amount *uint256.Int, validator common.Address, state *state.IntraBlockState, header *types.Header, txs *[]types.Transaction, receipts *types.Receipts, receivedTxs *[]types.Transaction, usedGas *uint64, mining bool) error { +func (p *Parlia) distributeToValidator(amount *uint256.Int, validator common.Address, state *state.IntraBlockState, header *types.Header, txs *types.Transactions, receipts *types.Receipts, receivedTxs *types.Transactions, usedGas *uint64, mining bool) error { // method method := "deposit" @@ -938,42 +1078,23 @@ func (p *Parlia) distributeToValidator(amount *uint256.Int, validator common.Add return err } // apply message - return p.applyTransaction( - header.Coinbase, - common.HexToAddress(systemcontracts.ValidatorContract), - amount, - data, - state, - header, - txs, - receipts, - receivedTxs, - usedGas, - mining) + return p.applyTransaction(header.Coinbase, common.HexToAddress(systemcontracts.ValidatorContract), amount, data, state, header, txs, receipts, receivedTxs, usedGas, mining) } -func (p *Parlia) applyTransaction( - from common.Address, - to common.Address, - value *uint256.Int, - data []byte, - ibs *state.IntraBlockState, - header *types.Header, - txs *[]types.Transaction, - receipts *types.Receipts, - receivedTxs *[]types.Transaction, - usedGas *uint64, - mining bool, -) (err error) { +func (p *Parlia) applyTransaction(from common.Address, to common.Address, value *uint256.Int, data []byte, ibs *state.IntraBlockState, header *types.Header, txs *types.Transactions, receipts *types.Receipts, receivedTxs *types.Transactions, usedGas *uint64, mining bool) (err error) { nonce := ibs.GetNonce(from) expectedTx := types.Transaction(types.NewTransaction(nonce, to, value, math.MaxUint64/2, u256.Num0, data)) expectedHash := expectedTx.SigningHash(p.chainConfig.ChainID) if from == p.val && mining { - return errNotSupported - //expectedTx, err = p.signTxFn(accounts.Account{Address: msg.From()}, expectedTx, p.chainConfig.ChainID) - //if err != nil { - // return err - //} + signature, err := p.signFn(from, expectedTx.SigningHash(p.chainConfig.ChainID).Bytes(), p.chainConfig.ChainID) + if err != nil { + return err + } + signer := types.LatestSignerForChainID(p.chainConfig.ChainID) + expectedTx, err = expectedTx.WithSignature(*signer, signature) + if err != nil { + return err + } } else { if receivedTxs == nil || len(*receivedTxs) == 0 || (*receivedTxs)[0] == nil { return errors.New("supposed to get a actual transaction, but get none") @@ -1003,7 +1124,7 @@ func (p *Parlia) applyTransaction( *receivedTxs = (*receivedTxs)[1:] } ibs.Prepare(expectedTx.Hash(), common.Hash{}, len(*txs)) - gasUsed, _, err := systemCall(from, to, data, *p.chainConfig, ibs, header, p, value) + gasUsed, _, err := p.systemCall(from, to, data, ibs, header, value) if err != nil { return err } @@ -1026,7 +1147,8 @@ func (p *Parlia) applyTransaction( return nil } -func systemCall(from, contract common.Address, data []byte, chainConfig params.ChainConfig, ibs *state.IntraBlockState, header *types.Header, engine consensus.Engine, value *uint256.Int) (gasUsed uint64, returnData []byte, err error) { +func (p *Parlia) systemCall(from, contract common.Address, data []byte, ibs *state.IntraBlockState, header *types.Header, value *uint256.Int) (gasUsed uint64, returnData []byte, err error) { + chainConfig := p.chainConfig if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(header.Number) == 0 { misc.ApplyDAOHardFork(ibs) } @@ -1040,8 +1162,8 @@ func systemCall(from, contract common.Address, data []byte, chainConfig params.C ) vmConfig := vm.Config{NoReceipts: true} // Create a new context to be used in the EVM environment - blockContext := core.NewEVMBlockContext(header, nil, engine, &from, nil) - evm := vm.NewEVM(blockContext, core.NewEVMTxContext(msg), ibs, &chainConfig, vmConfig) + blockContext := core.NewEVMBlockContext(header, nil, p, &from, nil) + evm := vm.NewEVM(blockContext, core.NewEVMTxContext(msg), ibs, chainConfig, vmConfig) ret, leftOverGas, err := evm.Call( vm.AccountRef(msg.From()), *msg.To(), diff --git a/consensus/serenity/serenity.go b/consensus/serenity/serenity.go index de4b172d75a..c79b474a00d 100644 --- a/consensus/serenity/serenity.go +++ b/consensus/serenity/serenity.go @@ -86,17 +86,17 @@ func (s *Serenity) VerifyUncles(chain consensus.ChainReader, header *types.Heade } // Prepare makes sure difficulty and nonce are correct -func (s *Serenity) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { +func (s *Serenity) Prepare(chain consensus.ChainHeaderReader, header *types.Header, state *state.IntraBlockState) error { header.Difficulty = SerenityDifficulty header.Nonce = types.BlockNonce{} return nil } func (s *Serenity) FinalizeAndAssemble(config *params.ChainConfig, header *types.Header, - state *state.IntraBlockState, txs []types.Transaction, uncles []*types.Header, - receipts types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, + state *state.IntraBlockState, txs *types.Transactions, uncles []*types.Header, + receipts *types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall, call consensus.Call) (*types.Block, error) { - return types.NewBlock(header, txs, uncles, receipts), nil + return types.NewBlock(header, *txs, uncles, *receipts), nil } func (s *Serenity) SealHash(header *types.Header) (hash common.Hash) { @@ -193,7 +193,7 @@ func (s *Serenity) verifyHeader(chain consensus.ChainHeaderReader, header, paren // v func (s *Serenity) Finalize(config *params.ChainConfig, header *types.Header, state *state.IntraBlockState, - txs []types.Transaction, uncles []*types.Header, r types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, + txs *types.Transactions, uncles []*types.Header, r *types.Receipts, e consensus.EpochReader, chain consensus.ChainHeaderReader, syscall consensus.SystemCall) error { return nil } diff --git a/core/blockchain.go b/core/blockchain.go index 40e37fd43bf..291ec49c7c8 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -162,10 +162,15 @@ func ExecuteBlockEphemerally( var newBlock *types.Block if !vmConfig.ReadOnly { - var err error - if newBlock, err = FinalizeBlockExecution(engine, stateReader, block.Header(), block.Transactions(), block.Uncles(), stateWriter, chainConfig, ibs, &receipts, epochReader, chainReader, usedGas); err != nil { + txs := block.Transactions() + if err := FinalizeBlockExecution(engine, stateReader, block.Header(), &txs, block.Uncles(), stateWriter, chainConfig, ibs, &receipts, epochReader, chainReader, usedGas, false); err != nil { return nil, err } + // We need repack this block because transactions and receipts might be changed by consensus, and + // it won't pass receipts hash or bloom verification + newBlock = types.NewBlock(block.Header(), txs, block.Uncles(), receipts) + } else { + newBlock = block } if chainConfig.IsByzantium(header.Number.Uint64()) && !vmConfig.NoReceipts { @@ -247,20 +252,40 @@ func CallContractTx(contract common.Address, data []byte, ibs *state.IntraBlockS return tx.FakeSign(from) } -func FinalizeBlockExecution(engine consensus.Engine, stateReader state.StateReader, header *types.Header, txs types.Transactions, uncles []*types.Header, stateWriter state.WriterWithChangeSets, cc *params.ChainConfig, ibs *state.IntraBlockState, receipts *types.Receipts, e consensus.EpochReader, headerReader consensus.ChainHeaderReader, gasUsed *uint64) (*types.Block, error) { +func FinalizeBlockExecution( + engine consensus.Engine, + stateReader state.StateReader, + header *types.Header, + txs *types.Transactions, + uncles []*types.Header, + stateWriter state.WriterWithChangeSets, + cc *params.ChainConfig, + ibs *state.IntraBlockState, + receipts *types.Receipts, + e consensus.EpochReader, + headerReader consensus.ChainHeaderReader, + gasUsed *uint64, + mining bool, +) error { - // We're doing this hack for BSC to avoid changing consensus interfaces. BSC modifies txs and receipts by appending + // We're doing this hack for BSC to avoid changing consensus interfaces a lot. BSC modifies txs and receipts by appending // system transactions, and they increase used gas and write cumulative gas to system receipts, that's why we need // to deduct system gas before. This line is equal to "blockGas-systemGas", but since we don't know how much gas is // used by system transactions we just override. Of course, we write used by block gas back. It also always true // that used gas by block is always equal to original's block header gas, and it's checked by receipts root verification // otherwise it causes block verification error. header.GasUsed = *gasUsed - block, err := engine.FinalizeAndAssemble(cc, header, ibs, txs, uncles, *receipts, e, headerReader, func(contract common.Address, data []byte) ([]byte, error) { + syscall := func(contract common.Address, data []byte) ([]byte, error) { return SysCallContract(contract, data, *cc, ibs, header, engine) - }, nil) + } + var err error + if mining { + _, err = engine.FinalizeAndAssemble(cc, header, ibs, txs, uncles, receipts, e, headerReader, syscall, syscall) + } else { + err = engine.Finalize(cc, header, ibs, txs, uncles, receipts, e, headerReader, syscall) + } if err != nil { - return nil, err + return err } *gasUsed = header.GasUsed @@ -272,27 +297,27 @@ func FinalizeBlockExecution(engine consensus.Engine, stateReader state.StateRead var err error originalSystemAcc, err = stateReader.ReadAccountData(state.SystemAddress) if err != nil { - return nil, err + return err } } } if err := ibs.CommitBlock(cc.Rules(header.Number.Uint64()), stateWriter); err != nil { - return nil, fmt.Errorf("committing block %d failed: %w", header.Number.Uint64(), err) + return fmt.Errorf("committing block %d failed: %w", header.Number.Uint64(), err) } if originalSystemAcc != nil { // hack for Sokol - don't understand why eip158 is enabled, but OE still save SystemAddress with nonce=0 acc := accounts.NewAccount() acc.Nonce = 0 if err := stateWriter.UpdateAccountData(state.SystemAddress, originalSystemAcc, &acc); err != nil { - return nil, err + return err } } if err := stateWriter.WriteChangeSets(); err != nil { - return nil, fmt.Errorf("writing changesets for block %d failed: %w", header.Number.Uint64(), err) + return fmt.Errorf("writing changesets for block %d failed: %w", header.Number.Uint64(), err) } - return block, nil + return nil } func InitializeBlockExecution(engine consensus.Engine, chain consensus.ChainHeaderReader, epochReader consensus.EpochReader, header *types.Header, txs types.Transactions, uncles []*types.Header, cc *params.ChainConfig, ibs *state.IntraBlockState) error { diff --git a/core/chain_makers.go b/core/chain_makers.go index af2b4b2b05f..c0b6333c380 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -287,7 +287,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse } if b.engine != nil { // Finalize and seal the block - if _, err := b.engine.FinalizeAndAssemble(config, b.header, ibs, b.txs, b.uncles, b.receipts, nil, nil, nil, nil); err != nil { + if _, err := b.engine.FinalizeAndAssemble(config, b.header, ibs, (*types.Transactions)(&b.txs), b.uncles, (*types.Receipts)(&b.receipts), nil, nil, nil, nil); err != nil { return nil, nil, fmt.Errorf("call to FinaliseAndAssemble: %w", err) } // Write state changes to db diff --git a/core/genesis.go b/core/genesis.go index 3598278db4f..51f9259f810 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -681,8 +681,10 @@ var DevnetEtherbase = common.HexToAddress("67b1d87101671b127f5f8714789c7192f7ad3 // DeveloperGenesisBlock returns the 'geth --dev' genesis block. func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis { // Override the default period to the user requested one - config := *params.AllCliqueProtocolChanges - config.Clique.Period = period + config := *params.ChapelChainConfig + if period > 0 { + config.Parlia.Period = period + } // Assemble and return the genesis with the precompiles and faucet pre-funded return &Genesis{ diff --git a/eth/backend.go b/eth/backend.go index e0cc8d4cf7d..63a169b5c96 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -543,22 +543,25 @@ func (s *Ethereum) StartMining(ctx context.Context, db kv.RwDB, mining *stagedsy log.Error("Cannot start mining without etherbase", "err", err) return fmt.Errorf("etherbase missing: %w", err) } - if clique, ok := s.engine.(*clique.Clique); ok { + if c, ok := s.engine.(*clique.Clique); ok { if cfg.SigKey == nil { log.Error("Etherbase account unavailable locally", "err", err) return fmt.Errorf("signer missing: %w", err) } - clique.Authorize(eb, func(_ common.Address, mimeType string, message []byte) ([]byte, error) { + c.Authorize(eb, func(_ common.Address, mimeType string, message []byte) ([]byte, error) { return crypto.Sign(crypto.Keccak256(message), cfg.SigKey) }) } - if _, ok := s.engine.(*parlia.Parlia); ok { + if p, ok := s.engine.(*parlia.Parlia); ok { if cfg.SigKey == nil { log.Error("Etherbase account unavailable locally", "err", err) return fmt.Errorf("signer missing: %w", err) } - panic("validator mode for parlia consensus is not yet supported") + + p.Authorize(eb, func(validator common.Address, payload []byte, chainId *big.Int) ([]byte, error) { + return crypto.Sign(payload, cfg.SigKey) + }) } if s.chainConfig.ChainID.Uint64() > 10 { diff --git a/eth/stagedsync/stage_mining_create_block.go b/eth/stagedsync/stage_mining_create_block.go index 1c1145464d4..80332367903 100644 --- a/eth/stagedsync/stage_mining_create_block.go +++ b/eth/stagedsync/stage_mining_create_block.go @@ -5,6 +5,7 @@ import ( "context" "errors" "fmt" + "github.com/ledgerwatch/erigon/core/state" "math/big" "time" @@ -27,7 +28,7 @@ import ( type MiningBlock struct { Header *types.Header Uncles []*types.Header - Txs []types.Transaction + Txs types.Transactions Receipts types.Receipts LocalTxs types.TransactionsStream @@ -190,7 +191,10 @@ func SpawnMiningCreateBlockStage(s *StageState, tx kv.RwTx, cfg MiningCreateBloc header.Coinbase = coinbase //} - if err = cfg.engine.Prepare(chain, header); err != nil { + stateReader := state.NewPlainStateReader(tx) + ibs := state.New(stateReader) + + if err = cfg.engine.Prepare(chain, header, ibs); err != nil { log.Error("Failed to prepare header for mining", "err", err, "headerNumber", header.Number.Uint64(), diff --git a/eth/stagedsync/stage_mining_exec.go b/eth/stagedsync/stage_mining_exec.go index 1b56684a01b..bc58d6241b0 100644 --- a/eth/stagedsync/stage_mining_exec.go +++ b/eth/stagedsync/stage_mining_exec.go @@ -5,18 +5,22 @@ import ( libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/log/v3" + + "github.com/ledgerwatch/erigon/cmd/rpcdaemon/interfaces" "github.com/ledgerwatch/erigon/common" "github.com/ledgerwatch/erigon/consensus" "github.com/ledgerwatch/erigon/consensus/misc" "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/core/state" + "github.com/ledgerwatch/erigon/core/systemcontracts" "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/core/vm" "github.com/ledgerwatch/erigon/eth/stagedsync/stages" "github.com/ledgerwatch/erigon/ethdb" "github.com/ledgerwatch/erigon/params" - "github.com/ledgerwatch/log/v3" + "github.com/ledgerwatch/erigon/turbo/snapshotsync" ) type MiningExecCfg struct { @@ -25,6 +29,7 @@ type MiningExecCfg struct { notifier ChainEventNotifier chainConfig params.ChainConfig engine consensus.Engine + blockReader interfaces.FullBlockReader vmConfig *vm.Config tmpdir string } @@ -44,6 +49,7 @@ func StageMiningExecCfg( notifier: notifier, chainConfig: chainConfig, engine: engine, + blockReader: snapshotsync.NewBlockReader(), vmConfig: vmConfig, tmpdir: tmpdir, } @@ -66,6 +72,7 @@ func SpawnMiningExecStage(s *StageState, tx kv.RwTx, cfg MiningExecCfg, quit <-c if cfg.chainConfig.DAOForkSupport && cfg.chainConfig.DAOForkBlock != nil && cfg.chainConfig.DAOForkBlock.Cmp(current.Header.Number) == 0 { misc.ApplyDAOHardFork(ibs) } + systemcontracts.UpgradeBuildInSystemContract(&cfg.chainConfig, current.Header.Number, ibs) // Create an empty block based on temporary copied state for // sealing in advance without waiting block execution finished. @@ -107,7 +114,18 @@ func SpawnMiningExecStage(s *StageState, tx kv.RwTx, cfg MiningExecCfg, quit <-c } } - if _, err := core.FinalizeBlockExecution(cfg.engine, stateReader, current.Header, current.Txs, current.Uncles, stateWriter, &cfg.chainConfig, ibs, nil, nil, nil, new(uint64)); err != nil { + if current.Uncles == nil { + current.Uncles = []*types.Header{} + } + if current.Txs == nil { + current.Txs = []types.Transaction{} + } + if current.Receipts == nil { + current.Receipts = types.Receipts{} + } + + err := core.FinalizeBlockExecution(cfg.engine, stateReader, current.Header, ¤t.Txs, current.Uncles, stateWriter, &cfg.chainConfig, ibs, ¤t.Receipts, epochReader{tx: tx}, chainReader{config: &cfg.chainConfig, tx: tx, blockReader: cfg.blockReader}, new(uint64), true) + if err != nil { return err } diff --git a/migrations/receipt_repair.go b/migrations/receipt_repair.go index 488217256ee..556ed8274cf 100644 --- a/migrations/receipt_repair.go +++ b/migrations/receipt_repair.go @@ -116,7 +116,7 @@ var ReceiptRepair = Migration{ getHeader := func(hash common.Hash, number uint64) *types.Header { return rawdb.ReadHeader(tx, hash, number) } contractHasTEVM := ethdb.GetHasTEVM(tx) - receipts1, err1 := runBlock(intraBlockState, noOpWriter, noOpWriter, chainConfig, getHeader, contractHasTEVM, block, vmConfig) + block, receipts1, err1 := runBlock(intraBlockState, noOpWriter, noOpWriter, chainConfig, getHeader, contractHasTEVM, block, vmConfig) if err1 != nil { return err1 } @@ -148,8 +148,15 @@ var ReceiptRepair = Migration{ }, } -func runBlock(ibs *state.IntraBlockState, txnWriter state.StateWriter, blockWriter state.StateWriter, - chainConfig *params.ChainConfig, getHeader func(hash common.Hash, number uint64) *types.Header, contractHasTEVM func(common.Hash) (bool, error), block *types.Block, vmConfig vm.Config) (types.Receipts, error) { +func runBlock( + ibs *state.IntraBlockState, + txnWriter state.StateWriter, + blockWriter state.StateWriter, + chainConfig *params.ChainConfig, + getHeader func(hash common.Hash, number uint64) *types.Header, contractHasTEVM func(common.Hash) (bool, error), + block *types.Block, + vmConfig vm.Config, +) (*types.Block, types.Receipts, error) { header := block.Header() vmConfig.TraceJumpDest = true engine := ethash.NewFullFaker() @@ -163,21 +170,22 @@ func runBlock(ibs *state.IntraBlockState, txnWriter state.StateWriter, blockWrit ibs.Prepare(tx.Hash(), block.Hash(), i) receipt, _, err := core.ApplyTransaction(chainConfig, getHeader, engine, nil, gp, ibs, txnWriter, header, tx, usedGas, vmConfig, contractHasTEVM) if err != nil { - return nil, fmt.Errorf("could not apply tx %d [%x] failed: %w", i, tx.Hash(), err) + return nil, nil, fmt.Errorf("could not apply tx %d [%x] failed: %w", i, tx.Hash(), err) } receipts = append(receipts, receipt) } if !vmConfig.ReadOnly { // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) - if _, err := engine.FinalizeAndAssemble(chainConfig, header, ibs, block.Transactions(), block.Uncles(), receipts, nil, nil, nil, nil); err != nil { - return nil, fmt.Errorf("finalize of block %d failed: %w", block.NumberU64(), err) + txs := block.Transactions() + if _, err := engine.FinalizeAndAssemble(chainConfig, header, ibs, &txs, block.Uncles(), &receipts, nil, nil, nil, nil); err != nil { + return nil, nil, fmt.Errorf("finalize of block %d failed: %w", block.NumberU64(), err) } - + block = types.NewBlock(block.Header(), txs, block.Uncles(), receipts) if err := ibs.CommitBlock(chainConfig.Rules(header.Number.Uint64()), blockWriter); err != nil { - return nil, fmt.Errorf("committing block %d failed: %w", block.NumberU64(), err) + return nil, nil, fmt.Errorf("committing block %d failed: %w", block.NumberU64(), err) } } - return receipts, nil + return block, receipts, nil } diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index 963ae4fe879..4df67c4e3fa 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -32,11 +32,12 @@ import ( "testing" "time" + "github.com/ledgerwatch/log/v3" + "github.com/ledgerwatch/erigon/internal/testlog" "github.com/ledgerwatch/erigon/p2p/discover/v4wire" "github.com/ledgerwatch/erigon/p2p/enode" "github.com/ledgerwatch/erigon/p2p/enr" - "github.com/ledgerwatch/log/v3" ) // shared test variables @@ -102,7 +103,7 @@ func (test *udpTest) packetInFrom(wantError error, key *ecdsa.PrivateKey, addr * enc, _, err := v4wire.Encode(key, data) if err != nil { - test.t.Errorf("%s encode error: %w", data.Name(), err) + test.t.Errorf("%s encode error: %v", data.Name(), err) } test.sent = append(test.sent, enc) if err = test.udp.handlePacket(addr, enc); err != wantError { @@ -124,7 +125,7 @@ func (test *udpTest) waitPacketOut(validate interface{}) (closed bool) { } p, _, hash, err := v4wire.Decode(dgram.data) if err != nil { - test.t.Errorf("sent packet decode error: %w", err) + test.t.Errorf("sent packet decode error: %v", err) return false } fn := reflect.ValueOf(validate) diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 7319a1d32c2..ffc37bebbb7 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -30,12 +30,13 @@ import ( "testing" "time" + "github.com/ledgerwatch/log/v3" + "github.com/ledgerwatch/erigon/internal/testlog" "github.com/ledgerwatch/erigon/p2p/discover/v5wire" "github.com/ledgerwatch/erigon/p2p/enode" "github.com/ledgerwatch/erigon/p2p/enr" "github.com/ledgerwatch/erigon/rlp" - "github.com/ledgerwatch/log/v3" ) // Real sockets, real crypto: this test checks end-to-end connectivity for UDPv5. @@ -755,7 +756,7 @@ func (test *udpV5Test) packetInFrom(key *ecdsa.PrivateKey, addr *net.UDPAddr, pa codec := &testCodec{test: test, id: ln.ID()} enc, _, err := codec.Encode(test.udp.Self().ID(), addr.String(), packet, nil) if err != nil { - test.t.Errorf("%s encode error: %w", packet.Name(), err) + test.t.Errorf("%s encode error: %v", packet.Name(), err) } if test.udp.dispatchReadPacket(addr, enc) { <-test.udp.readNextCh // unblock UDPv5.dispatch @@ -807,7 +808,7 @@ func (test *udpV5Test) waitPacketOut(validate interface{}) (closed bool) { codec := &testCodec{test: test, id: ln.ID()} frame, p, err := codec.decodeFrame(dgram.data) if err != nil { - test.t.Errorf("sent packet decode error: %w", err) + test.t.Errorf("sent packet decode error: %v", err) return false } if !reflect.TypeOf(p).AssignableTo(exptype) { diff --git a/turbo/cli/default_flags.go b/turbo/cli/default_flags.go index da2a041a45c..3d6e4da2507 100644 --- a/turbo/cli/default_flags.go +++ b/turbo/cli/default_flags.go @@ -55,6 +55,7 @@ var DefaultFlags = []cli.Flag{ utils.NodeKeyFileFlag, utils.NodeKeyHexFlag, utils.DNSDiscoveryFlag, + utils.BootnodesFlag, utils.StaticPeersFlag, utils.TrustedPeersFlag, utils.MaxPeersFlag,