github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/cmd/evm/internal/t8ntool/block.go (about)

     1  // Copyright 2021 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package t8ntool
    18  
    19  import (
    20  	"context"
    21  	"crypto/ecdsa"
    22  	"encoding/json"
    23  	"errors"
    24  	"fmt"
    25  	"math/big"
    26  	"os"
    27  
    28  	"github.com/ethereum/go-ethereum/common"
    29  	"github.com/ethereum/go-ethereum/common/hexutil"
    30  	"github.com/ethereum/go-ethereum/common/math"
    31  	"github.com/ethereum/go-ethereum/consensus/clique"
    32  	"github.com/ethereum/go-ethereum/consensus/ethash"
    33  	"github.com/ethereum/go-ethereum/core/types"
    34  	"github.com/ethereum/go-ethereum/crypto"
    35  	"github.com/ethereum/go-ethereum/log"
    36  	"github.com/ethereum/go-ethereum/rlp"
    37  	"gopkg.in/urfave/cli.v1"
    38  )
    39  
    40  //go:generate gencodec -type header -field-override headerMarshaling -out gen_header.go
    41  type header struct {
    42  	ParentHash  common.Hash       `json:"parentHash"`
    43  	OmmerHash   *common.Hash      `json:"sha3Uncles"`
    44  	Coinbase    *common.Address   `json:"miner"`
    45  	Root        common.Hash       `json:"stateRoot"        gencodec:"required"`
    46  	TxHash      *common.Hash      `json:"transactionsRoot"`
    47  	ReceiptHash *common.Hash      `json:"receiptsRoot"`
    48  	Bloom       types.Bloom       `json:"logsBloom"`
    49  	Difficulty  *big.Int          `json:"difficulty"`
    50  	Number      *big.Int          `json:"number"           gencodec:"required"`
    51  	GasLimit    uint64            `json:"gasLimit"         gencodec:"required"`
    52  	GasUsed     uint64            `json:"gasUsed"`
    53  	Time        uint64            `json:"timestamp"        gencodec:"required"`
    54  	Extra       []byte            `json:"extraData"`
    55  	MixDigest   common.Hash       `json:"mixHash"`
    56  	Nonce       *types.BlockNonce `json:"nonce"`
    57  	BaseFee     *big.Int          `json:"baseFeePerGas" rlp:"optional"`
    58  }
    59  
    60  type headerMarshaling struct {
    61  	Difficulty *math.HexOrDecimal256
    62  	Number     *math.HexOrDecimal256
    63  	GasLimit   math.HexOrDecimal64
    64  	GasUsed    math.HexOrDecimal64
    65  	Time       math.HexOrDecimal64
    66  	Extra      hexutil.Bytes
    67  	BaseFee    *math.HexOrDecimal256
    68  }
    69  
    70  type bbInput struct {
    71  	Header    *header      `json:"header,omitempty"`
    72  	OmmersRlp []string     `json:"ommers,omitempty"`
    73  	TxRlp     string       `json:"txs,omitempty"`
    74  	Clique    *cliqueInput `json:"clique,omitempty"`
    75  
    76  	Ethash    bool                 `json:"-"`
    77  	EthashDir string               `json:"-"`
    78  	PowMode   ethash.Mode          `json:"-"`
    79  	Txs       []*types.Transaction `json:"-"`
    80  	Ommers    []*types.Header      `json:"-"`
    81  }
    82  
    83  type cliqueInput struct {
    84  	Key       *ecdsa.PrivateKey
    85  	Voted     *common.Address
    86  	Authorize *bool
    87  	Vanity    common.Hash
    88  }
    89  
    90  // UnmarshalJSON implements json.Unmarshaler interface.
    91  func (c *cliqueInput) UnmarshalJSON(input []byte) error {
    92  	var x struct {
    93  		Key       *common.Hash    `json:"secretKey"`
    94  		Voted     *common.Address `json:"voted"`
    95  		Authorize *bool           `json:"authorize"`
    96  		Vanity    common.Hash     `json:"vanity"`
    97  	}
    98  	if err := json.Unmarshal(input, &x); err != nil {
    99  		return err
   100  	}
   101  	if x.Key == nil {
   102  		return errors.New("missing required field 'secretKey' for cliqueInput")
   103  	}
   104  	if ecdsaKey, err := crypto.ToECDSA(x.Key[:]); err != nil {
   105  		return err
   106  	} else {
   107  		c.Key = ecdsaKey
   108  	}
   109  	c.Voted = x.Voted
   110  	c.Authorize = x.Authorize
   111  	c.Vanity = x.Vanity
   112  	return nil
   113  }
   114  
   115  // ToBlock converts i into a *types.Block
   116  func (i *bbInput) ToBlock() *types.Block {
   117  	header := &types.Header{
   118  		ParentHash:  i.Header.ParentHash,
   119  		UncleHash:   types.EmptyUncleHash,
   120  		Coinbase:    common.Address{},
   121  		Root:        i.Header.Root,
   122  		TxHash:      types.EmptyRootHash,
   123  		ReceiptHash: types.EmptyRootHash,
   124  		Bloom:       i.Header.Bloom,
   125  		Difficulty:  common.Big0,
   126  		Number:      i.Header.Number,
   127  		GasLimit:    i.Header.GasLimit,
   128  		GasUsed:     i.Header.GasUsed,
   129  		Time:        i.Header.Time,
   130  		Extra:       i.Header.Extra,
   131  		MixDigest:   i.Header.MixDigest,
   132  		BaseFee:     i.Header.BaseFee,
   133  	}
   134  
   135  	// Fill optional values.
   136  	if i.Header.OmmerHash != nil {
   137  		header.UncleHash = *i.Header.OmmerHash
   138  	} else if len(i.Ommers) != 0 {
   139  		// Calculate the ommer hash if none is provided and there are ommers to hash
   140  		header.UncleHash = types.CalcUncleHash(i.Ommers)
   141  	}
   142  	if i.Header.Coinbase != nil {
   143  		header.Coinbase = *i.Header.Coinbase
   144  	}
   145  	if i.Header.TxHash != nil {
   146  		header.TxHash = *i.Header.TxHash
   147  	}
   148  	if i.Header.ReceiptHash != nil {
   149  		header.ReceiptHash = *i.Header.ReceiptHash
   150  	}
   151  	if i.Header.Nonce != nil {
   152  		header.Nonce = *i.Header.Nonce
   153  	}
   154  	if header.Difficulty != nil {
   155  		header.Difficulty = i.Header.Difficulty
   156  	}
   157  	return types.NewBlockWithHeader(header).WithBody(i.Txs, i.Ommers)
   158  }
   159  
   160  // SealBlock seals the given block using the configured engine.
   161  func (i *bbInput) SealBlock(block *types.Block) (*types.Block, error) {
   162  	switch {
   163  	case i.Ethash:
   164  		return i.sealEthash(block)
   165  	case i.Clique != nil:
   166  		return i.sealClique(block)
   167  	default:
   168  		return block, nil
   169  	}
   170  }
   171  
   172  // sealEthash seals the given block using ethash.
   173  func (i *bbInput) sealEthash(block *types.Block) (*types.Block, error) {
   174  	if i.Header.Nonce != nil {
   175  		return nil, NewError(ErrorConfig, fmt.Errorf("sealing with ethash will overwrite provided nonce"))
   176  	}
   177  	ethashConfig := ethash.Config{
   178  		PowMode:        i.PowMode,
   179  		DatasetDir:     i.EthashDir,
   180  		CacheDir:       i.EthashDir,
   181  		DatasetsInMem:  1,
   182  		DatasetsOnDisk: 2,
   183  		CachesInMem:    2,
   184  		CachesOnDisk:   3,
   185  	}
   186  	engine := ethash.New(ethashConfig, nil, true)
   187  	defer engine.Close()
   188  	// Use a buffered chan for results.
   189  	// If the testmode is used, the sealer will return quickly, and complain
   190  	// "Sealing result is not read by miner" if it cannot write the result.
   191  	results := make(chan *types.Block, 1)
   192  	if err := engine.Seal(context.Background(), nil, block, results, nil); err != nil {
   193  		panic(fmt.Sprintf("failed to seal block: %v", err))
   194  	}
   195  	found := <-results
   196  	return block.WithSeal(found.Header()), nil
   197  }
   198  
   199  // sealClique seals the given block using clique.
   200  func (i *bbInput) sealClique(block *types.Block) (*types.Block, error) {
   201  	// If any clique value overwrites an explicit header value, fail
   202  	// to avoid silently building a block with unexpected values.
   203  	if i.Header.Extra != nil {
   204  		return nil, NewError(ErrorConfig, fmt.Errorf("sealing with clique will overwrite provided extra data"))
   205  	}
   206  	header := block.Header()
   207  	if i.Clique.Voted != nil {
   208  		if i.Header.Coinbase != nil {
   209  			return nil, NewError(ErrorConfig, fmt.Errorf("sealing with clique and voting will overwrite provided coinbase"))
   210  		}
   211  		header.Coinbase = *i.Clique.Voted
   212  	}
   213  	if i.Clique.Authorize != nil {
   214  		if i.Header.Nonce != nil {
   215  			return nil, NewError(ErrorConfig, fmt.Errorf("sealing with clique and voting will overwrite provided nonce"))
   216  		}
   217  		if *i.Clique.Authorize {
   218  			header.Nonce = [8]byte{}
   219  		} else {
   220  			header.Nonce = [8]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
   221  		}
   222  	}
   223  	// Extra is fixed 32 byte vanity and 65 byte signature
   224  	header.Extra = make([]byte, 32+65)
   225  	copy(header.Extra[0:32], i.Clique.Vanity.Bytes()[:])
   226  
   227  	// Sign the seal hash and fill in the rest of the extra data
   228  	h := clique.SealHash(header)
   229  	sighash, err := crypto.Sign(h[:], i.Clique.Key)
   230  	if err != nil {
   231  		return nil, err
   232  	}
   233  	copy(header.Extra[32:], sighash)
   234  	block = block.WithSeal(header)
   235  	return block, nil
   236  }
   237  
   238  // BuildBlock constructs a block from the given inputs.
   239  func BuildBlock(ctx *cli.Context) error {
   240  	// Configure the go-ethereum logger
   241  	glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
   242  	glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name)))
   243  	log.Root().SetHandler(glogger)
   244  
   245  	baseDir, err := createBasedir(ctx)
   246  	if err != nil {
   247  		return NewError(ErrorIO, fmt.Errorf("failed creating output basedir: %v", err))
   248  	}
   249  	inputData, err := readInput(ctx)
   250  	if err != nil {
   251  		return err
   252  	}
   253  	block := inputData.ToBlock()
   254  	block, err = inputData.SealBlock(block)
   255  	if err != nil {
   256  		return err
   257  	}
   258  	return dispatchBlock(ctx, baseDir, block)
   259  }
   260  
   261  func readInput(ctx *cli.Context) (*bbInput, error) {
   262  	var (
   263  		headerStr  = ctx.String(InputHeaderFlag.Name)
   264  		ommersStr  = ctx.String(InputOmmersFlag.Name)
   265  		txsStr     = ctx.String(InputTxsRlpFlag.Name)
   266  		cliqueStr  = ctx.String(SealCliqueFlag.Name)
   267  		ethashOn   = ctx.Bool(SealEthashFlag.Name)
   268  		ethashDir  = ctx.String(SealEthashDirFlag.Name)
   269  		ethashMode = ctx.String(SealEthashModeFlag.Name)
   270  		inputData  = &bbInput{}
   271  	)
   272  	if ethashOn && cliqueStr != "" {
   273  		return nil, NewError(ErrorConfig, fmt.Errorf("both ethash and clique sealing specified, only one may be chosen"))
   274  	}
   275  	if ethashOn {
   276  		inputData.Ethash = ethashOn
   277  		inputData.EthashDir = ethashDir
   278  		switch ethashMode {
   279  		case "normal":
   280  			inputData.PowMode = ethash.ModeNormal
   281  		case "test":
   282  			inputData.PowMode = ethash.ModeTest
   283  		case "fake":
   284  			inputData.PowMode = ethash.ModeFake
   285  		default:
   286  			return nil, NewError(ErrorConfig, fmt.Errorf("unknown pow mode: %s, supported modes: test, fake, normal", ethashMode))
   287  		}
   288  	}
   289  	if headerStr == stdinSelector || ommersStr == stdinSelector || txsStr == stdinSelector || cliqueStr == stdinSelector {
   290  		decoder := json.NewDecoder(os.Stdin)
   291  		if err := decoder.Decode(inputData); err != nil {
   292  			return nil, NewError(ErrorJson, fmt.Errorf("failed unmarshaling stdin: %v", err))
   293  		}
   294  	}
   295  	if cliqueStr != stdinSelector && cliqueStr != "" {
   296  		var clique cliqueInput
   297  		if err := readFile(cliqueStr, "clique", &clique); err != nil {
   298  			return nil, err
   299  		}
   300  		inputData.Clique = &clique
   301  	}
   302  	if headerStr != stdinSelector {
   303  		var env header
   304  		if err := readFile(headerStr, "header", &env); err != nil {
   305  			return nil, err
   306  		}
   307  		inputData.Header = &env
   308  	}
   309  	if ommersStr != stdinSelector && ommersStr != "" {
   310  		var ommers []string
   311  		if err := readFile(ommersStr, "ommers", &ommers); err != nil {
   312  			return nil, err
   313  		}
   314  		inputData.OmmersRlp = ommers
   315  	}
   316  	if txsStr != stdinSelector {
   317  		var txs string
   318  		if err := readFile(txsStr, "txs", &txs); err != nil {
   319  			return nil, err
   320  		}
   321  		inputData.TxRlp = txs
   322  	}
   323  	// Deserialize rlp txs and ommers
   324  	var (
   325  		ommers = []*types.Header{}
   326  		txs    = []*types.Transaction{}
   327  	)
   328  	if inputData.TxRlp != "" {
   329  		if err := rlp.DecodeBytes(common.FromHex(inputData.TxRlp), &txs); err != nil {
   330  			return nil, NewError(ErrorRlp, fmt.Errorf("unable to decode transaction from rlp data: %v", err))
   331  		}
   332  		inputData.Txs = txs
   333  	}
   334  	for _, str := range inputData.OmmersRlp {
   335  		type extblock struct {
   336  			Header *types.Header
   337  			Txs    []*types.Transaction
   338  			Ommers []*types.Header
   339  		}
   340  		var ommer *extblock
   341  		if err := rlp.DecodeBytes(common.FromHex(str), &ommer); err != nil {
   342  			return nil, NewError(ErrorRlp, fmt.Errorf("unable to decode ommer from rlp data: %v", err))
   343  		}
   344  		ommers = append(ommers, ommer.Header)
   345  	}
   346  	inputData.Ommers = ommers
   347  
   348  	return inputData, nil
   349  }
   350  
   351  // dispatchOutput writes the output data to either stderr or stdout, or to the specified
   352  // files
   353  func dispatchBlock(ctx *cli.Context, baseDir string, block *types.Block) error {
   354  	raw, _ := rlp.EncodeToBytes(block)
   355  
   356  	type blockInfo struct {
   357  		Rlp  hexutil.Bytes `json:"rlp"`
   358  		Hash common.Hash   `json:"hash"`
   359  	}
   360  	var enc blockInfo
   361  	enc.Rlp = raw
   362  	enc.Hash = block.Hash()
   363  
   364  	b, err := json.MarshalIndent(enc, "", "  ")
   365  	if err != nil {
   366  		return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err))
   367  	}
   368  	switch dest := ctx.String(OutputBlockFlag.Name); dest {
   369  	case "stdout":
   370  		os.Stdout.Write(b)
   371  		os.Stdout.WriteString("\n")
   372  	case "stderr":
   373  		os.Stderr.Write(b)
   374  		os.Stderr.WriteString("\n")
   375  	default:
   376  		if err := saveFile(baseDir, dest, enc); err != nil {
   377  			return err
   378  		}
   379  	}
   380  	return nil
   381  }