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