transition.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. // Copyright 2020 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. package t8ntool
  17. import (
  18. "crypto/ecdsa"
  19. "encoding/json"
  20. "errors"
  21. "fmt"
  22. "math/big"
  23. "os"
  24. "path"
  25. "strings"
  26. "github.com/ethereum/go-ethereum/common"
  27. "github.com/ethereum/go-ethereum/common/hexutil"
  28. "github.com/ethereum/go-ethereum/core"
  29. "github.com/ethereum/go-ethereum/core/state"
  30. "github.com/ethereum/go-ethereum/core/types"
  31. "github.com/ethereum/go-ethereum/core/vm"
  32. "github.com/ethereum/go-ethereum/crypto"
  33. "github.com/ethereum/go-ethereum/eth/tracers/logger"
  34. "github.com/ethereum/go-ethereum/log"
  35. "github.com/ethereum/go-ethereum/params"
  36. "github.com/ethereum/go-ethereum/rlp"
  37. "github.com/ethereum/go-ethereum/tests"
  38. "github.com/urfave/cli/v2"
  39. )
  40. const (
  41. ErrorEVM = 2
  42. ErrorConfig = 3
  43. ErrorMissingBlockhash = 4
  44. ErrorJson = 10
  45. ErrorIO = 11
  46. ErrorRlp = 12
  47. stdinSelector = "stdin"
  48. )
  49. type NumberedError struct {
  50. errorCode int
  51. err error
  52. }
  53. func NewError(errorCode int, err error) *NumberedError {
  54. return &NumberedError{errorCode, err}
  55. }
  56. func (n *NumberedError) Error() string {
  57. return fmt.Sprintf("ERROR(%d): %v", n.errorCode, n.err.Error())
  58. }
  59. func (n *NumberedError) ExitCode() int {
  60. return n.errorCode
  61. }
  62. // compile-time conformance test
  63. var (
  64. _ cli.ExitCoder = (*NumberedError)(nil)
  65. )
  66. type input struct {
  67. Alloc core.GenesisAlloc `json:"alloc,omitempty"`
  68. Env *stEnv `json:"env,omitempty"`
  69. Txs []*txWithKey `json:"txs,omitempty"`
  70. TxRlp string `json:"txsRlp,omitempty"`
  71. }
  72. func Transition(ctx *cli.Context) error {
  73. // Configure the go-ethereum logger
  74. glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
  75. glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name)))
  76. log.Root().SetHandler(glogger)
  77. var (
  78. err error
  79. tracer vm.EVMLogger
  80. )
  81. var getTracer func(txIndex int, txHash common.Hash) (vm.EVMLogger, error)
  82. baseDir, err := createBasedir(ctx)
  83. if err != nil {
  84. return NewError(ErrorIO, fmt.Errorf("failed creating output basedir: %v", err))
  85. }
  86. if ctx.Bool(TraceFlag.Name) {
  87. if ctx.IsSet(TraceDisableMemoryFlag.Name) && ctx.IsSet(TraceEnableMemoryFlag.Name) {
  88. return NewError(ErrorConfig, fmt.Errorf("can't use both flags --%s and --%s", TraceDisableMemoryFlag.Name, TraceEnableMemoryFlag.Name))
  89. }
  90. if ctx.IsSet(TraceDisableReturnDataFlag.Name) && ctx.IsSet(TraceEnableReturnDataFlag.Name) {
  91. return NewError(ErrorConfig, fmt.Errorf("can't use both flags --%s and --%s", TraceDisableReturnDataFlag.Name, TraceEnableReturnDataFlag.Name))
  92. }
  93. if ctx.IsSet(TraceDisableMemoryFlag.Name) {
  94. log.Warn(fmt.Sprintf("--%s has been deprecated in favour of --%s", TraceDisableMemoryFlag.Name, TraceEnableMemoryFlag.Name))
  95. }
  96. if ctx.IsSet(TraceDisableReturnDataFlag.Name) {
  97. log.Warn(fmt.Sprintf("--%s has been deprecated in favour of --%s", TraceDisableReturnDataFlag.Name, TraceEnableReturnDataFlag.Name))
  98. }
  99. // Configure the EVM logger
  100. logConfig := &logger.Config{
  101. DisableStack: ctx.Bool(TraceDisableStackFlag.Name),
  102. EnableMemory: !ctx.Bool(TraceDisableMemoryFlag.Name) || ctx.Bool(TraceEnableMemoryFlag.Name),
  103. EnableReturnData: !ctx.Bool(TraceDisableReturnDataFlag.Name) || ctx.Bool(TraceEnableReturnDataFlag.Name),
  104. Debug: true,
  105. }
  106. var prevFile *os.File
  107. // This one closes the last file
  108. defer func() {
  109. if prevFile != nil {
  110. prevFile.Close()
  111. }
  112. }()
  113. getTracer = func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) {
  114. if prevFile != nil {
  115. prevFile.Close()
  116. }
  117. traceFile, err := os.Create(path.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String())))
  118. if err != nil {
  119. return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err))
  120. }
  121. prevFile = traceFile
  122. return logger.NewJSONLogger(logConfig, traceFile), nil
  123. }
  124. } else {
  125. getTracer = func(txIndex int, txHash common.Hash) (tracer vm.EVMLogger, err error) {
  126. return nil, nil
  127. }
  128. }
  129. // We need to load three things: alloc, env and transactions. May be either in
  130. // stdin input or in files.
  131. // Check if anything needs to be read from stdin
  132. var (
  133. prestate Prestate
  134. txs types.Transactions // txs to apply
  135. allocStr = ctx.String(InputAllocFlag.Name)
  136. envStr = ctx.String(InputEnvFlag.Name)
  137. txStr = ctx.String(InputTxsFlag.Name)
  138. inputData = &input{}
  139. )
  140. // Figure out the prestate alloc
  141. if allocStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector {
  142. decoder := json.NewDecoder(os.Stdin)
  143. if err := decoder.Decode(inputData); err != nil {
  144. return NewError(ErrorJson, fmt.Errorf("failed unmarshaling stdin: %v", err))
  145. }
  146. }
  147. if allocStr != stdinSelector {
  148. if err := readFile(allocStr, "alloc", &inputData.Alloc); err != nil {
  149. return err
  150. }
  151. }
  152. prestate.Pre = inputData.Alloc
  153. // Set the block environment
  154. if envStr != stdinSelector {
  155. var env stEnv
  156. if err := readFile(envStr, "env", &env); err != nil {
  157. return err
  158. }
  159. inputData.Env = &env
  160. }
  161. prestate.Env = *inputData.Env
  162. vmConfig := vm.Config{
  163. Tracer: tracer,
  164. Debug: (tracer != nil),
  165. }
  166. // Construct the chainconfig
  167. var chainConfig *params.ChainConfig
  168. if cConf, extraEips, err := tests.GetChainConfig(ctx.String(ForknameFlag.Name)); err != nil {
  169. return NewError(ErrorConfig, fmt.Errorf("failed constructing chain configuration: %v", err))
  170. } else {
  171. chainConfig = cConf
  172. vmConfig.ExtraEips = extraEips
  173. }
  174. // Set the chain id
  175. chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name))
  176. var txsWithKeys []*txWithKey
  177. if txStr != stdinSelector {
  178. inFile, err := os.Open(txStr)
  179. if err != nil {
  180. return NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err))
  181. }
  182. defer inFile.Close()
  183. decoder := json.NewDecoder(inFile)
  184. if strings.HasSuffix(txStr, ".rlp") {
  185. var body hexutil.Bytes
  186. if err := decoder.Decode(&body); err != nil {
  187. return err
  188. }
  189. var txs types.Transactions
  190. if err := rlp.DecodeBytes(body, &txs); err != nil {
  191. return err
  192. }
  193. for _, tx := range txs {
  194. txsWithKeys = append(txsWithKeys, &txWithKey{
  195. key: nil,
  196. tx: tx,
  197. })
  198. }
  199. } else {
  200. if err := decoder.Decode(&txsWithKeys); err != nil {
  201. return NewError(ErrorJson, fmt.Errorf("failed unmarshaling txs-file: %v", err))
  202. }
  203. }
  204. } else {
  205. if len(inputData.TxRlp) > 0 {
  206. // Decode the body of already signed transactions
  207. body := common.FromHex(inputData.TxRlp)
  208. var txs types.Transactions
  209. if err := rlp.DecodeBytes(body, &txs); err != nil {
  210. return err
  211. }
  212. for _, tx := range txs {
  213. txsWithKeys = append(txsWithKeys, &txWithKey{
  214. key: nil,
  215. tx: tx,
  216. })
  217. }
  218. } else {
  219. // JSON encoded transactions
  220. txsWithKeys = inputData.Txs
  221. }
  222. }
  223. // We may have to sign the transactions.
  224. signer := types.MakeSigner(chainConfig, big.NewInt(int64(prestate.Env.Number)))
  225. if txs, err = signUnsignedTransactions(txsWithKeys, signer); err != nil {
  226. return NewError(ErrorJson, fmt.Errorf("failed signing transactions: %v", err))
  227. }
  228. // Sanity check, to not `panic` in state_transition
  229. if chainConfig.IsLondon(big.NewInt(int64(prestate.Env.Number))) {
  230. if prestate.Env.BaseFee == nil {
  231. return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section"))
  232. }
  233. }
  234. isMerged := chainConfig.TerminalTotalDifficulty != nil && chainConfig.TerminalTotalDifficulty.BitLen() == 0
  235. env := prestate.Env
  236. if isMerged {
  237. // post-merge:
  238. // - random must be supplied
  239. // - difficulty must be zero
  240. switch {
  241. case env.Random == nil:
  242. return NewError(ErrorConfig, errors.New("post-merge requires currentRandom to be defined in env"))
  243. case env.Difficulty != nil && env.Difficulty.BitLen() != 0:
  244. return NewError(ErrorConfig, errors.New("post-merge difficulty must be zero (or omitted) in env"))
  245. }
  246. prestate.Env.Difficulty = nil
  247. } else if env.Difficulty == nil {
  248. // pre-merge:
  249. // If difficulty was not provided by caller, we need to calculate it.
  250. switch {
  251. case env.ParentDifficulty == nil:
  252. return NewError(ErrorConfig, errors.New("currentDifficulty was not provided, and cannot be calculated due to missing parentDifficulty"))
  253. case env.Number == 0:
  254. return NewError(ErrorConfig, errors.New("currentDifficulty needs to be provided for block number 0"))
  255. case env.Timestamp <= env.ParentTimestamp:
  256. return NewError(ErrorConfig, fmt.Errorf("currentDifficulty cannot be calculated -- currentTime (%d) needs to be after parent time (%d)",
  257. env.Timestamp, env.ParentTimestamp))
  258. }
  259. prestate.Env.Difficulty = calcDifficulty(chainConfig, env.Number, env.Timestamp,
  260. env.ParentTimestamp, env.ParentDifficulty, env.ParentUncleHash)
  261. }
  262. // Run the test and aggregate the result
  263. s, result, err := prestate.Apply(vmConfig, chainConfig, txs, ctx.Int64(RewardFlag.Name), getTracer)
  264. if err != nil {
  265. return err
  266. }
  267. body, _ := rlp.EncodeToBytes(txs)
  268. // Dump the excution result
  269. collector := make(Alloc)
  270. s.DumpToCollector(collector, nil)
  271. return dispatchOutput(ctx, baseDir, result, collector, body)
  272. }
  273. // txWithKey is a helper-struct, to allow us to use the types.Transaction along with
  274. // a `secretKey`-field, for input
  275. type txWithKey struct {
  276. key *ecdsa.PrivateKey
  277. tx *types.Transaction
  278. protected bool
  279. }
  280. func (t *txWithKey) UnmarshalJSON(input []byte) error {
  281. // Read the metadata, if present
  282. type txMetadata struct {
  283. Key *common.Hash `json:"secretKey"`
  284. Protected *bool `json:"protected"`
  285. }
  286. var data txMetadata
  287. if err := json.Unmarshal(input, &data); err != nil {
  288. return err
  289. }
  290. if data.Key != nil {
  291. k := data.Key.Hex()[2:]
  292. if ecdsaKey, err := crypto.HexToECDSA(k); err != nil {
  293. return err
  294. } else {
  295. t.key = ecdsaKey
  296. }
  297. }
  298. if data.Protected != nil {
  299. t.protected = *data.Protected
  300. } else {
  301. t.protected = true
  302. }
  303. // Now, read the transaction itself
  304. var tx types.Transaction
  305. if err := json.Unmarshal(input, &tx); err != nil {
  306. return err
  307. }
  308. t.tx = &tx
  309. return nil
  310. }
  311. // signUnsignedTransactions converts the input txs to canonical transactions.
  312. //
  313. // The transactions can have two forms, either
  314. // 1. unsigned or
  315. // 2. signed
  316. // For (1), r, s, v, need so be zero, and the `secretKey` needs to be set.
  317. // If so, we sign it here and now, with the given `secretKey`
  318. // If the condition above is not met, then it's considered a signed transaction.
  319. //
  320. // To manage this, we read the transactions twice, first trying to read the secretKeys,
  321. // and secondly to read them with the standard tx json format
  322. func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Transactions, error) {
  323. var signedTxs []*types.Transaction
  324. for i, txWithKey := range txs {
  325. tx := txWithKey.tx
  326. key := txWithKey.key
  327. v, r, s := tx.RawSignatureValues()
  328. if key != nil && v.BitLen()+r.BitLen()+s.BitLen() == 0 {
  329. // This transaction needs to be signed
  330. var (
  331. signed *types.Transaction
  332. err error
  333. )
  334. if txWithKey.protected {
  335. signed, err = types.SignTx(tx, signer, key)
  336. } else {
  337. signed, err = types.SignTx(tx, types.FrontierSigner{}, key)
  338. }
  339. if err != nil {
  340. return nil, NewError(ErrorJson, fmt.Errorf("tx %d: failed to sign tx: %v", i, err))
  341. }
  342. signedTxs = append(signedTxs, signed)
  343. } else {
  344. // Already signed
  345. signedTxs = append(signedTxs, tx)
  346. }
  347. }
  348. return signedTxs, nil
  349. }
  350. type Alloc map[common.Address]core.GenesisAccount
  351. func (g Alloc) OnRoot(common.Hash) {}
  352. func (g Alloc) OnAccount(addr common.Address, dumpAccount state.DumpAccount) {
  353. balance, _ := new(big.Int).SetString(dumpAccount.Balance, 10)
  354. var storage map[common.Hash]common.Hash
  355. if dumpAccount.Storage != nil {
  356. storage = make(map[common.Hash]common.Hash)
  357. for k, v := range dumpAccount.Storage {
  358. storage[k] = common.HexToHash(v)
  359. }
  360. }
  361. genesisAccount := core.GenesisAccount{
  362. Code: dumpAccount.Code,
  363. Storage: storage,
  364. Balance: balance,
  365. Nonce: dumpAccount.Nonce,
  366. }
  367. g[addr] = genesisAccount
  368. }
  369. // saveFile marshalls the object to the given file
  370. func saveFile(baseDir, filename string, data interface{}) error {
  371. b, err := json.MarshalIndent(data, "", " ")
  372. if err != nil {
  373. return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err))
  374. }
  375. location := path.Join(baseDir, filename)
  376. if err = os.WriteFile(location, b, 0644); err != nil {
  377. return NewError(ErrorIO, fmt.Errorf("failed writing output: %v", err))
  378. }
  379. log.Info("Wrote file", "file", location)
  380. return nil
  381. }
  382. // dispatchOutput writes the output data to either stderr or stdout, or to the specified
  383. // files
  384. func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, alloc Alloc, body hexutil.Bytes) error {
  385. stdOutObject := make(map[string]interface{})
  386. stdErrObject := make(map[string]interface{})
  387. dispatch := func(baseDir, fName, name string, obj interface{}) error {
  388. switch fName {
  389. case "stdout":
  390. stdOutObject[name] = obj
  391. case "stderr":
  392. stdErrObject[name] = obj
  393. case "":
  394. // don't save
  395. default: // save to file
  396. if err := saveFile(baseDir, fName, obj); err != nil {
  397. return err
  398. }
  399. }
  400. return nil
  401. }
  402. if err := dispatch(baseDir, ctx.String(OutputAllocFlag.Name), "alloc", alloc); err != nil {
  403. return err
  404. }
  405. if err := dispatch(baseDir, ctx.String(OutputResultFlag.Name), "result", result); err != nil {
  406. return err
  407. }
  408. if err := dispatch(baseDir, ctx.String(OutputBodyFlag.Name), "body", body); err != nil {
  409. return err
  410. }
  411. if len(stdOutObject) > 0 {
  412. b, err := json.MarshalIndent(stdOutObject, "", " ")
  413. if err != nil {
  414. return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err))
  415. }
  416. os.Stdout.Write(b)
  417. os.Stdout.WriteString("\n")
  418. }
  419. if len(stdErrObject) > 0 {
  420. b, err := json.MarshalIndent(stdErrObject, "", " ")
  421. if err != nil {
  422. return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err))
  423. }
  424. os.Stderr.Write(b)
  425. os.Stderr.WriteString("\n")
  426. }
  427. return nil
  428. }