diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index db686c5d0..28358fa34 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -212,7 +212,11 @@ type Config struct { // CreateConsensusEngine creates a consensus engine for the given chain configuration. func CreateConsensusEngine(stack *node.Node, ethashConfig *ethash.Config, cliqueConfig *params.CliqueConfig, notify []string, noverify bool, db ethdb.Database) consensus.Engine { // If proof-of-authority is requested, set it up + if engine := pluginGetEngine(stack, notify, noverify, db); engine != nil { + return engine + } var engine consensus.Engine + if cliqueConfig != nil { engine = clique.New(cliqueConfig, db) } else { diff --git a/plugins/wrappers/engine/enginewrapper.go b/plugins/wrappers/engine/enginewrapper.go new file mode 100644 index 000000000..61de2c8cf --- /dev/null +++ b/plugins/wrappers/engine/enginewrapper.go @@ -0,0 +1,456 @@ +package engine + +import ( + "fmt" + "math/big" + "reflect" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + // "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/plugins/wrappers" + "github.com/openrelayxyz/plugeth-utils/core" + ptypes "github.com/openrelayxyz/plugeth-utils/restricted/types" + pconsensus "github.com/openrelayxyz/plugeth-utils/restricted/consensus" + pparams "github.com/openrelayxyz/plugeth-utils/restricted/params" +) + + +func gethToUtilsHeader(header *types.Header) *ptypes.Header { + if header == nil { return nil } + return &ptypes.Header{ + ParentHash: core.Hash(header.ParentHash), + UncleHash: core.Hash(header.UncleHash), + Coinbase: core.Address(header.Coinbase), + Root: core.Hash(header.Root), + TxHash: core.Hash(header.TxHash), + ReceiptHash: core.Hash(header.ReceiptHash), + Bloom: ptypes.Bloom(header.Bloom), + Difficulty: header.Difficulty, + Number: header.Number, + GasLimit: header.GasLimit, + GasUsed: header.GasUsed, + Time: header.Time, + Extra: header.Extra, + MixDigest: core.Hash(header.MixDigest), + Nonce: ptypes.BlockNonce(header.Nonce), + BaseFee: header.BaseFee, + WithdrawalsHash: (*core.Hash)(header.WithdrawalsHash), + } +} +func utilsToGethHeader(header *ptypes.Header) *types.Header { + if header == nil { return nil } + return &types.Header{ + ParentHash: common.Hash(header.ParentHash), + UncleHash: common.Hash(header.UncleHash), + Coinbase: common.Address(header.Coinbase), + Root: common.Hash(header.Root), + TxHash: common.Hash(header.TxHash), + ReceiptHash: common.Hash(header.ReceiptHash), + Bloom: types.Bloom(header.Bloom), + Difficulty: header.Difficulty, + Number: header.Number, + GasLimit: header.GasLimit, + GasUsed: header.GasUsed, + Time: header.Time, + Extra: header.Extra, + MixDigest: common.Hash(header.MixDigest), + Nonce: types.BlockNonce(header.Nonce), + BaseFee: header.BaseFee, + WithdrawalsHash: (*common.Hash)(header.WithdrawalsHash), + } +} + +func gethToUtilsTransactions(transactions []*types.Transaction) []*ptypes.Transaction { + if transactions == nil { return nil } + txs := make([]*ptypes.Transaction, len(transactions)) + for i, tx := range transactions { + bin, err := tx.MarshalBinary() + if err != nil { panic (err) } + txs[i] = &ptypes.Transaction{} + txs[i].UnmarshalBinary(bin) + } + return txs +} + +func gethToUtilsHeaders(headers []*types.Header) []*ptypes.Header { + if headers == nil { return nil } + pheaders := make([]*ptypes.Header, len(headers)) + for i, header := range headers { + pheaders[i] = gethToUtilsHeader(header) + } + return pheaders +} + +func gethToUtilsReceipts(receipts []*types.Receipt) []*ptypes.Receipt { + if receipts == nil { return nil } + preceipts := make([]*ptypes.Receipt, len(receipts)) + for i, receipt := range receipts { + preceipts[i] = &ptypes.Receipt{ + Type: receipt.Type, + PostState: receipt.PostState, + Status: receipt.Status, + CumulativeGasUsed: receipt.CumulativeGasUsed, + Bloom: ptypes.Bloom(receipt.Bloom), + Logs: gethToUtilsLogs(receipt.Logs), + TxHash: core.Hash(receipt.TxHash), + ContractAddress: core.Address(receipt.ContractAddress), + GasUsed: receipt.GasUsed, + BlockHash: core.Hash(receipt.BlockHash), + BlockNumber: receipt.BlockNumber, + TransactionIndex: receipt.TransactionIndex, + } + } + return preceipts +} + +func gethToUtilsWithdrawals(withdrawals []*types.Withdrawal) []*ptypes.Withdrawal { + if withdrawals == nil { return nil } + pwithdrawals := make([]*ptypes.Withdrawal, len(withdrawals)) + for i, withdrawal := range withdrawals { + pwithdrawals[i] = &ptypes.Withdrawal{ + Index: withdrawal.Index, + Validator: withdrawal.Validator, + Address: core.Address(withdrawal.Address), + Amount: withdrawal.Amount, + } + } + return pwithdrawals +} + +func gethToUtilsBlock(block *types.Block) *ptypes.Block { + if block == nil { return nil } + return ptypes.NewBlockWithHeader(gethToUtilsHeader(block.Header())).WithBody(gethToUtilsTransactions(block.Transactions()), gethToUtilsHeaders(block.Uncles())).WithWithdrawals(gethToUtilsWithdrawals(block.Withdrawals())) + + // NewBlockWithWithdrawals( + // gethToUtilsHeader(block.Header()), + // gethToUtilsTransactions(block.Transactions()), + // gethToUtilsHeaders(block.Uncles()), + // gethToUtilsReceipts(block.Receipts()), + // gethToUtilsWithdrawals(block.Withdrawals()), + // &hasherWrapper{trie.NewStackTrie(nil)}, + // ) +} + +func utilsToGethBlock(block *ptypes.Block) *types.Block { + if block == nil { return nil } + return types.NewBlockWithHeader(utilsToGethHeader(block.Header())).WithBody(utilsToGethTransactions(block.Transactions()), utilsToGethHeaders(block.Uncles())).WithWithdrawals(utilsToGethWithdrawals(block.Withdrawals())) + // return types.NewBlockWithWithdrawals( + // utilsToGethHeader(block.Header()), + // utilsToGethTransactions(block.Transactions()), + // utilsToGethHeaders(block.Uncles()), + // utilsToGethReceipts(block.Receipts()), + // utilsToGethWithdrawals(block.Withdrawals()), + // trie.NewStackTrie(nil), + // ) +} + +func utilsToGethHeaders(headers []*ptypes.Header) []*types.Header { + if headers == nil { return nil } + pheaders := make([]*types.Header, len(headers)) + for i, header := range headers { + pheaders[i] = utilsToGethHeader(header) + } + return pheaders +} + +func utilsToGethTransactions(transactions []*ptypes.Transaction) []*types.Transaction { + if transactions == nil { return nil } + txs := make([]*types.Transaction, len(transactions)) + for i, tx := range transactions { + bin, err := tx.MarshalBinary() + if err != nil { panic (err) } + txs[i] = &types.Transaction{} + txs[i].UnmarshalBinary(bin) + } + return txs +} +// func utilsToGethReceipts(receipts []*ptypes.Receipt) []*types.Receipt { +// if receipts == nil { return nil } +// preceipts := make([]*types.Receipt, len(receipts)) +// for i, receipt := range receipts { +// preceipts[i] = &types.Receipt{ +// Type: receipt.Type, +// PostState: receipt.PostState, +// Status: receipt.Status, +// CumulativeGasUsed: receipt.CumulativeGasUsed, +// Bloom: types.Bloom(receipt.Bloom), +// Logs: utilsToGethLogs(receipt.Logs), +// TxHash: common.Hash(receipt.TxHash), +// ContractAddress: common.Address(receipt.ContractAddress), +// GasUsed: receipt.GasUsed, +// BlockHash: common.Hash(receipt.BlockHash), +// BlockNumber: receipt.BlockNumber, +// TransactionIndex: receipt.TransactionIndex, +// } +// } +// return preceipts +// } +func utilsToGethWithdrawals(withdrawals []*ptypes.Withdrawal) []*types.Withdrawal { + if withdrawals == nil { return nil } + pwithdrawals := make([]*types.Withdrawal, len(withdrawals)) + for i, withdrawal := range withdrawals { + pwithdrawals[i] = &types.Withdrawal{ + Index: withdrawal.Index, + Validator: withdrawal.Validator, + Address: common.Address(withdrawal.Address), + Amount: withdrawal.Amount, + } + } + return pwithdrawals +} + +func gethToUtilsBlockChan(ch chan<- *types.Block) chan<- *ptypes.Block { + pchan := make(chan *ptypes.Block) + go func() { + for block := range pchan { + ch <- utilsToGethBlock(block) + } + close(ch) + }() + return pchan +} + +func gethToUtilsLog(logRecord *types.Log) *ptypes.Log { + if logRecord == nil { return nil } + topics := make([]core.Hash, len(logRecord.Topics)) + for i, t := range logRecord.Topics { + topics[i] = core.Hash(t) + } + return &ptypes.Log{ + Address: core.Address(logRecord.Address), + Topics: topics, + Data: logRecord.Data, + BlockNumber: logRecord.BlockNumber, + TxHash: core.Hash(logRecord.TxHash), + TxIndex: logRecord.TxIndex, + BlockHash: core.Hash(logRecord.BlockHash), + Index: logRecord.Index, + Removed: logRecord.Removed, + } +} + +func utilsToGethLog(logRecord *ptypes.Log) *types.Log { + if logRecord == nil { return nil } + topics := make([]common.Hash, len(logRecord.Topics)) + for i, t := range logRecord.Topics { + topics[i] = common.Hash(t) + } + return &types.Log{ + Address: common.Address(logRecord.Address), + Topics: topics, + Data: logRecord.Data, + BlockNumber: logRecord.BlockNumber, + TxHash: common.Hash(logRecord.TxHash), + TxIndex: logRecord.TxIndex, + BlockHash: common.Hash(logRecord.BlockHash), + Index: logRecord.Index, + Removed: logRecord.Removed, + } +} + +func gethToUtilsLogs(logs []*types.Log) []*ptypes.Log { + result := make([]*ptypes.Log, len(logs)) + for i, logRecord := range logs { + result[i] = gethToUtilsLog(logRecord) + } + return result +} + +func utilsToGethLogs(logs []*ptypes.Log) []*types.Log { + result := make([]*types.Log, len(logs)) + for i, logRecord := range logs { + result[i] = utilsToGethLog(logRecord) + } + return result +} + + +func convertAndSet(a, b reflect.Value) (err error) { + defer func() { + if recover() != nil { + fmt.Errorf("error converting: %v", err.Error()) + } + }() + a.Set(b.Convert(a.Type())) + return nil +} + +func gethToUtilsConfig(gcfg *params.ChainConfig) *pparams.ChainConfig { + cfg := &pparams.ChainConfig{} + nval := reflect.ValueOf(gcfg) + ntype := nval.Elem().Type() + lval := reflect.ValueOf(cfg) + for i := 0; i < nval.Elem().NumField(); i++ { + field := ntype.Field(i) + v := nval.Elem().FieldByName(field.Name) + lv := lval.Elem().FieldByName(field.Name) + log.Info("Checking value for", "field", field.Name) + if lv.Kind() != reflect.Invalid { + // If core.ChainConfig doesn't have this field, skip it. + if v.Type() == lv.Type() && lv.CanSet() { + lv.Set(v) + } else { + convertAndSet(lv, v) + } + } + } + return cfg +} + +type WrappedHeaderReader struct { + chr consensus.ChainHeaderReader + cfg *pparams.ChainConfig +} + +func (whr *WrappedHeaderReader) Config() *pparams.ChainConfig { + if whr.cfg == nil { + whr.cfg = gethToUtilsConfig(whr.chr.Config()) + } + return whr.cfg +} + +// CurrentHeader retrieves the current header from the local chain. +func (whr *WrappedHeaderReader) CurrentHeader() *ptypes.Header { + return gethToUtilsHeader(whr.chr.CurrentHeader()) +} + +// GetHeader retrieves a block header from the database by hash and number. +func (whr *WrappedHeaderReader) GetHeader(hash core.Hash, number uint64) *ptypes.Header { + return gethToUtilsHeader(whr.chr.GetHeader(common.Hash(hash), number)) +} + +// GetHeaderByNumber retrieves a block header from the database by number. +func (whr *WrappedHeaderReader) GetHeaderByNumber(number uint64) *ptypes.Header { + return gethToUtilsHeader(whr.chr.GetHeaderByNumber(number)) +} + +// GetHeaderByHash retrieves a block header from the database by its hash. +func (whr *WrappedHeaderReader) GetHeaderByHash(hash core.Hash) *ptypes.Header { + return gethToUtilsHeader(whr.chr.GetHeaderByHash(common.Hash(hash))) +} + +// GetTd retrieves the total difficulty from the database by hash and number. +func (whr *WrappedHeaderReader) GetTd(hash core.Hash, number uint64) *big.Int { + return whr.chr.GetTd(common.Hash(hash), number) +} + + +type WrappedChainReader struct { + chr consensus.ChainReader + cfg *pparams.ChainConfig +} + +func (whr *WrappedChainReader) Config() *pparams.ChainConfig { + // We're using the reflect library to copy data from params.ChainConfig to + // pparams.ChainConfig, so this function shouldn't need to be touched for + // simple changes to ChainConfig (though pparams.ChainConfig may need to be + // updated). Note that this probably won't carry over consensus engine data. + if whr.cfg == nil { + whr.cfg = gethToUtilsConfig(whr.chr.Config()) + } + return whr.cfg +} + +// CurrentHeader retrieves the current header from the local chain. +func (whr *WrappedChainReader) CurrentHeader() *ptypes.Header { + return gethToUtilsHeader(whr.chr.CurrentHeader()) +} + +// GetHeader retrieves a block header from the database by hash and number. +func (whr *WrappedChainReader) GetHeader(hash core.Hash, number uint64) *ptypes.Header { + return gethToUtilsHeader(whr.chr.GetHeader(common.Hash(hash), number)) +} + +// GetHeaderByNumber retrieves a block header from the database by number. +func (whr *WrappedChainReader) GetHeaderByNumber(number uint64) *ptypes.Header { + return gethToUtilsHeader(whr.chr.GetHeaderByNumber(number)) +} + +// GetHeaderByHash retrieves a block header from the database by its hash. +func (whr *WrappedChainReader) GetHeaderByHash(hash core.Hash) *ptypes.Header { + return gethToUtilsHeader(whr.chr.GetHeaderByHash(common.Hash(hash))) +} + +// GetTd retrieves the total difficulty from the database by hash and number. +func (whr *WrappedChainReader) GetTd(hash core.Hash, number uint64) *big.Int { + return whr.chr.GetTd(common.Hash(hash), number) +} + +func (whr *WrappedChainReader) GetBlock(hash core.Hash, number uint64) *ptypes.Block { + return gethToUtilsBlock(whr.chr.GetBlock(common.Hash(hash), number)) +} + +type hasherWrapper struct { + th types.TrieHasher +} +func (hw *hasherWrapper) Reset() { + hw.th.Reset() +} +func (hw *hasherWrapper) Update(a, b []byte) { + hw.th.Update(a, b) +} +func (hw *hasherWrapper) Hash() core.Hash { + return core.Hash(hw.th.Hash()) +} + +type engineWrapper struct { + engine pconsensus.Engine +} + +func (ew *engineWrapper) Author(header *types.Header) (core.Address, error) { + addr, err := ew.engine.Author(gethToUtilsHeader(header)) + return core.Address(addr), err +} +func (ew *engineWrapper) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, seal bool) error { + return ew.engine.VerifyHeader(&WrappedHeaderReader{chain, nil}, gethToUtilsHeader(header), seal) +} +func (ew *engineWrapper) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { + pheaders := make([]*ptypes.Header, len(headers)) + for i, header := range headers { + pheaders[i] = gethToUtilsHeader(header) + } + return ew.engine.VerifyHeaders(&WrappedHeaderReader{chain, nil}, pheaders, seals) +} +func (ew *engineWrapper) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { + return ew.engine.VerifyUncles(&WrappedChainReader{chain, nil}, gethToUtilsBlock(block)) +} +func (ew *engineWrapper) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { + return ew.engine.Prepare(&WrappedHeaderReader{chain, nil}, gethToUtilsHeader(header)) +} +func (ew *engineWrapper) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { + ew.engine.Finalize(&WrappedHeaderReader{chain, nil}, gethToUtilsHeader(header), wrappers.NewWrappedStateDB(state), gethToUtilsTransactions(txs), gethToUtilsHeaders(uncles), gethToUtilsWithdrawals(withdrawals)) +} +func (ew *engineWrapper) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) { + block, err := ew.engine.FinalizeAndAssemble(&WrappedHeaderReader{chain, nil}, gethToUtilsHeader(header), wrappers.NewWrappedStateDB(state), gethToUtilsTransactions(txs), gethToUtilsHeaders(uncles), gethToUtilsReceipts(receipts), gethToUtilsWithdrawals(withdrawals)) + return utilsToGethBlock(block), err +} +func (ew *engineWrapper) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { + return ew.engine.Seal(&WrappedHeaderReader{chain, nil}, gethToUtilsBlock(block), gethToUtilsBlockChan(results), stop) +} +func (ew *engineWrapper) SealHash(header *types.Header) common.Hash { + return common.Hash(ew.engine.SealHash(gethToUtilsHeader(header))) +} +func (ew *engineWrapper) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { + return ew.engine.CalcDifficulty(&WrappedHeaderReader{chain, nil}, time, gethToUtilsHeader(parent)) +} +func (ew *engineWrapper) APIs(chain consensus.ChainHeaderReader) []rpc.API { + papis := ew.engine.APIs(&WrappedHeaderReader{chain, nil}) + apis := make([]rpc.API, len(papis)) + for i, api := range papis { + apis[i] = rpc.API{ + Namespace: api.Namespace, + Version: api.Version, + Service: api.Service, + Public: api.Public, + } + } + return apis +} +func (ew *engineWrapper) Close() error { + return ew.engine.Close() +}