github.com/shrimpyuk/bor@v0.2.15-0.20220224151350-fb4ec6020bae/cmd/evm/internal/t8ntool/transaction.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  	"encoding/json"
    21  	"errors"
    22  	"fmt"
    23  	"math/big"
    24  	"os"
    25  	"strings"
    26  
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/common/hexutil"
    29  	"github.com/ethereum/go-ethereum/core"
    30  	"github.com/ethereum/go-ethereum/core/types"
    31  	"github.com/ethereum/go-ethereum/log"
    32  	"github.com/ethereum/go-ethereum/params"
    33  	"github.com/ethereum/go-ethereum/rlp"
    34  	"github.com/ethereum/go-ethereum/tests"
    35  	"gopkg.in/urfave/cli.v1"
    36  )
    37  
    38  type result struct {
    39  	Error   error
    40  	Address common.Address
    41  	Hash    common.Hash
    42  }
    43  
    44  // MarshalJSON marshals as JSON with a hash.
    45  func (r *result) MarshalJSON() ([]byte, error) {
    46  	type xx struct {
    47  		Error   string          `json:"error,omitempty"`
    48  		Address *common.Address `json:"address,omitempty"`
    49  		Hash    *common.Hash    `json:"hash,omitempty"`
    50  	}
    51  	var out xx
    52  	if r.Error != nil {
    53  		out.Error = r.Error.Error()
    54  	}
    55  	if r.Address != (common.Address{}) {
    56  		out.Address = &r.Address
    57  	}
    58  	if r.Hash != (common.Hash{}) {
    59  		out.Hash = &r.Hash
    60  	}
    61  	return json.Marshal(out)
    62  }
    63  
    64  func Transaction(ctx *cli.Context) error {
    65  	// Configure the go-ethereum logger
    66  	glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
    67  	glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name)))
    68  	log.Root().SetHandler(glogger)
    69  
    70  	var (
    71  		err error
    72  	)
    73  	// We need to load the transactions. May be either in stdin input or in files.
    74  	// Check if anything needs to be read from stdin
    75  	var (
    76  		txStr       = ctx.String(InputTxsFlag.Name)
    77  		inputData   = &input{}
    78  		chainConfig *params.ChainConfig
    79  	)
    80  	// Construct the chainconfig
    81  	if cConf, _, err := tests.GetChainConfig(ctx.String(ForknameFlag.Name)); err != nil {
    82  		return NewError(ErrorVMConfig, fmt.Errorf("failed constructing chain configuration: %v", err))
    83  	} else {
    84  		chainConfig = cConf
    85  	}
    86  	// Set the chain id
    87  	chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name))
    88  	var body hexutil.Bytes
    89  	if txStr == stdinSelector {
    90  		decoder := json.NewDecoder(os.Stdin)
    91  		if err := decoder.Decode(inputData); err != nil {
    92  			return NewError(ErrorJson, fmt.Errorf("failed unmarshaling stdin: %v", err))
    93  		}
    94  		// Decode the body of already signed transactions
    95  		body = common.FromHex(inputData.TxRlp)
    96  	} else {
    97  		// Read input from file
    98  		inFile, err := os.Open(txStr)
    99  		if err != nil {
   100  			return NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err))
   101  		}
   102  		defer inFile.Close()
   103  		decoder := json.NewDecoder(inFile)
   104  		if strings.HasSuffix(txStr, ".rlp") {
   105  			if err := decoder.Decode(&body); err != nil {
   106  				return err
   107  			}
   108  		} else {
   109  			return NewError(ErrorIO, errors.New("only rlp supported"))
   110  		}
   111  	}
   112  	signer := types.MakeSigner(chainConfig, new(big.Int))
   113  	// We now have the transactions in 'body', which is supposed to be an
   114  	// rlp list of transactions
   115  	it, err := rlp.NewListIterator([]byte(body))
   116  	if err != nil {
   117  		return err
   118  	}
   119  	var results []result
   120  	for it.Next() {
   121  		var tx types.Transaction
   122  		err := rlp.DecodeBytes(it.Value(), &tx)
   123  		if err != nil {
   124  			results = append(results, result{Error: err})
   125  			continue
   126  		}
   127  		r := result{Hash: tx.Hash()}
   128  		if sender, err := types.Sender(signer, &tx); err != nil {
   129  			r.Error = err
   130  			results = append(results, r)
   131  			continue
   132  		} else {
   133  			r.Address = sender
   134  		}
   135  
   136  		if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil,
   137  			chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int))); err != nil {
   138  			r.Error = err
   139  		} else if tx.Gas() < gas {
   140  			r.Error = fmt.Errorf("%w: have %d, want %d", core.ErrIntrinsicGas, tx.Gas(), gas)
   141  		}
   142  		results = append(results, r)
   143  	}
   144  	out, err := json.MarshalIndent(results, "", "  ")
   145  	fmt.Println(string(out))
   146  	return err
   147  }