| 
									
										
										
										
											2021-09-13 13:57:40 +02:00
										 |  |  | // Copyright 2021 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of go-ethereum. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // go-ethereum is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // go-ethereum is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package t8ntool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"math/big" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common/hexutil" | 
					
						
							| 
									
										
										
										
											2021-10-11 12:30:13 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core" | 
					
						
							| 
									
										
										
										
											2021-09-13 13:57:40 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/params" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/rlp" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/tests" | 
					
						
							|  |  |  | 	"gopkg.in/urfave/cli.v1" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type result struct { | 
					
						
							| 
									
										
										
										
											2021-10-18 22:36:45 +02:00
										 |  |  | 	Error        error | 
					
						
							|  |  |  | 	Address      common.Address | 
					
						
							|  |  |  | 	Hash         common.Hash | 
					
						
							|  |  |  | 	IntrinsicGas uint64 | 
					
						
							| 
									
										
										
										
											2021-09-13 13:57:40 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MarshalJSON marshals as JSON with a hash. | 
					
						
							|  |  |  | func (r *result) MarshalJSON() ([]byte, error) { | 
					
						
							|  |  |  | 	type xx struct { | 
					
						
							| 
									
										
										
										
											2021-10-18 22:36:45 +02:00
										 |  |  | 		Error        string          `json:"error,omitempty"` | 
					
						
							|  |  |  | 		Address      *common.Address `json:"address,omitempty"` | 
					
						
							|  |  |  | 		Hash         *common.Hash    `json:"hash,omitempty"` | 
					
						
							|  |  |  | 		IntrinsicGas uint64          `json:"intrinsicGas,omitempty"` | 
					
						
							| 
									
										
										
										
											2021-09-13 13:57:40 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	var out xx | 
					
						
							|  |  |  | 	if r.Error != nil { | 
					
						
							|  |  |  | 		out.Error = r.Error.Error() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if r.Address != (common.Address{}) { | 
					
						
							|  |  |  | 		out.Address = &r.Address | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if r.Hash != (common.Hash{}) { | 
					
						
							|  |  |  | 		out.Hash = &r.Hash | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-18 22:36:45 +02:00
										 |  |  | 	out.IntrinsicGas = r.IntrinsicGas | 
					
						
							| 
									
										
										
										
											2021-09-13 13:57:40 +02:00
										 |  |  | 	return json.Marshal(out) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func Transaction(ctx *cli.Context) error { | 
					
						
							|  |  |  | 	// Configure the go-ethereum logger | 
					
						
							|  |  |  | 	glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) | 
					
						
							|  |  |  | 	glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) | 
					
						
							|  |  |  | 	log.Root().SetHandler(glogger) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		err error | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	// We need to load the transactions. May be either in stdin input or in files. | 
					
						
							|  |  |  | 	// Check if anything needs to be read from stdin | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		txStr       = ctx.String(InputTxsFlag.Name) | 
					
						
							|  |  |  | 		inputData   = &input{} | 
					
						
							|  |  |  | 		chainConfig *params.ChainConfig | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	// Construct the chainconfig | 
					
						
							|  |  |  | 	if cConf, _, err := tests.GetChainConfig(ctx.String(ForknameFlag.Name)); err != nil { | 
					
						
							|  |  |  | 		return NewError(ErrorVMConfig, fmt.Errorf("failed constructing chain configuration: %v", err)) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		chainConfig = cConf | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Set the chain id | 
					
						
							|  |  |  | 	chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name)) | 
					
						
							|  |  |  | 	var body hexutil.Bytes | 
					
						
							|  |  |  | 	if txStr == stdinSelector { | 
					
						
							|  |  |  | 		decoder := json.NewDecoder(os.Stdin) | 
					
						
							|  |  |  | 		if err := decoder.Decode(inputData); err != nil { | 
					
						
							|  |  |  | 			return NewError(ErrorJson, fmt.Errorf("failed unmarshaling stdin: %v", err)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Decode the body of already signed transactions | 
					
						
							|  |  |  | 		body = common.FromHex(inputData.TxRlp) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		// Read input from file | 
					
						
							|  |  |  | 		inFile, err := os.Open(txStr) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		defer inFile.Close() | 
					
						
							|  |  |  | 		decoder := json.NewDecoder(inFile) | 
					
						
							|  |  |  | 		if strings.HasSuffix(txStr, ".rlp") { | 
					
						
							|  |  |  | 			if err := decoder.Decode(&body); err != nil { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return NewError(ErrorIO, errors.New("only rlp supported")) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	signer := types.MakeSigner(chainConfig, new(big.Int)) | 
					
						
							|  |  |  | 	// We now have the transactions in 'body', which is supposed to be an | 
					
						
							|  |  |  | 	// rlp list of transactions | 
					
						
							|  |  |  | 	it, err := rlp.NewListIterator([]byte(body)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var results []result | 
					
						
							|  |  |  | 	for it.Next() { | 
					
						
							| 
									
										
										
										
											2021-10-27 13:28:50 +02:00
										 |  |  | 		if err := it.Err(); err != nil { | 
					
						
							|  |  |  | 			return NewError(ErrorIO, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-09-13 13:57:40 +02:00
										 |  |  | 		var tx types.Transaction | 
					
						
							|  |  |  | 		err := rlp.DecodeBytes(it.Value(), &tx) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			results = append(results, result{Error: err}) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-10-11 12:30:13 +02:00
										 |  |  | 		r := result{Hash: tx.Hash()} | 
					
						
							|  |  |  | 		if sender, err := types.Sender(signer, &tx); err != nil { | 
					
						
							|  |  |  | 			r.Error = err | 
					
						
							|  |  |  | 			results = append(results, r) | 
					
						
							| 
									
										
										
										
											2021-09-13 13:57:40 +02:00
										 |  |  | 			continue | 
					
						
							| 
									
										
										
										
											2021-10-11 12:30:13 +02:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			r.Address = sender | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-10-18 22:36:45 +02:00
										 |  |  | 		// Check intrinsic gas | 
					
						
							| 
									
										
										
										
											2021-10-11 12:30:13 +02:00
										 |  |  | 		if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, | 
					
						
							|  |  |  | 			chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int))); err != nil { | 
					
						
							|  |  |  | 			r.Error = err | 
					
						
							| 
									
										
										
										
											2021-10-18 22:36:45 +02:00
										 |  |  | 			results = append(results, r) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			r.IntrinsicGas = gas | 
					
						
							|  |  |  | 			if tx.Gas() < gas { | 
					
						
							|  |  |  | 				r.Error = fmt.Errorf("%w: have %d, want %d", core.ErrIntrinsicGas, tx.Gas(), gas) | 
					
						
							|  |  |  | 				results = append(results, r) | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Validate <256bit fields | 
					
						
							|  |  |  | 		switch { | 
					
						
							|  |  |  | 		case tx.Value().BitLen() > 256: | 
					
						
							|  |  |  | 			r.Error = errors.New("value exceeds 256 bits") | 
					
						
							|  |  |  | 		case tx.GasPrice().BitLen() > 256: | 
					
						
							|  |  |  | 			r.Error = errors.New("gasPrice exceeds 256 bits") | 
					
						
							|  |  |  | 		case tx.GasTipCap().BitLen() > 256: | 
					
						
							|  |  |  | 			r.Error = errors.New("maxPriorityFeePerGas exceeds 256 bits") | 
					
						
							|  |  |  | 		case tx.GasFeeCap().BitLen() > 256: | 
					
						
							|  |  |  | 			r.Error = errors.New("maxFeePerGas exceeds 256 bits") | 
					
						
							|  |  |  | 		case tx.GasFeeCap().Cmp(tx.GasTipCap()) < 0: | 
					
						
							|  |  |  | 			r.Error = errors.New("maxFeePerGas < maxPriorityFeePerGas") | 
					
						
							|  |  |  | 		case new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas())).BitLen() > 256: | 
					
						
							|  |  |  | 			r.Error = errors.New("gas * gasPrice exceeds 256 bits") | 
					
						
							|  |  |  | 		case new(big.Int).Mul(tx.GasFeeCap(), new(big.Int).SetUint64(tx.Gas())).BitLen() > 256: | 
					
						
							|  |  |  | 			r.Error = errors.New("gas * maxFeePerGas exceeds 256 bits") | 
					
						
							| 
									
										
										
										
											2021-09-13 13:57:40 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-10-11 12:30:13 +02:00
										 |  |  | 		results = append(results, r) | 
					
						
							| 
									
										
										
										
											2021-09-13 13:57:40 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	out, err := json.MarshalIndent(results, "", "  ") | 
					
						
							|  |  |  | 	fmt.Println(string(out)) | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } |