github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/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  	"crypto/ecdsa"
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	"math/big"
    25  	"os"
    26  
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/common/hexutil"
    29  	"github.com/ethereum/go-ethereum/common/math"
    30  	"github.com/ethereum/go-ethereum/consensus/clique"
    31  	"github.com/ethereum/go-ethereum/core/types"
    32  	"github.com/ethereum/go-ethereum/crypto"
    33  	"github.com/ethereum/go-ethereum/rlp"
    34  	"github.com/urfave/cli/v2"
    35  )
    36  
    37  //go:generate go run github.com/fjl/gencodec -type header -field-override headerMarshaling -out gen_header.go
    38  type header struct {
    39  	ParentHash            common.Hash       `json:"parentHash"`
    40  	OmmerHash             *common.Hash      `json:"sha3Uncles"`
    41  	Coinbase              *common.Address   `json:"miner"`
    42  	Root                  common.Hash       `json:"stateRoot"        gencodec:"required"`
    43  	TxHash                *common.Hash      `json:"transactionsRoot"`
    44  	ReceiptHash           *common.Hash      `json:"receiptsRoot"`
    45  	Bloom                 types.Bloom       `json:"logsBloom"`
    46  	Difficulty            *big.Int          `json:"difficulty"`
    47  	Number                *big.Int          `json:"number"           gencodec:"required"`
    48  	GasLimit              uint64            `json:"gasLimit"         gencodec:"required"`
    49  	GasUsed               uint64            `json:"gasUsed"`
    50  	Time                  uint64            `json:"timestamp"        gencodec:"required"`
    51  	Extra                 []byte            `json:"extraData"`
    52  	MixDigest             common.Hash       `json:"mixHash"`
    53  	Nonce                 *types.BlockNonce `json:"nonce"`
    54  	BaseFee               *big.Int          `json:"baseFeePerGas" rlp:"optional"`
    55  	WithdrawalsHash       *common.Hash      `json:"withdrawalsRoot" rlp:"optional"`
    56  	BlobGasUsed           *uint64           `json:"blobGasUsed"   rlp:"optional"`
    57  	ExcessBlobGas         *uint64           `json:"excessBlobGas"   rlp:"optional"`
    58  	ParentBeaconBlockRoot *common.Hash      `json:"parentBeaconBlockRoot" rlp:"optional"`
    59  }
    60  
    61  type headerMarshaling struct {
    62  	Difficulty    *math.HexOrDecimal256
    63  	Number        *math.HexOrDecimal256
    64  	GasLimit      math.HexOrDecimal64
    65  	GasUsed       math.HexOrDecimal64
    66  	Time          math.HexOrDecimal64
    67  	Extra         hexutil.Bytes
    68  	BaseFee       *math.HexOrDecimal256
    69  	BlobGasUsed   *math.HexOrDecimal64
    70  	ExcessBlobGas *math.HexOrDecimal64
    71  }
    72  
    73  type bbInput struct {
    74  	Header      *header             `json:"header,omitempty"`
    75  	OmmersRlp   []string            `json:"ommers,omitempty"`
    76  	TxRlp       string              `json:"txs,omitempty"`
    77  	Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
    78  	Clique      *cliqueInput        `json:"clique,omitempty"`
    79  
    80  	Ethash bool                 `json:"-"`
    81  	Txs    []*types.Transaction `json:"-"`
    82  	Ommers []*types.Header      `json:"-"`
    83  }
    84  
    85  type cliqueInput struct {
    86  	Key       *ecdsa.PrivateKey
    87  	Voted     *common.Address
    88  	Authorize *bool
    89  	Vanity    common.Hash
    90  }
    91  
    92  // UnmarshalJSON implements json.Unmarshaler interface.
    93  func (c *cliqueInput) UnmarshalJSON(input []byte) error {
    94  	var x struct {
    95  		Key       *common.Hash    `json:"secretKey"`
    96  		Voted     *common.Address `json:"voted"`
    97  		Authorize *bool           `json:"authorize"`
    98  		Vanity    common.Hash     `json:"vanity"`
    99  	}
   100  	if err := json.Unmarshal(input, &x); err != nil {
   101  		return err
   102  	}
   103  	if x.Key == nil {
   104  		return errors.New("missing required field 'secretKey' for cliqueInput")
   105  	}
   106  	if ecdsaKey, err := crypto.ToECDSA(x.Key[:]); err != nil {
   107  		return err
   108  	} else {
   109  		c.Key = ecdsaKey
   110  	}
   111  	c.Voted = x.Voted
   112  	c.Authorize = x.Authorize
   113  	c.Vanity = x.Vanity
   114  	return nil
   115  }
   116  
   117  // ToBlock converts i into a *types.Block
   118  func (i *bbInput) ToBlock() *types.Block {
   119  	header := &types.Header{
   120  		ParentHash:       i.Header.ParentHash,
   121  		UncleHash:        types.EmptyUncleHash,
   122  		Coinbase:         common.Address{},
   123  		Root:             i.Header.Root,
   124  		TxHash:           types.EmptyTxsHash,
   125  		ReceiptHash:      types.EmptyReceiptsHash,
   126  		Bloom:            i.Header.Bloom,
   127  		Difficulty:       common.Big0,
   128  		Number:           i.Header.Number,
   129  		GasLimit:         i.Header.GasLimit,
   130  		GasUsed:          i.Header.GasUsed,
   131  		Time:             i.Header.Time,
   132  		Extra:            i.Header.Extra,
   133  		MixDigest:        i.Header.MixDigest,
   134  		BaseFee:          i.Header.BaseFee,
   135  		WithdrawalsHash:  i.Header.WithdrawalsHash,
   136  		BlobGasUsed:      i.Header.BlobGasUsed,
   137  		ExcessBlobGas:    i.Header.ExcessBlobGas,
   138  		ParentBeaconRoot: i.Header.ParentBeaconBlockRoot,
   139  	}
   140  
   141  	// Fill optional values.
   142  	if i.Header.OmmerHash != nil {
   143  		header.UncleHash = *i.Header.OmmerHash
   144  	} else if len(i.Ommers) != 0 {
   145  		// Calculate the ommer hash if none is provided and there are ommers to hash
   146  		header.UncleHash = types.CalcUncleHash(i.Ommers)
   147  	}
   148  	if i.Header.Coinbase != nil {
   149  		header.Coinbase = *i.Header.Coinbase
   150  	}
   151  	if i.Header.TxHash != nil {
   152  		header.TxHash = *i.Header.TxHash
   153  	}
   154  	if i.Header.ReceiptHash != nil {
   155  		header.ReceiptHash = *i.Header.ReceiptHash
   156  	}
   157  	if i.Header.Nonce != nil {
   158  		header.Nonce = *i.Header.Nonce
   159  	}
   160  	if i.Header.Difficulty != nil {
   161  		header.Difficulty = i.Header.Difficulty
   162  	}
   163  	return types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: i.Txs, Uncles: i.Ommers, Withdrawals: i.Withdrawals})
   164  }
   165  
   166  // SealBlock seals the given block using the configured engine.
   167  func (i *bbInput) SealBlock(block *types.Block) (*types.Block, error) {
   168  	switch {
   169  	case i.Clique != nil:
   170  		return i.sealClique(block)
   171  	default:
   172  		return block, nil
   173  	}
   174  }
   175  
   176  // sealClique seals the given block using clique.
   177  func (i *bbInput) sealClique(block *types.Block) (*types.Block, error) {
   178  	// If any clique value overwrites an explicit header value, fail
   179  	// to avoid silently building a block with unexpected values.
   180  	if i.Header.Extra != nil {
   181  		return nil, NewError(ErrorConfig, errors.New("sealing with clique will overwrite provided extra data"))
   182  	}
   183  	header := block.Header()
   184  	if i.Clique.Voted != nil {
   185  		if i.Header.Coinbase != nil {
   186  			return nil, NewError(ErrorConfig, errors.New("sealing with clique and voting will overwrite provided coinbase"))
   187  		}
   188  		header.Coinbase = *i.Clique.Voted
   189  	}
   190  	if i.Clique.Authorize != nil {
   191  		if i.Header.Nonce != nil {
   192  			return nil, NewError(ErrorConfig, errors.New("sealing with clique and voting will overwrite provided nonce"))
   193  		}
   194  		if *i.Clique.Authorize {
   195  			header.Nonce = [8]byte{}
   196  		} else {
   197  			header.Nonce = [8]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
   198  		}
   199  	}
   200  	// Extra is fixed 32 byte vanity and 65 byte signature
   201  	header.Extra = make([]byte, 32+65)
   202  	copy(header.Extra[0:32], i.Clique.Vanity.Bytes()[:])
   203  
   204  	// Sign the seal hash and fill in the rest of the extra data
   205  	h := clique.SealHash(header)
   206  	sighash, err := crypto.Sign(h[:], i.Clique.Key)
   207  	if err != nil {
   208  		return nil, err
   209  	}
   210  	copy(header.Extra[32:], sighash)
   211  	block = block.WithSeal(header)
   212  	return block, nil
   213  }
   214  
   215  // BuildBlock constructs a block from the given inputs.
   216  func BuildBlock(ctx *cli.Context) error {
   217  	baseDir, err := createBasedir(ctx)
   218  	if err != nil {
   219  		return NewError(ErrorIO, fmt.Errorf("failed creating output basedir: %v", err))
   220  	}
   221  	inputData, err := readInput(ctx)
   222  	if err != nil {
   223  		return err
   224  	}
   225  	block := inputData.ToBlock()
   226  	block, err = inputData.SealBlock(block)
   227  	if err != nil {
   228  		return err
   229  	}
   230  	return dispatchBlock(ctx, baseDir, block)
   231  }
   232  
   233  func readInput(ctx *cli.Context) (*bbInput, error) {
   234  	var (
   235  		headerStr      = ctx.String(InputHeaderFlag.Name)
   236  		ommersStr      = ctx.String(InputOmmersFlag.Name)
   237  		withdrawalsStr = ctx.String(InputWithdrawalsFlag.Name)
   238  		txsStr         = ctx.String(InputTxsRlpFlag.Name)
   239  		cliqueStr      = ctx.String(SealCliqueFlag.Name)
   240  		inputData      = &bbInput{}
   241  	)
   242  	if headerStr == stdinSelector || ommersStr == stdinSelector || txsStr == stdinSelector || cliqueStr == stdinSelector {
   243  		decoder := json.NewDecoder(os.Stdin)
   244  		if err := decoder.Decode(inputData); err != nil {
   245  			return nil, NewError(ErrorJson, fmt.Errorf("failed unmarshalling stdin: %v", err))
   246  		}
   247  	}
   248  	if cliqueStr != stdinSelector && cliqueStr != "" {
   249  		var clique cliqueInput
   250  		if err := readFile(cliqueStr, "clique", &clique); err != nil {
   251  			return nil, err
   252  		}
   253  		inputData.Clique = &clique
   254  	}
   255  	if headerStr != stdinSelector {
   256  		var env header
   257  		if err := readFile(headerStr, "header", &env); err != nil {
   258  			return nil, err
   259  		}
   260  		inputData.Header = &env
   261  	}
   262  	if ommersStr != stdinSelector && ommersStr != "" {
   263  		var ommers []string
   264  		if err := readFile(ommersStr, "ommers", &ommers); err != nil {
   265  			return nil, err
   266  		}
   267  		inputData.OmmersRlp = ommers
   268  	}
   269  	if withdrawalsStr != stdinSelector && withdrawalsStr != "" {
   270  		var withdrawals []*types.Withdrawal
   271  		if err := readFile(withdrawalsStr, "withdrawals", &withdrawals); err != nil {
   272  			return nil, err
   273  		}
   274  		inputData.Withdrawals = withdrawals
   275  	}
   276  	if txsStr != stdinSelector {
   277  		var txs string
   278  		if err := readFile(txsStr, "txs", &txs); err != nil {
   279  			return nil, err
   280  		}
   281  		inputData.TxRlp = txs
   282  	}
   283  	// Deserialize rlp txs and ommers
   284  	var (
   285  		ommers = []*types.Header{}
   286  		txs    = []*types.Transaction{}
   287  	)
   288  	if inputData.TxRlp != "" {
   289  		if err := rlp.DecodeBytes(common.FromHex(inputData.TxRlp), &txs); err != nil {
   290  			return nil, NewError(ErrorRlp, fmt.Errorf("unable to decode transaction from rlp data: %v", err))
   291  		}
   292  		inputData.Txs = txs
   293  	}
   294  	for _, str := range inputData.OmmersRlp {
   295  		type extblock struct {
   296  			Header *types.Header
   297  			Txs    []*types.Transaction
   298  			Ommers []*types.Header
   299  		}
   300  		var ommer *extblock
   301  		if err := rlp.DecodeBytes(common.FromHex(str), &ommer); err != nil {
   302  			return nil, NewError(ErrorRlp, fmt.Errorf("unable to decode ommer from rlp data: %v", err))
   303  		}
   304  		ommers = append(ommers, ommer.Header)
   305  	}
   306  	inputData.Ommers = ommers
   307  
   308  	return inputData, nil
   309  }
   310  
   311  // dispatchBlock writes the output data to either stderr or stdout, or to the specified
   312  // files
   313  func dispatchBlock(ctx *cli.Context, baseDir string, block *types.Block) error {
   314  	raw, _ := rlp.EncodeToBytes(block)
   315  	type blockInfo struct {
   316  		Rlp  hexutil.Bytes `json:"rlp"`
   317  		Hash common.Hash   `json:"hash"`
   318  	}
   319  	enc := blockInfo{
   320  		Rlp:  raw,
   321  		Hash: block.Hash(),
   322  	}
   323  	b, err := json.MarshalIndent(enc, "", "  ")
   324  	if err != nil {
   325  		return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err))
   326  	}
   327  	switch dest := ctx.String(OutputBlockFlag.Name); dest {
   328  	case "stdout":
   329  		os.Stdout.Write(b)
   330  		os.Stdout.WriteString("\n")
   331  	case "stderr":
   332  		os.Stderr.Write(b)
   333  		os.Stderr.WriteString("\n")
   334  	default:
   335  		if err := saveFile(baseDir, dest, enc); err != nil {
   336  			return err
   337  		}
   338  	}
   339  	return nil
   340  }