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