├── .circleci
└── config.yml
├── .github
├── contributing.md
├── labeler.yml
└── workflows
│ ├── labeler.yml
│ ├── vm-lint.yml
│ ├── vm-nightly-test.yml
│ └── vm-test.yml
├── .gitignore
├── .prettierignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── developer.md
├── docs
├── README.md
├── classes
│ ├── statemanager.md
│ ├── vm.md
│ └── vmerror.md
├── enums
│ └── error.md
└── interfaces
│ ├── evmresult.md
│ ├── execresult.md
│ ├── newcontractevent.md
│ ├── runblockopts.md
│ ├── runblockresult.md
│ ├── runcallopts.md
│ ├── runcodeopts.md
│ ├── runtxopts.md
│ ├── runtxresult.md
│ ├── statemanageropts.md
│ ├── storagedump.md
│ ├── txreceipt.md
│ └── vmopts.md
├── examples
├── decode-opcodes
│ ├── README.md
│ ├── index.js
│ └── package.json
├── run-blockchain
│ ├── README.md
│ ├── index.ts
│ ├── package.json
│ └── test-data.json
├── run-code-browser
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── index.js
│ └── package.json
├── run-solidity-contract
│ ├── README.md
│ ├── contracts
│ │ └── Greeter.sol
│ ├── index.ts
│ └── package.json
└── run-transactions-complete
│ ├── README.md
│ ├── index.ts
│ ├── key-pair.json
│ ├── package.json
│ ├── raw-tx1.json
│ └── raw-tx2.js
├── karma.conf.js
├── lib
├── bloom
│ └── index.ts
├── evm
│ ├── eei.ts
│ ├── evm.ts
│ ├── interpreter.ts
│ ├── memory.ts
│ ├── message.ts
│ ├── opFns.ts
│ ├── opcodes.ts
│ ├── precompiles
│ │ ├── 01-ecrecover.ts
│ │ ├── 02-sha256.ts
│ │ ├── 03-ripemd160.ts
│ │ ├── 04-identity.ts
│ │ ├── 05-modexp.ts
│ │ ├── 06-ecadd.ts
│ │ ├── 07-ecmul.ts
│ │ ├── 08-ecpairing.ts
│ │ ├── 09-blake2f.ts
│ │ ├── index.ts
│ │ └── types.ts
│ ├── stack.ts
│ └── txContext.ts
├── exceptions.ts
├── index.ts
├── runBlock.ts
├── runBlockchain.ts
├── runCall.ts
├── runCode.ts
├── runTx.ts
└── state
│ ├── cache.ts
│ ├── index.ts
│ ├── promisified.ts
│ └── stateManager.ts
├── package.json
├── prettier.config.js
├── scripts
└── formatTest.js
├── tests
├── BlockchainTestsRunner.js
├── GeneralStateTestsRunner.js
├── VMTestsRunner.js
├── api
│ ├── bloom.js
│ ├── events.js
│ ├── evm
│ │ ├── memory.js
│ │ ├── precompiles
│ │ │ ├── 06-ecadd.js
│ │ │ ├── 07-ecmul.js
│ │ │ └── 08-ecpairing.js
│ │ └── stack.js
│ ├── index.js
│ ├── istanbul
│ │ ├── eip-1108.js
│ │ ├── eip-1344.js
│ │ ├── eip-152.js
│ │ ├── eip-1884.js
│ │ ├── eip-2200.js
│ │ └── index.js
│ ├── muirGlacier
│ │ └── index.js
│ ├── opcodes.js
│ ├── runBlock.js
│ ├── runBlockchain.js
│ ├── runCode.js
│ ├── runTx.js
│ ├── state
│ │ ├── cache.js
│ │ └── stateManager.js
│ ├── testdata.json
│ └── utils.js
├── tester.js
└── util.js
├── tsconfig.json
├── tsconfig.prod.json
├── tslint.json
├── typedoc.json
└── utils
└── diffTestOutput.py
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 |
3 | orbs:
4 | codecov: codecov/codecov@1.0.5
5 |
6 | aliases:
7 | - &defaults
8 | working_directory: ~/project/ethereumjs-vm
9 | docker:
10 | - image: circleci/node:8
11 | - &restore_node_modules
12 | restore_cache:
13 | name: Restore node_modules cache
14 | keys:
15 | - node8-{{ checksum "package.json" }}
16 |
17 | jobs:
18 | install:
19 | <<: *defaults
20 | steps:
21 | - checkout
22 | - *restore_node_modules
23 | - run:
24 | name: Install dependencies
25 | command: npm install
26 | - save_cache:
27 | name: Save node_modules cache
28 | key: node8-{{ checksum "package.json" }}
29 | paths:
30 | - node_modules/
31 | - persist_to_workspace:
32 | root: ~/project
33 | paths:
34 | - ethereumjs-vm/
35 | coverage:
36 | <<: *defaults
37 | steps:
38 | - attach_workspace:
39 | at: ~/project
40 | - *restore_node_modules
41 | - run:
42 | name: coverage
43 | command: npm run coverage
44 | - codecov/upload:
45 | file: ./coverage/lcov.info
46 | flags: vm
47 |
48 | workflows:
49 | version: 2
50 | install-and-coverage:
51 | jobs:
52 | - install
53 | - coverage:
54 | requires:
55 | - install
56 |
--------------------------------------------------------------------------------
/.github/contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Great that you want to contribute to the `EthereumJS` [ecosystem](https://ethereumjs.readthedocs.io/en/latest/introduction.html). `EthereumJS` is managed by the Ethereum Foundation and largely driven by the wider community. Everyone is welcome to join the effort and help to improve on the libraries (see our [Code of Conduct](https://ethereumjs.readthedocs.io/en/latest/code_of_conduct.html) 🌷).
4 |
5 | We have written up some [Contribution Guidelines](https://ethereumjs.readthedocs.io/en/latest/contributing.html#how-to-start) to help you getting started.
6 |
7 | These include information on how we work with **Git** and how our **general workflow** and **technical setup** looks like (stuff like language, tooling, code quality and style).
8 |
9 | Happy Coding! 👾 😀 💻
10 |
--------------------------------------------------------------------------------
/.github/labeler.yml:
--------------------------------------------------------------------------------
1 | 'package: account':
2 | - packages/account/*
3 | - packages/account/**/*
4 |
5 | 'package: block':
6 | - packages/block/*
7 | - packages/block/**/*
8 |
9 | 'package: blockchain':
10 | - packages/blockchain/*
11 | - packages/blockchain/**/*
12 |
13 | 'package: common':
14 | - packages/common/*
15 | - packages/common/**/*
16 |
17 | 'package: tx':
18 | - packages/tx/*
19 | - packages/tx/**/*
20 |
21 | 'package: vm':
22 | - packages/vm/*
23 | - packages/vm/**/*
24 |
--------------------------------------------------------------------------------
/.github/workflows/labeler.yml:
--------------------------------------------------------------------------------
1 | name: 'PR Labeler'
2 | on:
3 | - pull_request
4 |
5 | jobs:
6 | label:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/labeler@v2
10 | with:
11 | repo-token: '${{ secrets.GITHUB_TOKEN }}'
12 |
--------------------------------------------------------------------------------
/.github/workflows/vm-lint.yml:
--------------------------------------------------------------------------------
1 | name: 'VM Lint'
2 | on:
3 | push:
4 | branches:
5 | - master
6 | tags:
7 | - '*'
8 | pull_request:
9 | types: [opened, reopened, synchronize]
10 | jobs:
11 | lint:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/setup-node@v1
15 | with:
16 | node-version: 8.x
17 |
18 | - uses: actions/checkout@v1
19 |
20 | - name: Cache node modules
21 | id: cache-node-modules
22 | uses: actions/cache@v1
23 | with:
24 | path: node_modules
25 | key: ${{ runner.os }}-node8-${{ hashFiles('**/package.json') }}
26 |
27 | - run: npm install
28 | if: steps.cache-node-modules.outputs.cache-hit != 'true'
29 |
30 | - run: npm run lint
31 | env:
32 | CI: true
33 |
--------------------------------------------------------------------------------
/.github/workflows/vm-nightly-test.yml:
--------------------------------------------------------------------------------
1 | name: 'VM Nightly Test' # without caching
2 | on:
3 | schedule:
4 | - cron: '0 0 * * *' # once a day at midnight
5 | jobs:
6 | test-api:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/setup-node@v1
10 | with:
11 | node-version: 8.x
12 | - uses: actions/checkout@v1
13 | - run: npm install
14 | - run: npm run test:API
15 | env:
16 | CI: true
17 | - run: npm run test:API:browser
18 | env:
19 | CI: true
20 |
21 | test-state:
22 | runs-on: ubuntu-latest
23 | steps:
24 | - uses: actions/setup-node@v1
25 | with:
26 | node-version: 8.x
27 | - uses: actions/checkout@v1
28 | - run: npm install
29 | - run: npm run test:state:allForks
30 | env:
31 | CI: true
32 |
33 | test-blockchain:
34 | runs-on: ubuntu-latest
35 | steps:
36 | - uses: actions/setup-node@v1
37 | with:
38 | node-version: 8.x
39 | - uses: actions/checkout@v1
40 | - run: npm install
41 | - run: npm run test:blockchain
42 | env:
43 | CI: true
44 |
45 | slow-tests:
46 | runs-on: ubuntu-latest
47 | steps:
48 | - uses: actions/setup-node@v1
49 | with:
50 | node-version: 8.x
51 | - uses: actions/checkout@v1
52 | - run: npm install
53 | - run: npm run test:state:slow
54 | env:
55 | CI: true
56 |
--------------------------------------------------------------------------------
/.github/workflows/vm-test.yml:
--------------------------------------------------------------------------------
1 | name: 'VM Test'
2 | on:
3 | push:
4 | branches:
5 | - master
6 | tags:
7 | - '*'
8 | pull_request:
9 | types: [opened, reopened, synchronize]
10 | jobs:
11 | test-api:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/setup-node@v1
15 | with:
16 | node-version: 8.x
17 |
18 | - uses: actions/checkout@v1
19 |
20 | - name: Cache node modules
21 | id: cache-node-modules
22 | uses: actions/cache@v1
23 | with:
24 | path: node_modules
25 | key: ${{ runner.os }}-node8-${{ hashFiles('**/package.json') }}
26 |
27 | - run: npm install
28 | if: steps.cache-node-modules.outputs.cache-hit != 'true'
29 |
30 | - run: npm run test:API
31 | env:
32 | CI: true
33 |
34 | - run: npm run test:API:browser
35 | env:
36 | CI: true
37 |
38 | test-state:
39 | runs-on: ubuntu-latest
40 | steps:
41 | - uses: actions/setup-node@v1
42 | with:
43 | node-version: 8.x
44 |
45 | - uses: actions/checkout@v1
46 |
47 | - name: Cache node modules
48 | id: cache-node-modules
49 | uses: actions/cache@v1
50 | with:
51 | path: node_modules
52 | key: ${{ runner.os }}-node8-${{ hashFiles('**/package.json') }}
53 |
54 | - run: npm install
55 | if: steps.cache-node-modules.outputs.cache-hit != 'true'
56 |
57 | - run: npm run test:state:selectedForks
58 | env:
59 | CI: true
60 |
61 | test-blockchain:
62 | runs-on: ubuntu-latest
63 | steps:
64 | - uses: actions/setup-node@v1
65 | with:
66 | node-version: 8.x
67 |
68 | - uses: actions/checkout@v1
69 |
70 | - name: Cache node modules
71 | id: cache-node-modules
72 | uses: actions/cache@v1
73 | with:
74 | path: node_modules
75 | key: ${{ runner.os }}-node8-${{ hashFiles('**/package.json') }}
76 |
77 | - run: npm install
78 | if: steps.cache-node-modules.outputs.cache-hit != 'true'
79 |
80 | - run: npm run test:blockchain
81 | env:
82 | CI: true
83 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### App ###
2 |
3 | .cachedb
4 |
5 |
6 | # Created by https://www.gitignore.io/api/osx,node
7 |
8 | ### OSX ###
9 | .DS_Store
10 | .AppleDouble
11 | .LSOverride
12 |
13 | # Icon must end with two \r
14 | Icon
15 |
16 |
17 | # Thumbnails
18 | ._*
19 |
20 | # Files that might appear in the root of a volume
21 | .DocumentRevisions-V100
22 | .fseventsd
23 | .Spotlight-V100
24 | .TemporaryItems
25 | .Trashes
26 | .VolumeIcon.icns
27 |
28 | # Directories potentially created on remote AFP share
29 | .AppleDB
30 | .AppleDesktop
31 | Network Trash Folder
32 | Temporary Items
33 | .apdisk
34 |
35 | ### IDE ###
36 | .idea
37 |
38 | ### Node ###
39 | # Logs
40 | logs
41 | *.log
42 | npm-debug.log*
43 |
44 | # Runtime data
45 | pids
46 | *.pid
47 | *.seed
48 |
49 | # Directory for instrumented libs generated by jscoverage/JSCover
50 | lib-cov
51 |
52 | # Coverage directory used by tools like istanbul
53 | coverage
54 | .nyc_output
55 |
56 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
57 | .grunt
58 |
59 | # node-waf configuration
60 | .lock-wscript
61 |
62 | # Compiled binary addons (http://nodejs.org/api/addons.html)
63 | build/Release
64 |
65 | # Dependency directory
66 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
67 | node_modules
68 | package-lock.json
69 | yarn.lock
70 |
71 | # Build folder
72 | dist
73 |
74 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .vscode
3 | package.json
4 | dist
5 | .nyc_output
6 | *.json
7 | docs
8 |
--------------------------------------------------------------------------------
/developer.md:
--------------------------------------------------------------------------------
1 | # Developer Documentation
2 |
3 | ## TESTING
4 |
5 | ### Running Tests
6 |
7 | Tests can be found in the `tests` directory. There are test runners for [State tests](http://www.ethdocs.org/en/latest/contracts-and-transactions/ethereum-tests/state_tests/index.html) and [Blockchain tests](http://www.ethdocs.org/en/latest/contracts-and-transactions/ethereum-tests/blockchain_tests/index.html). VM tests are disabled since Frontier gas costs are not supported any more. Tests are then executed by the [ethereumjs-testing](https://github.com/ethereumjs/ethereumjs-testing) utility library using the official client-independent [Ethereum tests](https://github.com/ethereum/tests).
8 |
9 | For a wider picture about how to use tests to implement EIPs you can have a look at this [Reddit post](https://www.reddit.com/r/ethereum/comments/6kc5g3/ethereumjs_team_is_seeking_contributors/)
10 | or the associated YouTube video introduction to [Core Development with Ethereumjs-vm](https://www.youtube.com/watch?v=L0BVDl6HZzk).
11 |
12 | #### Running different Test Types
13 |
14 | Running the State tests:
15 |
16 | `ts-node ./tests/tester --state`
17 |
18 | Running the Blockchain tests:
19 |
20 | `ts-node ./tests/tester --blockchain`
21 |
22 | Tests run against source by default. They can be run with the `--dist` flag:
23 |
24 | `npm run build:dist && node ./tests/tester --state --dist`
25 |
26 | See `package.json` for all the scripts in the `test:` namespace, such as `npm run test:state` which would execute the above.
27 |
28 | Use `--fork` to pass in the desired hardfork:
29 |
30 | `ts-node ./tests/tester --state --fork='Constantinople'`
31 |
32 | or
33 |
34 | `npm run test:state -- --fork='Constantinople'`
35 |
36 | By default it is set to use the latest hardfork (`FORK_CONFIG` in `tests/tester.js`).
37 |
38 | State tests run significantly faster than Blockchain tests, so it is often a good choice to start fixing State tests.
39 |
40 | #### Running Specific Tests
41 |
42 | Running all the blockchain tests in a file:
43 |
44 | `ts-node ./tests/tester --blockchain --file='randomStatetest303'`
45 |
46 | Running tests from a specific directory:
47 |
48 | `ts-node ./tests/tester --blockchain --dir='bcBlockGasLimitTest'`
49 |
50 | Running a specific state test case:
51 |
52 | `ts-node ./tests/tester --state --test='stackOverflow'`
53 |
54 | Only run test cases with selected `data`, `gas` and/or `value` values (see
55 | [attribute description](http://ethereum-tests.readthedocs.io/en/latest/test_types/state_tests.html) in
56 | test docs), provided by the index of the array element in the test `transaction` section:
57 |
58 | `ts-node ./tests/tester --state --test='CreateCollisionToEmpty' --data=0 --gas=1 --value=0`
59 |
60 | Run a state test from a specified source file not under the `tests` directory:
61 | `ts-node ./tests/tester --state --customStateTest='{path_to_file}'`
62 |
63 | #### Running tests with a reporter/formatter
64 |
65 | `npm run formatTest -t [npm script name OR node command]` will pipe to `tap-spec` by default.
66 |
67 | To pipe the results of the API tests through `tap-spec`:
68 |
69 | `npm run formatTest -- -t test:API`
70 |
71 | To pipe the results of tests run with a node command through `tap-spec`:
72 |
73 | `npm run formatTest -- -t "./tests/tester --blockchain --dir='bcBlockGasLimitTest'"`
74 |
75 | The `-with` flag allows the specification of a formatter of your choosing:
76 |
77 | `npm install -g tap-mocha-reporter`
78 | `npm run formatTest -- -t test:API -with 'tap-mocha-reporter json'`
79 |
80 | #### Skipping Tests
81 |
82 | There are three types of skip lists (`BROKEN`, `PERMANENT` and `SLOW`) which
83 | can be found in `tests/tester.js`. By default tests from all skip lists are omitted.
84 |
85 | You can change this behaviour with:
86 |
87 | `ts-node ./tests/tester --state --skip=BROKEN,PERMANENT`
88 |
89 | to skip only the `BROKEN` and `PERMANENT` tests and include the `SLOW` tests.
90 | There are also the keywords `NONE` or `ALL` for convenience.
91 |
92 | It is also possible to only run the tests from the skip lists:
93 |
94 | `ts-node ./tests/tester --state --runSkipped=SLOW`
95 |
96 | ### CI Test Integration
97 |
98 | Tests and checks are run in CI using [Github Actions](https://github.com/ethereumjs/ethereumjs-vm/actions). The configuration can be found in `.github/workflows`.
99 |
100 | ### Debugging
101 |
102 | #### Local Debugging
103 |
104 | For state tests you can use the `--jsontrace` flag to output opcode trace information.
105 |
106 | Blockchain tests support `--debug` to verify the postState:
107 |
108 | `ts-node ./tests/tester --blockchain --debug --test='ZeroValue_SELFDESTRUCT_ToOneStorageKey_OOGRevert_d0g0v0_EIP158'`
109 |
110 | All/most State tests are replicated as Blockchain tests in a `GeneralStateTests` [sub directory](https://github.com/ethereum/tests/tree/develop/BlockchainTests/GeneralStateTests) in the Ethereum tests repo, so for debugging single test cases the Blockchain test version of the State test can be used.
111 |
112 | #### Comparing Stack Traces
113 |
114 | Other client implementations often also provide functionality for output trace information.
115 |
116 | A convenient way is to use a local `geth` installation (can be the binary installation and doesn't has to be build from source or something) and then use the included `evm` tool like:
117 |
118 | ```shell
119 | evm --json --nomemory statetest node_modules/ethereumjs-testing/tests/GeneralStateTests/stCreate2/create2collisionCode2.json
120 | ```
121 |
122 | If you want to have only the output for a specific fork you can go into the referenced json test file and temporarily delete the `post` section for the non-desired fork outputs (or, more safe and also more convenient on triggering later: copy the test files you are interested in to your working directory and then modify without further worrying).
123 |
124 | #### Debugging Tools
125 |
126 | For comparing `EVM` traces [here](https://gist.github.com/cdetrio/41172f374ae32047a6c9e97fa9d09ad0) are some instructions for setting up `pyethereum` to generate corresponding traces for state tests.
127 |
128 | Compare TAP output from blockchain/state tests and produces concise diff of the differences between them (example):
129 |
130 | ```
131 | curl https://gist.githubusercontent.com/jwasinger/6cef66711b5e0787667ceb3db6bea0dc/raw/0740f03b4ce90d0955d5aba1e0c30ce698c7145a/gistfile1.txt > output-wip-byzantium.txt
132 | curl https://gist.githubusercontent.com/jwasinger/e7004e82426ff0a7137a88d273f11819/raw/66fbd58722747ebe4f7006cee59bbe22461df8eb/gistfile1.txt > output-master.txt
133 | python utils/diffTestOutput.py output-wip-byzantium.txt output-master.txt
134 | ```
135 |
136 | An extremely rich and powerful toolbox is the [evmlab](https://github.com/holiman/evmlab) from `holiman`, both for debugging and creating new test cases or example data.
137 |
138 | ## Profiling
139 |
140 | [Clinic](https://github.com/nearform/node-clinic) allows profiling the VM in the node environment. It supports various profiling methods, among them is [flame](https://github.com/nearform/node-clinic-flame) which can be used for generating flamegraphs to highlight bottlenecks and hot paths. As an example, to generate a flamegraph for the VM blockchain tests, you can run:
141 |
142 | ```sh
143 | NODE_OPTIONS="--max-old-space-size=4096" clinic flame -- node ./tests/tester.js --blockchain --excludeDir='GeneralStateTests'
144 | ```
145 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 |
2 | # ethereumjs-vm
3 |
4 | ## Index
5 |
6 | ### Enumerations
7 |
8 | * [ERROR](enums/error.md)
9 |
10 | ### Classes
11 |
12 | * [StateManager](classes/statemanager.md)
13 | * [VM](classes/vm.md)
14 | * [VmError](classes/vmerror.md)
15 |
16 | ### Interfaces
17 |
18 | * [EVMResult](interfaces/evmresult.md)
19 | * [ExecResult](interfaces/execresult.md)
20 | * [NewContractEvent](interfaces/newcontractevent.md)
21 | * [RunBlockOpts](interfaces/runblockopts.md)
22 | * [RunBlockResult](interfaces/runblockresult.md)
23 | * [RunCallOpts](interfaces/runcallopts.md)
24 | * [RunCodeOpts](interfaces/runcodeopts.md)
25 | * [RunTxOpts](interfaces/runtxopts.md)
26 | * [RunTxResult](interfaces/runtxresult.md)
27 | * [StateManagerOpts](interfaces/statemanageropts.md)
28 | * [StorageDump](interfaces/storagedump.md)
29 | * [TxReceipt](interfaces/txreceipt.md)
30 | * [VMOpts](interfaces/vmopts.md)
31 |
32 | ### Functions
33 |
34 | * [OOGResult](#oogresult)
35 |
36 | ---
37 |
38 | ## Functions
39 |
40 |
41 |
42 | ### OOGResult
43 |
44 | ▸ **OOGResult**(gasLimit: *`BN`*): [ExecResult](interfaces/execresult.md)
45 |
46 | *Defined in [evm/evm.ts:80](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L80)*
47 |
48 | **Parameters:**
49 |
50 | | Name | Type |
51 | | ------ | ------ |
52 | | gasLimit | `BN` |
53 |
54 | **Returns:** [ExecResult](interfaces/execresult.md)
55 |
56 | ___
57 |
58 |
--------------------------------------------------------------------------------
/docs/classes/vmerror.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [VmError](../classes/vmerror.md)
2 |
3 | # Class: VmError
4 |
5 | ## Hierarchy
6 |
7 | **VmError**
8 |
9 | ## Index
10 |
11 | ### Constructors
12 |
13 | * [constructor](vmerror.md#constructor)
14 |
15 | ### Properties
16 |
17 | * [error](vmerror.md#error)
18 | * [errorType](vmerror.md#errortype)
19 |
20 | ---
21 |
22 | ## Constructors
23 |
24 |
25 |
26 | ### constructor
27 |
28 | ⊕ **new VmError**(error: *[ERROR](../enums/error.md)*): [VmError](vmerror.md)
29 |
30 | *Defined in [exceptions.ts:18](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L18)*
31 |
32 | **Parameters:**
33 |
34 | | Name | Type |
35 | | ------ | ------ |
36 | | error | [ERROR](../enums/error.md) |
37 |
38 | **Returns:** [VmError](vmerror.md)
39 |
40 | ___
41 |
42 | ## Properties
43 |
44 |
45 |
46 | ### error
47 |
48 | **● error**: *[ERROR](../enums/error.md)*
49 |
50 | *Defined in [exceptions.ts:17](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L17)*
51 |
52 | ___
53 |
54 |
55 | ### errorType
56 |
57 | **● errorType**: *`string`*
58 |
59 | *Defined in [exceptions.ts:18](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L18)*
60 |
61 | ___
62 |
63 |
--------------------------------------------------------------------------------
/docs/enums/error.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [ERROR](../enums/error.md)
2 |
3 | # Enumeration: ERROR
4 |
5 | ## Index
6 |
7 | ### Enumeration members
8 |
9 | * [CREATE_COLLISION](error.md#create_collision)
10 | * [INTERNAL_ERROR](error.md#internal_error)
11 | * [INVALID_JUMP](error.md#invalid_jump)
12 | * [INVALID_OPCODE](error.md#invalid_opcode)
13 | * [OUT_OF_GAS](error.md#out_of_gas)
14 | * [OUT_OF_RANGE](error.md#out_of_range)
15 | * [REFUND_EXHAUSTED](error.md#refund_exhausted)
16 | * [REVERT](error.md#revert)
17 | * [STACK_OVERFLOW](error.md#stack_overflow)
18 | * [STACK_UNDERFLOW](error.md#stack_underflow)
19 | * [STATIC_STATE_CHANGE](error.md#static_state_change)
20 | * [STOP](error.md#stop)
21 |
22 | ---
23 |
24 | ## Enumeration members
25 |
26 |
27 |
28 | ### CREATE_COLLISION
29 |
30 | **CREATE_COLLISION**: = "create collision"
31 |
32 | *Defined in [exceptions.ts:11](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L11)*
33 |
34 | ___
35 |
36 |
37 | ### INTERNAL_ERROR
38 |
39 | **INTERNAL_ERROR**: = "internal error"
40 |
41 | *Defined in [exceptions.ts:10](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L10)*
42 |
43 | ___
44 |
45 |
46 | ### INVALID_JUMP
47 |
48 | **INVALID_JUMP**: = "invalid JUMP"
49 |
50 | *Defined in [exceptions.ts:5](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L5)*
51 |
52 | ___
53 |
54 |
55 | ### INVALID_OPCODE
56 |
57 | **INVALID_OPCODE**: = "invalid opcode"
58 |
59 | *Defined in [exceptions.ts:6](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L6)*
60 |
61 | ___
62 |
63 |
64 | ### OUT_OF_GAS
65 |
66 | **OUT_OF_GAS**: = "out of gas"
67 |
68 | *Defined in [exceptions.ts:2](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L2)*
69 |
70 | ___
71 |
72 |
73 | ### OUT_OF_RANGE
74 |
75 | **OUT_OF_RANGE**: = "value out of range"
76 |
77 | *Defined in [exceptions.ts:7](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L7)*
78 |
79 | ___
80 |
81 |
82 | ### REFUND_EXHAUSTED
83 |
84 | **REFUND_EXHAUSTED**: = "refund exhausted"
85 |
86 | *Defined in [exceptions.ts:13](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L13)*
87 |
88 | ___
89 |
90 |
91 | ### REVERT
92 |
93 | **REVERT**: = "revert"
94 |
95 | *Defined in [exceptions.ts:8](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L8)*
96 |
97 | ___
98 |
99 |
100 | ### STACK_OVERFLOW
101 |
102 | **STACK_OVERFLOW**: = "stack overflow"
103 |
104 | *Defined in [exceptions.ts:4](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L4)*
105 |
106 | ___
107 |
108 |
109 | ### STACK_UNDERFLOW
110 |
111 | **STACK_UNDERFLOW**: = "stack underflow"
112 |
113 | *Defined in [exceptions.ts:3](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L3)*
114 |
115 | ___
116 |
117 |
118 | ### STATIC_STATE_CHANGE
119 |
120 | **STATIC_STATE_CHANGE**: = "static state change"
121 |
122 | *Defined in [exceptions.ts:9](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L9)*
123 |
124 | ___
125 |
126 |
127 | ### STOP
128 |
129 | **STOP**: = "stop"
130 |
131 | *Defined in [exceptions.ts:12](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/exceptions.ts#L12)*
132 |
133 | ___
134 |
135 |
--------------------------------------------------------------------------------
/docs/interfaces/evmresult.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [EVMResult](../interfaces/evmresult.md)
2 |
3 | # Interface: EVMResult
4 |
5 | Result of executing a message via the \[\[EVM\]\].
6 |
7 | ## Hierarchy
8 |
9 | **EVMResult**
10 |
11 | ↳ [RunTxResult](runtxresult.md)
12 |
13 | ## Index
14 |
15 | ### Properties
16 |
17 | * [createdAddress](evmresult.md#createdaddress)
18 | * [execResult](evmresult.md#execresult)
19 | * [gasUsed](evmresult.md#gasused)
20 |
21 | ---
22 |
23 | ## Properties
24 |
25 |
26 |
27 | ### `` createdAddress
28 |
29 | **● createdAddress**: *`Buffer`*
30 |
31 | *Defined in [evm/evm.ts:32](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L32)*
32 |
33 | Address of created account durint transaction, if any
34 |
35 | ___
36 |
37 |
38 | ### execResult
39 |
40 | **● execResult**: *[ExecResult](execresult.md)*
41 |
42 | *Defined in [evm/evm.ts:36](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L36)*
43 |
44 | Contains the results from running the code, if any, as described in [runCode](../classes/vm.md#runcode)
45 |
46 | ___
47 |
48 |
49 | ### gasUsed
50 |
51 | **● gasUsed**: *`BN`*
52 |
53 | *Defined in [evm/evm.ts:28](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L28)*
54 |
55 | Amount of gas used by the transaction
56 |
57 | ___
58 |
59 |
--------------------------------------------------------------------------------
/docs/interfaces/execresult.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [ExecResult](../interfaces/execresult.md)
2 |
3 | # Interface: ExecResult
4 |
5 | Result of executing a call via the \[\[EVM\]\].
6 |
7 | ## Hierarchy
8 |
9 | **ExecResult**
10 |
11 | ## Index
12 |
13 | ### Properties
14 |
15 | * [exceptionError](execresult.md#exceptionerror)
16 | * [gas](execresult.md#gas)
17 | * [gasRefund](execresult.md#gasrefund)
18 | * [gasUsed](execresult.md#gasused)
19 | * [logs](execresult.md#logs)
20 | * [returnValue](execresult.md#returnvalue)
21 | * [runState](execresult.md#runstate)
22 | * [selfdestruct](execresult.md#selfdestruct)
23 |
24 | ---
25 |
26 | ## Properties
27 |
28 |
29 |
30 | ### `` exceptionError
31 |
32 | **● exceptionError**: *[VmError](../classes/vmerror.md)*
33 |
34 | *Defined in [evm/evm.ts:47](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L47)*
35 |
36 | Description of the exception, if any occured
37 |
38 | ___
39 |
40 |
41 | ### `` gas
42 |
43 | **● gas**: *`BN`*
44 |
45 | *Defined in [evm/evm.ts:51](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L51)*
46 |
47 | Amount of gas left
48 |
49 | ___
50 |
51 |
52 | ### `` gasRefund
53 |
54 | **● gasRefund**: *`BN`*
55 |
56 | *Defined in [evm/evm.ts:67](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L67)*
57 |
58 | Amount of gas to refund from deleting storage values
59 |
60 | ___
61 |
62 |
63 | ### gasUsed
64 |
65 | **● gasUsed**: *`BN`*
66 |
67 | *Defined in [evm/evm.ts:55](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L55)*
68 |
69 | Amount of gas the code used to run
70 |
71 | ___
72 |
73 |
74 | ### `` logs
75 |
76 | **● logs**: *`any`[]*
77 |
78 | *Defined in [evm/evm.ts:63](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L63)*
79 |
80 | Array of logs that the contract emitted
81 |
82 | ___
83 |
84 |
85 | ### returnValue
86 |
87 | **● returnValue**: *`Buffer`*
88 |
89 | *Defined in [evm/evm.ts:59](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L59)*
90 |
91 | Return value from the contract
92 |
93 | ___
94 |
95 |
96 | ### `` runState
97 |
98 | **● runState**: *`RunState`*
99 |
100 | *Defined in [evm/evm.ts:43](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L43)*
101 |
102 | ___
103 |
104 |
105 | ### `` selfdestruct
106 |
107 | **● selfdestruct**: *`undefined` \| `object`*
108 |
109 | *Defined in [evm/evm.ts:71](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L71)*
110 |
111 | A map from the accounts that have self-destructed to the addresses to send their funds to
112 |
113 | ___
114 |
115 |
--------------------------------------------------------------------------------
/docs/interfaces/newcontractevent.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [NewContractEvent](../interfaces/newcontractevent.md)
2 |
3 | # Interface: NewContractEvent
4 |
5 | ## Hierarchy
6 |
7 | **NewContractEvent**
8 |
9 | ## Index
10 |
11 | ### Properties
12 |
13 | * [address](newcontractevent.md#address)
14 | * [code](newcontractevent.md#code)
15 |
16 | ---
17 |
18 | ## Properties
19 |
20 |
21 |
22 | ### address
23 |
24 | **● address**: *`Buffer`*
25 |
26 | *Defined in [evm/evm.ts:75](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L75)*
27 |
28 | ___
29 |
30 |
31 | ### code
32 |
33 | **● code**: *`Buffer`*
34 |
35 | *Defined in [evm/evm.ts:77](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L77)*
36 |
37 | ___
38 |
39 |
--------------------------------------------------------------------------------
/docs/interfaces/runblockopts.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [RunBlockOpts](../interfaces/runblockopts.md)
2 |
3 | # Interface: RunBlockOpts
4 |
5 | Options for running a block.
6 |
7 | ## Hierarchy
8 |
9 | **RunBlockOpts**
10 |
11 | ## Index
12 |
13 | ### Properties
14 |
15 | * [block](runblockopts.md#block)
16 | * [generate](runblockopts.md#generate)
17 | * [root](runblockopts.md#root)
18 | * [skipBlockValidation](runblockopts.md#skipblockvalidation)
19 |
20 | ---
21 |
22 | ## Properties
23 |
24 |
25 |
26 | ### block
27 |
28 | **● block**: *`any`*
29 |
30 | *Defined in [runBlock.ts:18](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runBlock.ts#L18)*
31 |
32 | The [`Block`](https://github.com/ethereumjs/ethereumjs-block) to process
33 |
34 | ___
35 |
36 |
37 | ### `` generate
38 |
39 | **● generate**: *`undefined` \| `false` \| `true`*
40 |
41 | *Defined in [runBlock.ts:27](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runBlock.ts#L27)*
42 |
43 | Whether to generate the stateRoot. If false `runBlock` will check the stateRoot of the block against the Trie
44 |
45 | ___
46 |
47 |
48 | ### `` root
49 |
50 | **● root**: *`Buffer`*
51 |
52 | *Defined in [runBlock.ts:22](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runBlock.ts#L22)*
53 |
54 | Root of the state trie
55 |
56 | ___
57 |
58 |
59 | ### `` skipBlockValidation
60 |
61 | **● skipBlockValidation**: *`undefined` \| `false` \| `true`*
62 |
63 | *Defined in [runBlock.ts:31](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runBlock.ts#L31)*
64 |
65 | If true, will skip block validation
66 |
67 | ___
68 |
69 |
--------------------------------------------------------------------------------
/docs/interfaces/runblockresult.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [RunBlockResult](../interfaces/runblockresult.md)
2 |
3 | # Interface: RunBlockResult
4 |
5 | Result of [runBlock](../classes/vm.md#runblock)
6 |
7 | ## Hierarchy
8 |
9 | **RunBlockResult**
10 |
11 | ## Index
12 |
13 | ### Properties
14 |
15 | * [receipts](runblockresult.md#receipts)
16 | * [results](runblockresult.md#results)
17 |
18 | ---
19 |
20 | ## Properties
21 |
22 |
23 |
24 | ### receipts
25 |
26 | **● receipts**: *[TxReceipt](txreceipt.md)[]*
27 |
28 | *Defined in [runBlock.ts:41](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runBlock.ts#L41)*
29 |
30 | Receipts generated for transactions in the block
31 |
32 | ___
33 |
34 |
35 | ### results
36 |
37 | **● results**: *[RunTxResult](runtxresult.md)[]*
38 |
39 | *Defined in [runBlock.ts:45](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runBlock.ts#L45)*
40 |
41 | Results of executing the transactions in the block
42 |
43 | ___
44 |
45 |
--------------------------------------------------------------------------------
/docs/interfaces/runcallopts.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [RunCallOpts](../interfaces/runcallopts.md)
2 |
3 | # Interface: RunCallOpts
4 |
5 | Options for running a call (or create) operation
6 |
7 | ## Hierarchy
8 |
9 | **RunCallOpts**
10 |
11 | ## Index
12 |
13 | ### Properties
14 |
15 | * [block](runcallopts.md#block)
16 | * [caller](runcallopts.md#caller)
17 | * [code](runcallopts.md#code)
18 | * [compiled](runcallopts.md#compiled)
19 | * [data](runcallopts.md#data)
20 | * [delegatecall](runcallopts.md#delegatecall)
21 | * [depth](runcallopts.md#depth)
22 | * [gasLimit](runcallopts.md#gaslimit)
23 | * [gasPrice](runcallopts.md#gasprice)
24 | * [origin](runcallopts.md#origin)
25 | * [salt](runcallopts.md#salt)
26 | * [selfdestruct](runcallopts.md#selfdestruct)
27 | * [static](runcallopts.md#static)
28 | * [to](runcallopts.md#to)
29 | * [value](runcallopts.md#value)
30 |
31 | ---
32 |
33 | ## Properties
34 |
35 |
36 |
37 | ### `` block
38 |
39 | **● block**: *`any`*
40 |
41 | *Defined in [runCall.ts:13](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L13)*
42 |
43 | ___
44 |
45 |
46 | ### `` caller
47 |
48 | **● caller**: *`Buffer`*
49 |
50 | *Defined in [runCall.ts:16](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L16)*
51 |
52 | ___
53 |
54 |
55 | ### `` code
56 |
57 | **● code**: *`Buffer`*
58 |
59 | *Defined in [runCall.ts:24](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L24)*
60 |
61 | This is for CALLCODE where the code to load is different than the code from the to account
62 |
63 | ___
64 |
65 |
66 | ### `` compiled
67 |
68 | **● compiled**: *`undefined` \| `false` \| `true`*
69 |
70 | *Defined in [runCall.ts:26](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L26)*
71 |
72 | ___
73 |
74 |
75 | ### `` data
76 |
77 | **● data**: *`Buffer`*
78 |
79 | *Defined in [runCall.ts:20](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L20)*
80 |
81 | ___
82 |
83 |
84 | ### `` delegatecall
85 |
86 | **● delegatecall**: *`undefined` \| `false` \| `true`*
87 |
88 | *Defined in [runCall.ts:30](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L30)*
89 |
90 | ___
91 |
92 |
93 | ### `` depth
94 |
95 | **● depth**: *`undefined` \| `number`*
96 |
97 | *Defined in [runCall.ts:25](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L25)*
98 |
99 | ___
100 |
101 |
102 | ### `` gasLimit
103 |
104 | **● gasLimit**: *`Buffer`*
105 |
106 | *Defined in [runCall.ts:17](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L17)*
107 |
108 | ___
109 |
110 |
111 | ### `` gasPrice
112 |
113 | **● gasPrice**: *`Buffer`*
114 |
115 | *Defined in [runCall.ts:14](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L14)*
116 |
117 | ___
118 |
119 |
120 | ### `` origin
121 |
122 | **● origin**: *`Buffer`*
123 |
124 | *Defined in [runCall.ts:15](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L15)*
125 |
126 | ___
127 |
128 |
129 | ### `` salt
130 |
131 | **● salt**: *`Buffer`*
132 |
133 | *Defined in [runCall.ts:28](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L28)*
134 |
135 | ___
136 |
137 |
138 | ### `` selfdestruct
139 |
140 | **● selfdestruct**: *`undefined` \| `object`*
141 |
142 | *Defined in [runCall.ts:29](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L29)*
143 |
144 | ___
145 |
146 |
147 | ### `` static
148 |
149 | **● static**: *`undefined` \| `false` \| `true`*
150 |
151 | *Defined in [runCall.ts:27](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L27)*
152 |
153 | ___
154 |
155 |
156 | ### `` to
157 |
158 | **● to**: *`Buffer`*
159 |
160 | *Defined in [runCall.ts:18](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L18)*
161 |
162 | ___
163 |
164 |
165 | ### `` value
166 |
167 | **● value**: *`Buffer`*
168 |
169 | *Defined in [runCall.ts:19](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCall.ts#L19)*
170 |
171 | ___
172 |
173 |
--------------------------------------------------------------------------------
/docs/interfaces/runcodeopts.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [RunCodeOpts](../interfaces/runcodeopts.md)
2 |
3 | # Interface: RunCodeOpts
4 |
5 | Options for the [runCode](../classes/vm.md#runcode) method.
6 |
7 | ## Hierarchy
8 |
9 | **RunCodeOpts**
10 |
11 | ## Index
12 |
13 | ### Properties
14 |
15 | * [address](runcodeopts.md#address)
16 | * [block](runcodeopts.md#block)
17 | * [caller](runcodeopts.md#caller)
18 | * [code](runcodeopts.md#code)
19 | * [data](runcodeopts.md#data)
20 | * [depth](runcodeopts.md#depth)
21 | * [evm](runcodeopts.md#evm)
22 | * [gasLimit](runcodeopts.md#gaslimit)
23 | * [gasPrice](runcodeopts.md#gasprice)
24 | * [isStatic](runcodeopts.md#isstatic)
25 | * [message](runcodeopts.md#message)
26 | * [origin](runcodeopts.md#origin)
27 | * [pc](runcodeopts.md#pc)
28 | * [selfdestruct](runcodeopts.md#selfdestruct)
29 | * [txContext](runcodeopts.md#txcontext)
30 | * [value](runcodeopts.md#value)
31 |
32 | ---
33 |
34 | ## Properties
35 |
36 |
37 |
38 | ### `` address
39 |
40 | **● address**: *`Buffer`*
41 |
42 | *Defined in [runCode.ts:63](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L63)*
43 |
44 | The address of the account that is executing this code. The address should be a `Buffer` of bytes. Defaults to `0`
45 |
46 | ___
47 |
48 |
49 | ### `` block
50 |
51 | **● block**: *`any`*
52 |
53 | *Defined in [runCode.ts:28](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L28)*
54 |
55 | The [`Block`](https://github.com/ethereumjs/ethereumjs-block) the `tx` belongs to. If omitted a blank block will be used
56 |
57 | ___
58 |
59 |
60 | ### `` caller
61 |
62 | **● caller**: *`Buffer`*
63 |
64 | *Defined in [runCode.ts:40](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L40)*
65 |
66 | The address that ran this code. The address should be a `Buffer` of 20bits. Defaults to `0`
67 |
68 | ___
69 |
70 |
71 | ### `` code
72 |
73 | **● code**: *`Buffer`*
74 |
75 | *Defined in [runCode.ts:44](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L44)*
76 |
77 | The EVM code to run
78 |
79 | ___
80 |
81 |
82 | ### `` data
83 |
84 | **● data**: *`Buffer`*
85 |
86 | *Defined in [runCode.ts:48](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L48)*
87 |
88 | The input data
89 |
90 | ___
91 |
92 |
93 | ### `` depth
94 |
95 | **● depth**: *`undefined` \| `number`*
96 |
97 | *Defined in [runCode.ts:57](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L57)*
98 |
99 | ___
100 |
101 |
102 | ### `` evm
103 |
104 | **● evm**: *`EVM`*
105 |
106 | *Defined in [runCode.ts:29](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L29)*
107 |
108 | ___
109 |
110 |
111 | ### `` gasLimit
112 |
113 | **● gasLimit**: *`Buffer`*
114 |
115 | *Defined in [runCode.ts:52](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L52)*
116 |
117 | Gas limit
118 |
119 | ___
120 |
121 |
122 | ### `` gasPrice
123 |
124 | **● gasPrice**: *`Buffer`*
125 |
126 | *Defined in [runCode.ts:31](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L31)*
127 |
128 | ___
129 |
130 |
131 | ### `` isStatic
132 |
133 | **● isStatic**: *`undefined` \| `false` \| `true`*
134 |
135 | *Defined in [runCode.ts:58](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L58)*
136 |
137 | ___
138 |
139 |
140 | ### `` message
141 |
142 | **● message**: *`Message`*
143 |
144 | *Defined in [runCode.ts:36](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L36)*
145 |
146 | ___
147 |
148 |
149 | ### `` origin
150 |
151 | **● origin**: *`Buffer`*
152 |
153 | *Defined in [runCode.ts:35](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L35)*
154 |
155 | The address where the call originated from. The address should be a `Buffer` of 20bits. Defaults to `0`
156 |
157 | ___
158 |
159 |
160 | ### `` pc
161 |
162 | **● pc**: *`undefined` \| `number`*
163 |
164 | *Defined in [runCode.ts:67](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L67)*
165 |
166 | The initial program counter. Defaults to `0`
167 |
168 | ___
169 |
170 |
171 | ### `` selfdestruct
172 |
173 | **● selfdestruct**: *`undefined` \| `object`*
174 |
175 | *Defined in [runCode.ts:59](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L59)*
176 |
177 | ___
178 |
179 |
180 | ### `` txContext
181 |
182 | **● txContext**: *`TxContext`*
183 |
184 | *Defined in [runCode.ts:30](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L30)*
185 |
186 | ___
187 |
188 |
189 | ### `` value
190 |
191 | **● value**: *`Buffer`*
192 |
193 | *Defined in [runCode.ts:56](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runCode.ts#L56)*
194 |
195 | The value in ether that is being sent to `opt.address`. Defaults to `0`
196 |
197 | ___
198 |
199 |
--------------------------------------------------------------------------------
/docs/interfaces/runtxopts.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [RunTxOpts](../interfaces/runtxopts.md)
2 |
3 | # Interface: RunTxOpts
4 |
5 | Options for the `runTx` method.
6 |
7 | ## Hierarchy
8 |
9 | **RunTxOpts**
10 |
11 | ## Index
12 |
13 | ### Properties
14 |
15 | * [block](runtxopts.md#block)
16 | * [skipBalance](runtxopts.md#skipbalance)
17 | * [skipNonce](runtxopts.md#skipnonce)
18 | * [tx](runtxopts.md#tx)
19 |
20 | ---
21 |
22 | ## Properties
23 |
24 |
25 |
26 | ### `` block
27 |
28 | **● block**: *`any`*
29 |
30 | *Defined in [runTx.ts:20](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runTx.ts#L20)*
31 |
32 | The block to which the `tx` belongs
33 |
34 | ___
35 |
36 |
37 | ### `` skipBalance
38 |
39 | **● skipBalance**: *`undefined` \| `false` \| `true`*
40 |
41 | *Defined in [runTx.ts:32](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runTx.ts#L32)*
42 |
43 | If true, skips the balance check
44 |
45 | ___
46 |
47 |
48 | ### `` skipNonce
49 |
50 | **● skipNonce**: *`undefined` \| `false` \| `true`*
51 |
52 | *Defined in [runTx.ts:28](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runTx.ts#L28)*
53 |
54 | If true, skips the nonce check
55 |
56 | ___
57 |
58 |
59 | ### tx
60 |
61 | **● tx**: *`Transaction`*
62 |
63 | *Defined in [runTx.ts:24](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runTx.ts#L24)*
64 |
65 | A [`Transaction`](https://github.com/ethereum/ethereumjs-tx) to run
66 |
67 | ___
68 |
69 |
--------------------------------------------------------------------------------
/docs/interfaces/runtxresult.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [RunTxResult](../interfaces/runtxresult.md)
2 |
3 | # Interface: RunTxResult
4 |
5 | Execution result of a transaction
6 |
7 | ## Hierarchy
8 |
9 | [EVMResult](evmresult.md)
10 |
11 | **↳ RunTxResult**
12 |
13 | ## Index
14 |
15 | ### Properties
16 |
17 | * [amountSpent](runtxresult.md#amountspent)
18 | * [bloom](runtxresult.md#bloom)
19 | * [createdAddress](runtxresult.md#createdaddress)
20 | * [execResult](runtxresult.md#execresult)
21 | * [gasRefund](runtxresult.md#gasrefund)
22 | * [gasUsed](runtxresult.md#gasused)
23 |
24 | ---
25 |
26 | ## Properties
27 |
28 |
29 |
30 | ### amountSpent
31 |
32 | **● amountSpent**: *`BN`*
33 |
34 | *Defined in [runTx.ts:46](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runTx.ts#L46)*
35 |
36 | The amount of ether used by this transaction
37 |
38 | ___
39 |
40 |
41 | ### bloom
42 |
43 | **● bloom**: *`Bloom`*
44 |
45 | *Defined in [runTx.ts:42](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runTx.ts#L42)*
46 |
47 | Bloom filter resulted from transaction
48 |
49 | ___
50 |
51 |
52 | ### `` createdAddress
53 |
54 | **● createdAddress**: *`Buffer`*
55 |
56 | *Inherited from [EVMResult](evmresult.md).[createdAddress](evmresult.md#createdaddress)*
57 |
58 | *Defined in [evm/evm.ts:32](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L32)*
59 |
60 | Address of created account durint transaction, if any
61 |
62 | ___
63 |
64 |
65 | ### execResult
66 |
67 | **● execResult**: *[ExecResult](execresult.md)*
68 |
69 | *Inherited from [EVMResult](evmresult.md).[execResult](evmresult.md#execresult)*
70 |
71 | *Defined in [evm/evm.ts:36](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L36)*
72 |
73 | Contains the results from running the code, if any, as described in [runCode](../classes/vm.md#runcode)
74 |
75 | ___
76 |
77 |
78 | ### `` gasRefund
79 |
80 | **● gasRefund**: *`BN`*
81 |
82 | *Defined in [runTx.ts:50](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runTx.ts#L50)*
83 |
84 | The amount of gas as that was refunded during the transaction (i.e. `gasUsed = totalGasConsumed - gasRefund`)
85 |
86 | ___
87 |
88 |
89 | ### gasUsed
90 |
91 | **● gasUsed**: *`BN`*
92 |
93 | *Inherited from [EVMResult](evmresult.md).[gasUsed](evmresult.md#gasused)*
94 |
95 | *Defined in [evm/evm.ts:28](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/evm/evm.ts#L28)*
96 |
97 | Amount of gas used by the transaction
98 |
99 | ___
100 |
101 |
--------------------------------------------------------------------------------
/docs/interfaces/statemanageropts.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [StateManagerOpts](../interfaces/statemanageropts.md)
2 |
3 | # Interface: StateManagerOpts
4 |
5 | Options for constructing a [StateManager](../classes/statemanager.md).
6 |
7 | ## Hierarchy
8 |
9 | **StateManagerOpts**
10 |
11 | ## Index
12 |
13 | ### Properties
14 |
15 | * [common](statemanageropts.md#common)
16 | * [trie](statemanageropts.md#trie)
17 |
18 | ---
19 |
20 | ## Properties
21 |
22 |
23 |
24 | ### `` common
25 |
26 | **● common**: *`Common`*
27 |
28 | *Defined in [state/stateManager.ts:26](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/state/stateManager.ts#L26)*
29 |
30 | Parameters of the chain ([`Common`](https://github.com/ethereumjs/ethereumjs-common))
31 |
32 | ___
33 |
34 |
35 | ### `` trie
36 |
37 | **● trie**: *`any`*
38 |
39 | *Defined in [state/stateManager.ts:30](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/state/stateManager.ts#L30)*
40 |
41 | A [`merkle-patricia-tree`](https://github.com/ethereumjs/merkle-patricia-tree) instance
42 |
43 | ___
44 |
45 |
--------------------------------------------------------------------------------
/docs/interfaces/storagedump.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [StorageDump](../interfaces/storagedump.md)
2 |
3 | # Interface: StorageDump
4 |
5 | Storage values of an account
6 |
7 | ## Hierarchy
8 |
9 | **StorageDump**
10 |
11 | ## Indexable
12 |
13 | \[key: `string`\]: `string`
14 | Storage values of an account
15 |
16 | ## Index
17 |
18 | ---
19 |
20 |
--------------------------------------------------------------------------------
/docs/interfaces/txreceipt.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [TxReceipt](../interfaces/txreceipt.md)
2 |
3 | # Interface: TxReceipt
4 |
5 | Receipt generated for a transaction
6 |
7 | ## Hierarchy
8 |
9 | **TxReceipt**
10 |
11 | ## Index
12 |
13 | ### Properties
14 |
15 | * [bitvector](txreceipt.md#bitvector)
16 | * [gasUsed](txreceipt.md#gasused)
17 | * [logs](txreceipt.md#logs)
18 | * [status](txreceipt.md#status)
19 |
20 | ---
21 |
22 | ## Properties
23 |
24 |
25 |
26 | ### bitvector
27 |
28 | **● bitvector**: *`Buffer`*
29 |
30 | *Defined in [runBlock.ts:63](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runBlock.ts#L63)*
31 |
32 | Bloom bitvector
33 |
34 | ___
35 |
36 |
37 | ### gasUsed
38 |
39 | **● gasUsed**: *`Buffer`*
40 |
41 | *Defined in [runBlock.ts:59](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runBlock.ts#L59)*
42 |
43 | Gas used
44 |
45 | ___
46 |
47 |
48 | ### logs
49 |
50 | **● logs**: *`any`[]*
51 |
52 | *Defined in [runBlock.ts:67](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runBlock.ts#L67)*
53 |
54 | Logs emitted
55 |
56 | ___
57 |
58 |
59 | ### status
60 |
61 | **● status**: *`0` \| `1`*
62 |
63 | *Defined in [runBlock.ts:55](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/runBlock.ts#L55)*
64 |
65 | Status of transaction, `1` if successful, `0` if an exception occured
66 |
67 | ___
68 |
69 |
--------------------------------------------------------------------------------
/docs/interfaces/vmopts.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-vm](../README.md) > [VMOpts](../interfaces/vmopts.md)
2 |
3 | # Interface: VMOpts
4 |
5 | Options for instantiating a [VM](../classes/vm.md).
6 |
7 | ## Hierarchy
8 |
9 | **VMOpts**
10 |
11 | ## Index
12 |
13 | ### Properties
14 |
15 | * [activatePrecompiles](vmopts.md#activateprecompiles)
16 | * [allowUnlimitedContractSize](vmopts.md#allowunlimitedcontractsize)
17 | * [blockchain](vmopts.md#blockchain)
18 | * [chain](vmopts.md#chain)
19 | * [common](vmopts.md#common)
20 | * [hardfork](vmopts.md#hardfork)
21 | * [state](vmopts.md#state)
22 | * [stateManager](vmopts.md#statemanager)
23 |
24 | ---
25 |
26 | ## Properties
27 |
28 |
29 |
30 | ### `` activatePrecompiles
31 |
32 | **● activatePrecompiles**: *`undefined` \| `false` \| `true`*
33 |
34 | *Defined in [index.ts:52](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/index.ts#L52)*
35 |
36 | If true, create entries in the state tree for the precompiled contracts, saving some gas the first time each of them is called.
37 |
38 | If this parameter is false, the first call to each of them has to pay an extra 25000 gas for creating the account.
39 |
40 | Setting this to true has the effect of precompiled contracts' gas costs matching mainnet's from the very first call, which is intended for testing networks.
41 |
42 | ___
43 |
44 |
45 | ### `` allowUnlimitedContractSize
46 |
47 | **● allowUnlimitedContractSize**: *`undefined` \| `false` \| `true`*
48 |
49 | *Defined in [index.ts:56](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/index.ts#L56)*
50 |
51 | Allows unlimited contract sizes while debugging. By setting this to `true`, the check for contract size limit of 24KB (see [EIP-170](https://git.io/vxZkK)) is bypassed
52 |
53 | ___
54 |
55 |
56 | ### `` blockchain
57 |
58 | **● blockchain**: *`Blockchain`*
59 |
60 | *Defined in [index.ts:41](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/index.ts#L41)*
61 |
62 | A [blockchain](https://github.com/ethereumjs/ethereumjs-blockchain) object for storing/retrieving blocks
63 |
64 | ___
65 |
66 |
67 | ### `` chain
68 |
69 | **● chain**: *`undefined` \| `string`*
70 |
71 | *Defined in [index.ts:24](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/index.ts#L24)*
72 |
73 | The chain the VM operates on
74 |
75 | ___
76 |
77 |
78 | ### `` common
79 |
80 | **● common**: *`Common`*
81 |
82 | *Defined in [index.ts:57](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/index.ts#L57)*
83 |
84 | ___
85 |
86 |
87 | ### `` hardfork
88 |
89 | **● hardfork**: *`undefined` \| `string`*
90 |
91 | *Defined in [index.ts:28](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/index.ts#L28)*
92 |
93 | Hardfork rules to be used
94 |
95 | ___
96 |
97 |
98 | ### `` state
99 |
100 | **● state**: *`any`*
101 |
102 | *Defined in [index.ts:37](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/index.ts#L37)*
103 |
104 | A [merkle-patricia-tree](https://github.com/ethereumjs/merkle-patricia-tree) instance for the state tree (ignored if stateManager is passed)
105 |
106 | *__deprecated__*:
107 |
108 | ___
109 |
110 |
111 | ### `` stateManager
112 |
113 | **● stateManager**: *[StateManager](../classes/statemanager.md)*
114 |
115 | *Defined in [index.ts:32](https://github.com/ethereumjs/ethereumjs-vm/blob/439570a/lib/index.ts#L32)*
116 |
117 | A [StateManager](../classes/statemanager.md) instance to use as the state store (Beta API)
118 |
119 | ___
120 |
121 |
--------------------------------------------------------------------------------
/examples/decode-opcodes/README.md:
--------------------------------------------------------------------------------
1 | # Decode opcodes example
2 |
3 | This directory contains an example on how to decode opcodes
4 |
5 | The example does these things:
6 |
7 | 1. Takes binary EVM code and decodes it into opcodes
8 |
9 | ## Installation
10 |
11 | 1. Run `npm install` in the root of this project
12 |
13 | ## Running the example
14 |
15 | 1. Run `npm run build:dist` in the root of this project
16 | 1. Run `npm run example` in this directory
17 |
--------------------------------------------------------------------------------
/examples/decode-opcodes/index.js:
--------------------------------------------------------------------------------
1 | const opcodes = require('../../dist/evm/opcodes').lookupOpInfo
2 |
3 | const data =
4 | '6107608061000e6000396000f30060003560e060020a90048063141961bc1461006e57806319ac74bd146100cf578063278ecde1146100e75780632c0f7b6f146100f8578063a87430ba1461010a578063ac273aa21461011f578063c06f4c1d14610133578063c1cbbca714610159578063e11523431461016a57005b610079600435610183565b8b6000528a60205289600160a060020a031660405288600160a060020a0316606052876080528660a0528560c0528460e05283610100528261012052816101405280600160a060020a0316610160526101806000f35b6100dd6004356024356106e8565b8060005260206000f35b6100f2600435610454565b60006000f35b61010061017c565b8060005260206000f35b6101156004356101da565b8060005260206000f35b61012d600435602435610729565b60006000f35b61015360043560243560443560643560843560a43560c43560e4356101ee565b60006000f35b610164600435610302565b60006000f35b6101756004356105dd565b60006000f35b5b60005481565b5b6000526001602052604060002080549080600101549080600201549080600301549080600401549080600501549080600601549080600701549080600801549080600901549080600c01549080600d015490508c565b5b600052600260205260406000208054905081565b600060006000600060008811801561020557504287115b61020e576102f4565b600080549081600101905593506001600085815260200190815260200160002092508b83819055508a83600101819055503383600201819055508883600301819055508783600501819055508683600401819055508583600701819055508983600c01819055508483600d01819055506002600033600160a060020a03168152602001908152602001600020915081805490816001019055905083826001016000838152602001908152602001600020819055508333600160a060020a03167f882da991e52c8933ce57314c9ba3f934798d912d862790c40d0feeb7025af08a60006000a35b505050505050505050505050565b600060006000600034116103155761044e565b600160008581526020019081526020016000209250428360040154101561033b5761044d565b82600901805490816001019055915082600a0160008381526020019081526020016000209050338181905550348160010181905550806001015483600601818154019150819055508183600b01600033600160a060020a03168152602001908152602001600020819055508333600160a060020a03167fc5e578961e5bd7481ccf1d1bdfbad97b9f1ddfad520f061ca764a57018f3febe6000866006015481526020016000a3600083600d0154600160a060020a031614156103fc5761044c565b82600d0154600160a060020a03166249f068600060008260e060020a02600052600488815260200133600160a060020a03168152602001348152602001600060008660325a03f161044957005b50505b5b5b50505050565b60006000600160008481526020019081526020016000209150816004015442118015610487575081600501548260060154105b8015610497575060008260060154115b6104a0576105d8565b81600a01600083600b01600033600160a060020a03168152602001908152602001600020548152602001908152602001600020905060008160010154116104e6576105d7565b8054600160a060020a0316600082600101546000600060006000848787f161050a57005b505050806001015482600601818154039150819055508233600160a060020a03167fe139691e7435f1fb40ec50ed3729009226be49087fd00e9e5bac276c2a8f40cf6000846001015481526020016000a360008160010181905550600082600d0154600160a060020a03161415610580576105d6565b81600d0154600160a060020a031663b71f3cde600060008260e060020a0260005260048781526020018554600160a060020a0316815260200185600101548152602001600060008660325a03f16105d357005b50505b5b5b505050565b6000600160008381526020019081526020016000209050806005015481600601541015610609576106e4565b8060030154600160a060020a0316600082600601546000600060006000848787f161063057005b5050508133600160a060020a03167f6be92574b1386f424263a096e8b66ff6cc223ab0f9d18702563aa339a372cf986000846006015481526020016000a36000816006018190555060018160080181905550600081600d0154600160a060020a0316141561069d576106e3565b80600d0154600160a060020a031663484ec26c600060008260e060020a02600052600486815260200185600601548152602001600060008660325a03f16106e057005b50505b5b5050565b600060006002600085600160a060020a0316815260200190815260200160002090508060010160008481526020019081526020016000205491505092915050565b6000600060016000858152602001908152602001600020905080600a0160008481526020019081526020016000209150509291505056'
5 |
6 | nameOpCodes(Buffer.from(data, 'hex'))
7 |
8 | function nameOpCodes(raw) {
9 | var pushData
10 |
11 | for (var i = 0; i < raw.length; i++) {
12 | var pc = i
13 | var curOpCode = opcodes(raw[pc], true).name
14 |
15 | // no destinations into the middle of PUSH
16 | if (curOpCode.slice(0, 4) === 'PUSH') {
17 | var jumpNum = raw[pc] - 0x5f
18 | pushData = raw.slice(pc + 1, pc + jumpNum + 1)
19 | i += jumpNum
20 | }
21 |
22 | console.log(
23 | pad(pc, roundLog(raw.length, 10)) + ' ' + curOpCode + ' ' + pushData.toString('hex'),
24 | )
25 |
26 | pushData = ''
27 | }
28 | }
29 |
30 | function pad(num, size) {
31 | var s = num + ''
32 | while (s.length < size) s = '0' + s
33 | return s
34 | }
35 |
36 | function log(num, base) {
37 | return Math.log(num) / Math.log(base)
38 | }
39 |
40 | function roundLog(num, base) {
41 | return Math.ceil(log(num, base))
42 | }
43 |
--------------------------------------------------------------------------------
/examples/decode-opcodes/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "decode-opcodes",
3 | "private": true,
4 | "scripts": {
5 | "example": "node index.js"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/examples/run-blockchain/README.md:
--------------------------------------------------------------------------------
1 | # Run Blockchain example
2 |
3 | This directory contains an example on how to run a blockchain.
4 |
5 | The example does these things:
6 |
7 | 1. Instantiates a VM and a Blockchain
8 | 1. Creates the accounts from `./test-data.json`'s `pre`
9 | 1. Creates a genesis block
10 | 1. Puts the blocks from `./test-data.json`'s `blocks` into the Blockchain
11 | 1. Runs the Blockchain on the VM.
12 |
13 | ## Installation
14 |
15 | 1. Run `npm install` in the root of this project
16 |
17 | ## Running the example
18 |
19 | 1. Run `npm run build:dist` in the root of this project
20 | 1. Run `npm run example` in this directory
21 |
--------------------------------------------------------------------------------
/examples/run-blockchain/index.ts:
--------------------------------------------------------------------------------
1 | import VM from '../../'
2 |
3 | import Account from 'ethereumjs-account'
4 | import Blockchain from 'ethereumjs-blockchain'
5 | import * as utils from 'ethereumjs-util'
6 | import { promisify } from 'util'
7 | import PStateManager from '../../lib/state/promisified'
8 |
9 | const Block = require('ethereumjs-block')
10 | const BlockHeader = require('ethereumjs-block/header.js')
11 | const testData = require('./test-data')
12 | const level = require('level')
13 |
14 | async function main() {
15 | const hardfork = testData.network.toLowerCase()
16 |
17 | const blockchain = new Blockchain({
18 | hardfork,
19 | // This flag can be control whether the blocks are validated. This includes:
20 | // * Verifying PoW
21 | // * Validating each blocks's difficulty, uncles, tries, header and uncles.
22 | validate: true,
23 | })
24 |
25 | // When verifying PoW, setting this cache improves the performance of subsequent runs of this
26 | // script. It has no effect if the blockchain is initialized with `validate: false`.
27 | setEthashCache(blockchain)
28 |
29 | const vm = new VM({
30 | blockchain: blockchain,
31 | hardfork,
32 | })
33 |
34 | await setupPreConditions(vm, testData)
35 |
36 | await setGenesisBlock(blockchain, hardfork)
37 |
38 | await putBlocks(blockchain, hardfork, testData)
39 |
40 | await vm.runBlockchain(blockchain)
41 |
42 | const blockchainHead = await promisify(vm.blockchain.getHead.bind(vm.blockchain))()
43 |
44 | console.log('--- Finished processing the BlockChain ---')
45 | console.log('New head:', '0x' + blockchainHead.hash().toString('hex'))
46 | console.log('Expected:', testData.lastblockhash)
47 | }
48 |
49 | function setEthashCache(blockchain: any) {
50 | if (blockchain.validate) {
51 | blockchain.ethash.cacheDB = level('./.cachedb')
52 | }
53 | }
54 |
55 | async function setupPreConditions(vm: VM, testData: any) {
56 | const psm = new PStateManager(vm.stateManager)
57 |
58 | await psm.checkpoint()
59 |
60 | for (const address of Object.keys(testData.pre)) {
61 | const addressBuf = utils.toBuffer(address)
62 |
63 | const acctData = testData.pre[address]
64 | const account = new Account({
65 | nonce: acctData.nonce,
66 | balance: acctData.balance,
67 | })
68 |
69 | await psm.putAccount(addressBuf, account)
70 |
71 | for (const hexStorageKey of Object.keys(acctData.storage)) {
72 | const val = utils.toBuffer(acctData.storage[hexStorageKey])
73 | const storageKey = utils.setLength(utils.toBuffer(hexStorageKey), 32)
74 |
75 | await psm.putContractStorage(addressBuf, storageKey, val)
76 | }
77 |
78 | const codeBuf = utils.toBuffer(acctData.code)
79 |
80 | await psm.putContractCode(addressBuf, codeBuf)
81 | }
82 |
83 | await psm.commit()
84 | }
85 |
86 | async function setGenesisBlock(blockchain: any, hardfork: string) {
87 | const genesisBlock = new Block({ hardfork })
88 | genesisBlock.header = new BlockHeader(testData.genesisBlockHeader, { hardfork })
89 |
90 | await promisify(blockchain.putGenesis.bind(blockchain))(genesisBlock)
91 | }
92 |
93 | async function putBlocks(blockchain: any, hardfork: string, testData: any) {
94 | for (const blockData of testData.blocks) {
95 | const block = new Block(utils.toBuffer(blockData.rlp), { hardfork })
96 | await promisify(blockchain.putBlock.bind(blockchain))(block)
97 | }
98 | }
99 |
100 | main()
101 | .then(() => process.exit(0))
102 | .catch(err => {
103 | console.error(err)
104 | process.exit(1)
105 | })
106 |
--------------------------------------------------------------------------------
/examples/run-blockchain/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "run-blockchain",
3 | "private": true,
4 | "scripts": {
5 | "example": "ts-node index.ts"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/examples/run-code-browser/.gitignore:
--------------------------------------------------------------------------------
1 | bundle.js
2 |
--------------------------------------------------------------------------------
/examples/run-code-browser/README.md:
--------------------------------------------------------------------------------
1 | # Running the VM in a browser
2 |
3 | This directory contains an example on how to run the VM in a browser.
4 |
5 | The example does these things:
6 |
7 | 1. Instantiates a VM
8 | 1. Set ups a listener of the VM's `step` event
9 | 1. Runs a sample code in the VM
10 | 1. Logs the results
11 |
12 | ## Installation
13 |
14 | 1. Run `npm install` in the root of this project
15 | 1. Run `npm install` in this directory
16 |
17 | ## Running the example
18 |
19 | First, follow these instructions:
20 |
21 | 1. Run `npm run build:dist` in the root of this project
22 |
23 | ### Node
24 |
25 | 1. Run `npm run example:node` in this directory
26 |
27 | # Run Example in a Browser
28 |
29 | 1. `npm run example:browser`
30 | 1. Open [http://localhost:8080](http://localhost:8080) in a browser and check the result in web console.
31 |
--------------------------------------------------------------------------------
/examples/run-code-browser/index.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/run-code-browser/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Example - Running code on an ethereum-vm
3 | *
4 | *
5 | * To run this example in the browser, bundle this file
6 | * with browserify using `browserify index.js -o bundle.js`
7 | * and then load this folder onto a HTTP WebServer (e.g.
8 | * using node-static or `python -mSimpleHTTPServer`).
9 | */
10 | const BN = require('bn.js')
11 | const VM = require('../..').default
12 |
13 | // Create a new VM instance
14 | // For explicity setting the HF use e.g. `new VM({ hardfork: 'petersburg' })`
15 | const vm = new VM()
16 |
17 | const STOP = '00'
18 | const ADD = '01'
19 | const PUSH1 = '60'
20 |
21 | // Note that numbers added are hex values, so '20' would be '32' as decimal e.g.
22 | const code = [PUSH1, '03', PUSH1, '05', ADD, STOP]
23 |
24 | vm.on('step', function (data) {
25 | console.log(`Opcode: ${data.opcode.name}\tStack: ${data.stack}`)
26 | })
27 |
28 | vm.runCode({
29 | code: Buffer.from(code.join(''), 'hex'),
30 | gasLimit: new BN(0xffff),
31 | })
32 | .then(results => {
33 | console.log('Returned : ' + results.returnValue.toString('hex'))
34 | console.log('gasUsed : ' + results.gasUsed.toString())
35 | })
36 | .catch(console.error)
37 |
--------------------------------------------------------------------------------
/examples/run-code-browser/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "run-code-browser",
3 | "private": true,
4 | "scripts": {
5 | "example:node": "node index.js",
6 | "example:browser": "browserify index.js -o bundle.js && http-server"
7 | },
8 | "dependencies": {
9 | "browserify": "^16.2.3",
10 | "http-server": "^0.11.1"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/examples/run-solidity-contract/README.md:
--------------------------------------------------------------------------------
1 | # Running a Solidity smart contract using ethereumjs-vm
2 |
3 | This directory contains an example on how to run smart contracts written in Solidity.
4 |
5 | The example does these things:
6 |
7 | 1. Compiles the contract `contracts/Greeter.sol`
8 | 1. Instantiates a VM
9 | 1. Creates an account
10 | 1. Funds the account with 1 ETH
11 | 1. Deploys the Greeter contract
12 | 1. Calls a constant function
13 | 1. Sends a transaction to the contract, modifying its state
14 | 1. Calls a constant function to verify the state change
15 |
16 | ## Installation
17 |
18 | 1. Run `npm install` in the root of this project
19 | 1. Run `npm install` in this directory
20 |
21 | ## Running the example
22 |
23 | 1. Run `npm run build:dist` in the root of this project
24 | 1. Run `npm run example` in this directory
25 |
--------------------------------------------------------------------------------
/examples/run-solidity-contract/contracts/Greeter.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.10;
2 |
3 | contract Greeter {
4 |
5 | string greeting;
6 |
7 | constructor(string memory _greeting) public {
8 | greeting = _greeting;
9 | }
10 |
11 | function setGreeting(string memory _greeting) public {
12 | greeting = _greeting;
13 | }
14 |
15 | function greet() public view returns (string memory) {
16 | return greeting;
17 | }
18 |
19 | }
--------------------------------------------------------------------------------
/examples/run-solidity-contract/index.ts:
--------------------------------------------------------------------------------
1 | import VM from '../../dist'
2 |
3 | import * as assert from 'assert'
4 | import * as path from 'path'
5 | import * as fs from 'fs'
6 | import { promisify } from 'util'
7 | import * as util from 'ethereumjs-util'
8 | import Account from 'ethereumjs-account'
9 | import { Transaction } from 'ethereumjs-tx'
10 | const abi = require('ethereumjs-abi')
11 | const solc = require('solc')
12 |
13 | const INITIAL_GREETING = 'Hello, World!'
14 | const SECOND_GREETING = 'Hola, Mundo!'
15 |
16 | /**
17 | * This function creates the input for the Solidity compiler.
18 | *
19 | * For more info about it, go to https://solidity.readthedocs.io/en/v0.5.10/using-the-compiler.html#compiler-input-and-output-json-description
20 | */
21 | function getSolcInput() {
22 | return {
23 | language: 'Solidity',
24 | sources: {
25 | 'contracts/Greeter.sol': {
26 | content: fs.readFileSync(path.join(__dirname, 'contracts', 'Greeter.sol'), 'utf8'),
27 | },
28 | // If more contracts were to be compiled, they should have their own entries here
29 | },
30 | settings: {
31 | optimizer: {
32 | enabled: true,
33 | runs: 200,
34 | },
35 | evmVersion: 'petersburg',
36 | outputSelection: {
37 | '*': {
38 | '*': ['abi', 'evm.bytecode'],
39 | },
40 | },
41 | },
42 | }
43 | }
44 |
45 | /**
46 | * This function compiles all the contracts in `contracts/` and returns the Solidity Standard JSON
47 | * output. If the compilation fails, it returns `undefined`.
48 | *
49 | * To learn about the output format, go to https://solidity.readthedocs.io/en/v0.5.10/using-the-compiler.html#compiler-input-and-output-json-description
50 | */
51 | function compileContracts() {
52 | const input = getSolcInput()
53 | const output = JSON.parse(solc.compile(JSON.stringify(input)))
54 |
55 | let compilationFailed = false
56 |
57 | if (output.errors) {
58 | for (const error of output.errors) {
59 | if (error.severity === 'error') {
60 | console.error(error.formattedMessage)
61 | compilationFailed = true
62 | } else {
63 | console.warn(error.formattedMessage)
64 | }
65 | }
66 | }
67 |
68 | if (compilationFailed) {
69 | return undefined
70 | }
71 |
72 | return output
73 | }
74 |
75 | function getGreeterDeploymentBytecode(solcOutput: any): any {
76 | return solcOutput.contracts['contracts/Greeter.sol'].Greeter.evm.bytecode.object
77 | }
78 |
79 | async function getAccountNonce(vm: VM, accountPrivateKey: Buffer) {
80 | const account = (await promisify(vm.stateManager.getAccount.bind(vm.stateManager))(
81 | util.privateToAddress(accountPrivateKey),
82 | )) as Account
83 |
84 | return account.nonce
85 | }
86 |
87 | async function deployContract(
88 | vm: VM,
89 | senderPrivateKey: Buffer,
90 | deploymentBytecode: Buffer,
91 | greeting: string,
92 | ): Promise {
93 | // Contracts are deployed by sending their deployment bytecode to the address 0
94 | // The contract params should be abi-encoded and appended to the deployment bytecode.
95 | const params = abi.rawEncode(['string'], [greeting])
96 |
97 | const tx = new Transaction({
98 | value: 0,
99 | gasLimit: 2000000, // We assume that 2M is enough,
100 | gasPrice: 1,
101 | data: '0x' + deploymentBytecode + params.toString('hex'),
102 | nonce: await getAccountNonce(vm, senderPrivateKey),
103 | })
104 |
105 | tx.sign(senderPrivateKey)
106 |
107 | const deploymentResult = await vm.runTx({ tx })
108 |
109 | if (deploymentResult.execResult.exceptionError) {
110 | throw deploymentResult.execResult.exceptionError
111 | }
112 |
113 | return deploymentResult.createdAddress!
114 | }
115 |
116 | async function setGreeting(
117 | vm: VM,
118 | senderPrivateKey: Buffer,
119 | contractAddress: Buffer,
120 | greeting: string,
121 | ) {
122 | const params = abi.rawEncode(['string'], [greeting])
123 |
124 | const tx = new Transaction({
125 | to: contractAddress,
126 | value: 0,
127 | gasLimit: 2000000, // We assume that 2M is enough,
128 | gasPrice: 1,
129 | data: '0x' + abi.methodID('setGreeting', ['string']).toString('hex') + params.toString('hex'),
130 | nonce: await getAccountNonce(vm, senderPrivateKey),
131 | })
132 |
133 | tx.sign(senderPrivateKey)
134 |
135 | const setGreetingResult = await vm.runTx({ tx })
136 |
137 | if (setGreetingResult.execResult.exceptionError) {
138 | throw setGreetingResult.execResult.exceptionError
139 | }
140 | }
141 |
142 | async function getGreeting(vm: VM, contractAddress: Buffer, caller: Buffer) {
143 | const greetResult = await vm.runCall({
144 | to: contractAddress,
145 | caller: caller,
146 | origin: caller, // The tx.origin is also the caller here
147 | data: abi.methodID('greet', []),
148 | })
149 |
150 | if (greetResult.execResult.exceptionError) {
151 | throw greetResult.execResult.exceptionError
152 | }
153 |
154 | const results = abi.rawDecode(['string'], greetResult.execResult.returnValue)
155 |
156 | return results[0]
157 | }
158 |
159 | async function main() {
160 | const accountPk = new Buffer(
161 | 'e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109',
162 | 'hex',
163 | )
164 |
165 | const accountAddress = util.privateToAddress(accountPk)
166 |
167 | console.log('Account:', util.bufferToHex(accountAddress))
168 |
169 | const account = new Account({ balance: 1e18 })
170 |
171 | const vm = new VM()
172 | await promisify(vm.stateManager.putAccount.bind(vm.stateManager))(accountAddress, account)
173 |
174 | console.log('Set account a balance of 1 ETH')
175 |
176 | console.log('Compiling...')
177 |
178 | const solcOutput = compileContracts()
179 | if (solcOutput === undefined) {
180 | throw new Error('Compilation failed')
181 | } else {
182 | console.log('Compiled the contract')
183 | }
184 |
185 | const bytecode = getGreeterDeploymentBytecode(solcOutput)
186 |
187 | console.log('Deploying the contract...')
188 |
189 | const contractAddress = await deployContract(vm, accountPk, bytecode, INITIAL_GREETING)
190 |
191 | console.log('Contract address:', util.bufferToHex(contractAddress))
192 |
193 | const greeting = await getGreeting(vm, contractAddress, accountAddress)
194 |
195 | console.log('Greeting:', greeting)
196 |
197 | assert.equal(greeting, INITIAL_GREETING)
198 |
199 | console.log('Changing greeting...')
200 |
201 | await setGreeting(vm, accountPk, contractAddress, SECOND_GREETING)
202 |
203 | const greeting2 = await getGreeting(vm, contractAddress, accountAddress)
204 |
205 | console.log('Greeting:', greeting2)
206 |
207 | assert.equal(greeting2, SECOND_GREETING)
208 |
209 | console.log('Everything run correctly!')
210 | }
211 |
212 | main()
213 | .then(() => process.exit(0))
214 | .catch(err => {
215 | console.error(err)
216 | process.exit(1)
217 | })
218 |
--------------------------------------------------------------------------------
/examples/run-solidity-contract/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "run-solidity-contract",
3 | "private": true,
4 | "scripts": {
5 | "example": "ts-node index.ts"
6 | },
7 | "dependencies": {
8 | "ethereumjs-abi": "^0.6.7",
9 | "solc": "^0.5.10"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/examples/run-transactions-complete/README.md:
--------------------------------------------------------------------------------
1 | # Running transactions
2 |
3 | This directory contains an example on how to run transactions
4 |
5 | The example does these things:
6 |
7 | 1. Sends a transaction that deploys a contract
8 | 1. Sends a transaction that calls the deployed contract
9 | 1. Prints the results
10 |
11 | ## Installation
12 |
13 | 1. Run `npm install` in the root of this project`
14 |
15 | ## Running the example
16 |
17 | 1. Run `npm run build:dist` in the root of this project
18 | 1. Run `npm run example` in this directory
19 |
--------------------------------------------------------------------------------
/examples/run-transactions-complete/index.ts:
--------------------------------------------------------------------------------
1 | import VM from '../..'
2 | import Account from 'ethereumjs-account'
3 | import * as utils from 'ethereumjs-util'
4 | import PStateManager from '../../lib/state/promisified'
5 | import { Transaction } from 'ethereumjs-tx'
6 |
7 | async function main() {
8 | const vm = new VM()
9 | const psm = new PStateManager(vm.stateManager)
10 |
11 | // import the key pair
12 | // used to sign transactions and generate addresses
13 | const keyPair = require('./key-pair')
14 | const privateKey = utils.toBuffer(keyPair.secretKey)
15 |
16 | const publicKeyBuf = utils.toBuffer(keyPair.publicKey)
17 | const address = utils.pubToAddress(publicKeyBuf, true)
18 |
19 | console.log('---------------------')
20 | console.log('Sender address: ', utils.bufferToHex(address))
21 |
22 | // create a new account
23 | const account = new Account({
24 | balance: 100e18,
25 | })
26 |
27 | // Save the account
28 | await psm.putAccount(address, account)
29 |
30 | const rawTx1 = require('./raw-tx1')
31 | const rawTx2 = require('./raw-tx2')
32 |
33 | // The first transaction deploys a contract
34 | const createdAddress = (await runTx(vm, rawTx1, privateKey))!
35 |
36 | // The second transaction calls that contract
37 | await runTx(vm, rawTx2, privateKey)
38 |
39 | // Now lets look at what we created. The transaction
40 | // should have created a new account for the contract
41 | // in the state. Lets test to see if it did.
42 |
43 | const createdAccount = await psm.getAccount(createdAddress)
44 |
45 | console.log('-------results-------')
46 | console.log('nonce: ' + createdAccount.nonce.toString('hex'))
47 | console.log('balance in wei: ', createdAccount.balance.toString('hex') || 0)
48 | console.log('stateRoot: ' + createdAccount.stateRoot.toString('hex'))
49 | console.log('codeHash: ' + createdAccount.codeHash.toString('hex'))
50 | console.log('---------------------')
51 | }
52 |
53 | async function runTx(vm: VM, rawTx: any, privateKey: Buffer) {
54 | const tx = new Transaction(rawTx)
55 |
56 | tx.sign(privateKey)
57 |
58 | console.log('----running tx-------')
59 | const results = await vm.runTx({
60 | tx: tx,
61 | })
62 |
63 | console.log('gas used: ' + results.gasUsed.toString())
64 | console.log('returned: ' + results.execResult.returnValue.toString('hex'))
65 |
66 | const createdAddress = results.createdAddress
67 |
68 | if (createdAddress) {
69 | console.log('address created: ' + createdAddress.toString('hex'))
70 | return createdAddress
71 | }
72 | }
73 |
74 | main()
75 | .then(() => process.exit(0))
76 | .catch(error => {
77 | console.error(error)
78 | process.exit(1)
79 | })
80 |
--------------------------------------------------------------------------------
/examples/run-transactions-complete/key-pair.json:
--------------------------------------------------------------------------------
1 | {
2 | "secretKey": "0x3cd7232cd6f3fc66a57a6bedc1a8ed6c228fff0a327e169c2bcc5e869ed49511",
3 | "publicKey": "0x0406cc661590d48ee972944b35ad13ff03c7876eae3fd191e8a2f77311b0a3c6613407b5005e63d7d8d76b89d5f900cde691497688bb281e07a5052ff61edebdc0"
4 | }
5 |
--------------------------------------------------------------------------------
/examples/run-transactions-complete/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "run-transactions-complete",
3 | "private": true,
4 | "scripts": {
5 | "example": "ts-node index.ts"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/examples/run-transactions-complete/raw-tx1.json:
--------------------------------------------------------------------------------
1 | {
2 | "nonce": "0x00",
3 | "gasPrice": "0x09184e72a000",
4 | "gasLimit": "0x90710",
5 | "data": "0x60606040526103dd806100126000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063454a2ab31461004f578063b9a2de3a14610091578063edd481bb146100d35761004d565b005b6100656004808035906020019091905050610189565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100a760048080359060200190919050506102d2565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100e960048080359060200190919050506100ff565b6040518082815260200191505060405180910390f35b600060016000818150548092919060010191905055905080508143016000600050600083815260200190815260200160002060005060000160005081905550336000600050600083815260200190815260200160002060005060030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b919050565b60006000600060005060008481526020019081526020016000206000509050346012600a8360010160005054011811806101c95750438160000160005054115b1561022d573373ffffffffffffffffffffffffffffffffffffffff16600034604051809050600060405180830381858888f19350505050508060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691506102cc565b8060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660008260010160005054604051809050600060405180830381858888f1935050505050338160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055503481600101600050819055503391506102cc565b50919050565b600060006000600050600084815260200190815260200160002060005090508060000160005054431015156103d6578060030160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660008260010160005054604051809050600060405180830381858888f19350505050506000816001016000508190555060008160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055506000816000016000508190555060008160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b5b5091905056"
6 | }
7 |
8 |
--------------------------------------------------------------------------------
/examples/run-transactions-complete/raw-tx2.js:
--------------------------------------------------------------------------------
1 | var bidSig = '0x454a2ab3'
2 | var time = '0000000000000000000000000000000000000000000000000000000000000045'
3 |
4 | var rawTx2 = {
5 | nonce: '0x01',
6 | gasPrice: '0x09184e72a000',
7 | gasLimit: '0x20710',
8 | value: '0x10',
9 | to: '0x692a70d2e424a56d2c6c27aa97d1a86395877b3a',
10 | data: bidSig + time,
11 | }
12 |
13 | module.exports = rawTx2
14 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Fri Mar 01 2019 22:02:29 GMT+0100 (CET)
3 |
4 | module.exports = function(config) {
5 | config.set({
6 | // base path that will be used to resolve all patterns (eg. files, exclude)
7 | basePath: '',
8 |
9 | // frameworks to use
10 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
11 | frameworks: ['browserify', 'tap'],
12 |
13 | // list of files / patterns to load in the browser
14 | files: ['./tests/api/**/*.js'],
15 |
16 | // list of files / patterns to exclude
17 | exclude: [],
18 |
19 | // preprocess matching files before serving them to the browser
20 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
21 | preprocessors: {
22 | './tests/api/**/*.js': ['browserify'],
23 | },
24 |
25 | // test results reporter to use
26 | // possible values: 'dots', 'progress'
27 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
28 | reporters: ['progress'],
29 |
30 | // web server port
31 | port: 9876,
32 |
33 | // enable / disable colors in the output (reporters and logs)
34 | colors: true,
35 |
36 | // level of logging
37 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
38 | logLevel: config.LOG_INFO,
39 |
40 | // enable / disable watching file and executing tests whenever any file changes
41 | autoWatch: false,
42 |
43 | // start these browsers
44 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
45 | browsers: ['FirefoxHeadless', 'ChromeHeadless'],
46 |
47 | // Continuous Integration mode
48 | // if true, Karma captures browsers, runs the tests and exits
49 | singleRun: true,
50 |
51 | // Concurrency level
52 | // how many browser should be started simultaneous
53 | concurrency: Infinity,
54 |
55 | // Fail after timeout
56 | browserDisconnectTimeout: 100000,
57 | browserNoActivityTimeout: 100000,
58 | })
59 | }
60 |
--------------------------------------------------------------------------------
/lib/bloom/index.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'assert'
2 | import { zeros, keccak256 } from 'ethereumjs-util'
3 |
4 | const BYTE_SIZE = 256
5 |
6 | export default class Bloom {
7 | bitvector: Buffer
8 |
9 | /**
10 | * Represents a Bloom filter.
11 | */
12 | constructor(bitvector?: Buffer) {
13 | if (!bitvector) {
14 | this.bitvector = zeros(BYTE_SIZE)
15 | } else {
16 | assert(bitvector.length === BYTE_SIZE, 'bitvectors must be 2048 bits long')
17 | this.bitvector = bitvector
18 | }
19 | }
20 |
21 | /**
22 | * Adds an element to a bit vector of a 64 byte bloom filter.
23 | * @param e - The element to add
24 | */
25 | add(e: Buffer) {
26 | assert(Buffer.isBuffer(e), 'Element should be buffer')
27 | e = keccak256(e)
28 | const mask = 2047 // binary 11111111111
29 |
30 | for (let i = 0; i < 3; i++) {
31 | const first2bytes = e.readUInt16BE(i * 2)
32 | const loc = mask & first2bytes
33 | const byteLoc = loc >> 3
34 | const bitLoc = 1 << loc % 8
35 | this.bitvector[BYTE_SIZE - byteLoc - 1] |= bitLoc
36 | }
37 | }
38 |
39 | /**
40 | * Checks if an element is in the bloom.
41 | * @param e - The element to check
42 | */
43 | check(e: Buffer): boolean {
44 | assert(Buffer.isBuffer(e), 'Element should be Buffer')
45 | e = keccak256(e)
46 | const mask = 2047 // binary 11111111111
47 | let match = true
48 |
49 | for (let i = 0; i < 3 && match; i++) {
50 | const first2bytes = e.readUInt16BE(i * 2)
51 | const loc = mask & first2bytes
52 | const byteLoc = loc >> 3
53 | const bitLoc = 1 << loc % 8
54 | match = (this.bitvector[BYTE_SIZE - byteLoc - 1] & bitLoc) !== 0
55 | }
56 |
57 | return Boolean(match)
58 | }
59 |
60 | /**
61 | * Checks if multiple topics are in a bloom.
62 | * @returns `true` if every topic is in the bloom
63 | */
64 | multiCheck(topics: Buffer[]): boolean {
65 | return topics.every((t: Buffer) => this.check(t))
66 | }
67 |
68 | /**
69 | * Bitwise or blooms together.
70 | */
71 | or(bloom: Bloom) {
72 | if (bloom) {
73 | for (let i = 0; i <= BYTE_SIZE; i++) {
74 | this.bitvector[i] = this.bitvector[i] | bloom.bitvector[i]
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/lib/evm/interpreter.ts:
--------------------------------------------------------------------------------
1 | import BN = require('bn.js')
2 | import Common from 'ethereumjs-common'
3 | import { StateManager } from '../state'
4 | import PStateManager from '../state/promisified'
5 | import { ERROR, VmError } from '../exceptions'
6 | import Memory from './memory'
7 | import Stack from './stack'
8 | import EEI from './eei'
9 | import { Opcode } from './opcodes'
10 | import { handlers as opHandlers, OpHandler } from './opFns'
11 | import Account from 'ethereumjs-account'
12 |
13 | export interface InterpreterOpts {
14 | pc?: number
15 | }
16 |
17 | export interface RunState {
18 | programCounter: number
19 | opCode: number
20 | memory: Memory
21 | memoryWordCount: BN
22 | highestMemCost: BN
23 | stack: Stack
24 | code: Buffer
25 | validJumps: number[]
26 | _common: Common
27 | stateManager: StateManager
28 | eei: EEI
29 | }
30 |
31 | export interface InterpreterResult {
32 | runState?: RunState
33 | exceptionError?: VmError
34 | }
35 |
36 | export interface InterpreterStep {
37 | gasLeft: BN
38 | stateManager: StateManager
39 | stack: BN[]
40 | pc: number
41 | depth: number
42 | address: Buffer
43 | memory: number[]
44 | memoryWordCount: BN
45 | opcode: Opcode
46 | account: Account
47 | codeAddress: Buffer
48 | }
49 |
50 | /**
51 | * Parses and executes EVM bytecode.
52 | */
53 | export default class Interpreter {
54 | _vm: any
55 | _state: PStateManager
56 | _runState: RunState
57 | _eei: EEI
58 |
59 | constructor(vm: any, eei: EEI) {
60 | this._vm = vm // TODO: remove when not needed
61 | this._state = vm.pStateManager
62 | this._eei = eei
63 | this._runState = {
64 | programCounter: 0,
65 | opCode: 0xfe, // INVALID opcode
66 | memory: new Memory(),
67 | memoryWordCount: new BN(0),
68 | highestMemCost: new BN(0),
69 | stack: new Stack(),
70 | code: Buffer.alloc(0),
71 | validJumps: [],
72 | // TODO: Replace with EEI methods
73 | _common: this._vm._common,
74 | stateManager: this._state._wrapped,
75 | eei: this._eei,
76 | }
77 | }
78 |
79 | async run(code: Buffer, opts: InterpreterOpts = {}): Promise {
80 | this._runState.code = code
81 | this._runState.programCounter = opts.pc || this._runState.programCounter
82 | this._runState.validJumps = this._getValidJumpDests(code)
83 |
84 | // Check that the programCounter is in range
85 | const pc = this._runState.programCounter
86 | if (pc !== 0 && (pc < 0 || pc >= this._runState.code.length)) {
87 | throw new Error('Internal error: program counter not in range')
88 | }
89 |
90 | let err
91 | // Iterate through the given ops until something breaks or we hit STOP
92 | while (this._runState.programCounter < this._runState.code.length) {
93 | const opCode = this._runState.code[this._runState.programCounter]
94 | this._runState.opCode = opCode
95 | await this._runStepHook()
96 |
97 | try {
98 | await this.runStep()
99 | } catch (e) {
100 | // STOP is not an exception
101 | if (e.error !== ERROR.STOP) {
102 | err = e
103 | }
104 | // TODO: Throw on non-VmError exceptions
105 | break
106 | }
107 | }
108 |
109 | return {
110 | runState: this._runState,
111 | exceptionError: err,
112 | }
113 | }
114 |
115 | /**
116 | * Executes the opcode to which the program counter is pointing,
117 | * reducing it's base gas cost, and increments the program counter.
118 | */
119 | async runStep(): Promise {
120 | const opInfo = this.lookupOpInfo(this._runState.opCode)
121 | // Check for invalid opcode
122 | if (opInfo.name === 'INVALID') {
123 | throw new VmError(ERROR.INVALID_OPCODE)
124 | }
125 |
126 | // Reduce opcode's base fee
127 | this._eei.useGas(new BN(opInfo.fee))
128 | // Advance program counter
129 | this._runState.programCounter++
130 |
131 | // Execute opcode handler
132 | const opFn = this.getOpHandler(opInfo)
133 | if (opInfo.isAsync) {
134 | await opFn.apply(null, [this._runState])
135 | } else {
136 | opFn.apply(null, [this._runState])
137 | }
138 | }
139 |
140 | /**
141 | * Get the handler function for an opcode.
142 | */
143 | getOpHandler(opInfo: Opcode): OpHandler {
144 | return opHandlers[opInfo.name]
145 | }
146 |
147 | /**
148 | * Get info for an opcode from VM's list of opcodes.
149 | */
150 | lookupOpInfo(op: number, full: boolean = false): Opcode {
151 | const opcode = this._vm._opcodes[op]
152 | ? this._vm._opcodes[op]
153 | : { name: 'INVALID', fee: 0, isAsync: false }
154 |
155 | if (full) {
156 | let name = opcode.name
157 | if (name === 'LOG') {
158 | name += op - 0xa0
159 | }
160 |
161 | if (name === 'PUSH') {
162 | name += op - 0x5f
163 | }
164 |
165 | if (name === 'DUP') {
166 | name += op - 0x7f
167 | }
168 |
169 | if (name === 'SWAP') {
170 | name += op - 0x8f
171 | }
172 | return { ...opcode, ...{ name } }
173 | }
174 |
175 | return opcode
176 | }
177 |
178 | async _runStepHook(): Promise {
179 | const eventObj: InterpreterStep = {
180 | pc: this._runState.programCounter,
181 | gasLeft: this._eei.getGasLeft(),
182 | opcode: this.lookupOpInfo(this._runState.opCode, true),
183 | stack: this._runState.stack._store,
184 | depth: this._eei._env.depth,
185 | address: this._eei._env.address,
186 | account: this._eei._env.contract,
187 | stateManager: this._runState.stateManager,
188 | memory: this._runState.memory._store, // Return underlying array for backwards-compatibility
189 | memoryWordCount: this._runState.memoryWordCount,
190 | codeAddress: this._eei._env.codeAddress,
191 | }
192 | /**
193 | * The `step` event for trace output
194 | *
195 | * @event Event: step
196 | * @type {Object}
197 | * @property {Number} pc representing the program counter
198 | * @property {String} opcode the next opcode to be ran
199 | * @property {BN} gasLeft amount of gasLeft
200 | * @property {Array} stack an `Array` of `Buffers` containing the stack
201 | * @property {Account} account the [`Account`](https://github.com/ethereum/ethereumjs-account) which owns the code running
202 | * @property {Buffer} address the address of the `account`
203 | * @property {Number} depth the current number of calls deep the contract is
204 | * @property {Buffer} memory the memory of the VM as a `buffer`
205 | * @property {BN} memoryWordCount current size of memory in words
206 | * @property {StateManager} stateManager a [`StateManager`](stateManager.md) instance (Beta API)
207 | */
208 | return this._vm._emit('step', eventObj)
209 | }
210 |
211 | // Returns all valid jump destinations.
212 | _getValidJumpDests(code: Buffer): number[] {
213 | const jumps = []
214 |
215 | for (let i = 0; i < code.length; i++) {
216 | const curOpCode = this.lookupOpInfo(code[i]).name
217 |
218 | // no destinations into the middle of PUSH
219 | if (curOpCode === 'PUSH') {
220 | i += code[i] - 0x5f
221 | }
222 |
223 | if (curOpCode === 'JUMPDEST') {
224 | jumps.push(i)
225 | }
226 | }
227 |
228 | return jumps
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/lib/evm/memory.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'assert'
2 |
3 | /**
4 | * Memory implements a simple memory model
5 | * for the ethereum virtual machine.
6 | */
7 | export default class Memory {
8 | _store: number[]
9 |
10 | constructor() {
11 | this._store = []
12 | }
13 |
14 | /**
15 | * Extends the memory given an offset and size. Rounds extended
16 | * memory to word-size.
17 | */
18 | extend(offset: number, size: number) {
19 | if (size === 0) {
20 | return
21 | }
22 |
23 | const newSize = ceil(offset + size, 32)
24 | const sizeDiff = newSize - this._store.length
25 | if (sizeDiff > 0) {
26 | this._store = this._store.concat(new Array(sizeDiff).fill(0))
27 | }
28 | }
29 |
30 | /**
31 | * Writes a byte array with length `size` to memory, starting from `offset`.
32 | * @param offset - Starting position
33 | * @param size - How many bytes to write
34 | * @param value - Value
35 | */
36 | write(offset: number, size: number, value: Buffer) {
37 | if (size === 0) {
38 | return
39 | }
40 |
41 | assert(value.length === size, 'Invalid value size')
42 | assert(offset + size <= this._store.length, 'Value exceeds memory capacity')
43 | assert(Buffer.isBuffer(value), 'Invalid value type')
44 |
45 | for (let i = 0; i < size; i++) {
46 | this._store[offset + i] = value[i]
47 | }
48 | }
49 |
50 | /**
51 | * Reads a slice of memory from `offset` till `offset + size` as a `Buffer`.
52 | * It fills up the difference between memory's length and `offset + size` with zeros.
53 | * @param offset - Starting position
54 | * @param size - How many bytes to read
55 | */
56 | read(offset: number, size: number): Buffer {
57 | const loaded = this._store.slice(offset, offset + size)
58 | // Fill the remaining length with zeros
59 | for (let i = loaded.length; i < size; i++) {
60 | loaded[i] = 0
61 | }
62 | return Buffer.from(loaded)
63 | }
64 | }
65 |
66 | const ceil = (value: number, ceiling: number): number => {
67 | const r = value % ceiling
68 | if (r === 0) {
69 | return value
70 | } else {
71 | return value + ceiling - r
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/lib/evm/message.ts:
--------------------------------------------------------------------------------
1 | import BN = require('bn.js')
2 | import { PrecompileFunc } from './precompiles'
3 |
4 | export default class Message {
5 | to: Buffer
6 | value: BN
7 | caller: Buffer
8 | gasLimit: BN
9 | data: Buffer
10 | depth: number
11 | code: Buffer | PrecompileFunc
12 | _codeAddress: Buffer
13 | isStatic: boolean
14 | isCompiled: boolean
15 | salt: Buffer
16 | selfdestruct: any
17 | delegatecall: boolean
18 |
19 | constructor(opts: any) {
20 | this.to = opts.to
21 | this.value = opts.value ? new BN(opts.value) : new BN(0)
22 | this.caller = opts.caller
23 | this.gasLimit = opts.gasLimit
24 | this.data = opts.data || Buffer.alloc(0)
25 | this.depth = opts.depth || 0
26 | this.code = opts.code
27 | this._codeAddress = opts.codeAddress
28 | this.isStatic = opts.isStatic || false
29 | this.isCompiled = opts.isCompiled || false // For CALLCODE, TODO: Move from here
30 | this.salt = opts.salt // For CREATE2, TODO: Move from here
31 | this.selfdestruct = opts.selfdestruct // TODO: Move from here
32 | this.delegatecall = opts.delegatecall || false
33 | }
34 |
35 | get codeAddress(): Buffer {
36 | return this._codeAddress ? this._codeAddress : this.to
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/evm/precompiles/01-ecrecover.ts:
--------------------------------------------------------------------------------
1 | import BN = require('bn.js')
2 | import { setLengthLeft, setLengthRight, ecrecover, publicToAddress } from 'ethereumjs-util'
3 | import { PrecompileInput } from './types'
4 | import { OOGResult, ExecResult } from '../evm'
5 | const assert = require('assert')
6 |
7 | export default function(opts: PrecompileInput): ExecResult {
8 | assert(opts.data)
9 |
10 | const gasUsed = new BN(opts._common.param('gasPrices', 'ecRecover'))
11 |
12 | if (opts.gasLimit.lt(gasUsed)) {
13 | return OOGResult(opts.gasLimit)
14 | }
15 |
16 | const data = setLengthRight(opts.data, 128)
17 |
18 | var msgHash = data.slice(0, 32)
19 | const v = data.slice(32, 64)
20 | const r = data.slice(64, 96)
21 | const s = data.slice(96, 128)
22 |
23 | let publicKey
24 | try {
25 | publicKey = ecrecover(msgHash, new BN(v).toNumber(), r, s)
26 | } catch (e) {
27 | return {
28 | gasUsed,
29 | returnValue: Buffer.alloc(0),
30 | }
31 | }
32 |
33 | return {
34 | gasUsed,
35 | returnValue: setLengthLeft(publicToAddress(publicKey), 32),
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/evm/precompiles/02-sha256.ts:
--------------------------------------------------------------------------------
1 | import BN = require('bn.js')
2 | import { sha256 } from 'ethereumjs-util'
3 | import { PrecompileInput } from './types'
4 | import { OOGResult, ExecResult } from '../evm'
5 | const assert = require('assert')
6 |
7 | export default function(opts: PrecompileInput): ExecResult {
8 | assert(opts.data)
9 |
10 | const data = opts.data
11 |
12 | const gasUsed = new BN(opts._common.param('gasPrices', 'sha256'))
13 | gasUsed.iadd(
14 | new BN(opts._common.param('gasPrices', 'sha256Word')).imuln(Math.ceil(data.length / 32)),
15 | )
16 |
17 | if (opts.gasLimit.lt(gasUsed)) {
18 | return OOGResult(opts.gasLimit)
19 | }
20 |
21 | return {
22 | gasUsed,
23 | returnValue: sha256(data),
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/evm/precompiles/03-ripemd160.ts:
--------------------------------------------------------------------------------
1 | import BN = require('bn.js')
2 | import { ripemd160 } from 'ethereumjs-util'
3 | import { PrecompileInput } from './types'
4 | import { OOGResult, ExecResult } from '../evm'
5 | const assert = require('assert')
6 |
7 | export default function(opts: PrecompileInput): ExecResult {
8 | assert(opts.data)
9 |
10 | const data = opts.data
11 |
12 | const gasUsed = new BN(opts._common.param('gasPrices', 'ripemd160'))
13 | gasUsed.iadd(
14 | new BN(opts._common.param('gasPrices', 'ripemd160Word')).imuln(Math.ceil(data.length / 32)),
15 | )
16 |
17 | if (opts.gasLimit.lt(gasUsed)) {
18 | return OOGResult(opts.gasLimit)
19 | }
20 |
21 | return {
22 | gasUsed,
23 | returnValue: ripemd160(data, true),
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/evm/precompiles/04-identity.ts:
--------------------------------------------------------------------------------
1 | import BN = require('bn.js')
2 | import { PrecompileInput } from './types'
3 | import { OOGResult, ExecResult } from '../evm'
4 | const assert = require('assert')
5 |
6 | export default function(opts: PrecompileInput): ExecResult {
7 | assert(opts.data)
8 |
9 | const data = opts.data
10 |
11 | const gasUsed = new BN(opts._common.param('gasPrices', 'identity'))
12 | gasUsed.iadd(
13 | new BN(opts._common.param('gasPrices', 'identityWord')).imuln(Math.ceil(data.length / 32)),
14 | )
15 |
16 | if (opts.gasLimit.lt(gasUsed)) {
17 | return OOGResult(opts.gasLimit)
18 | }
19 |
20 | return {
21 | gasUsed,
22 | returnValue: data,
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/evm/precompiles/05-modexp.ts:
--------------------------------------------------------------------------------
1 | import BN = require('bn.js')
2 | import { setLengthRight } from 'ethereumjs-util'
3 | import { PrecompileInput } from './types'
4 | import { OOGResult, ExecResult } from '../evm'
5 | const assert = require('assert')
6 |
7 | function multComplexity(x: BN): BN {
8 | var fac1
9 | var fac2
10 | if (x.lten(64)) {
11 | return x.sqr()
12 | } else if (x.lten(1024)) {
13 | // return Math.floor(Math.pow(x, 2) / 4) + 96 * x - 3072
14 | fac1 = x.sqr().divn(4)
15 | fac2 = x.muln(96)
16 | return fac1.add(fac2).subn(3072)
17 | } else {
18 | // return Math.floor(Math.pow(x, 2) / 16) + 480 * x - 199680
19 | fac1 = x.sqr().divn(16)
20 | fac2 = x.muln(480)
21 | return fac1.add(fac2).subn(199680)
22 | }
23 | }
24 |
25 | function getAdjustedExponentLength(data: Buffer): BN {
26 | var expBytesStart
27 | try {
28 | var baseLen = new BN(data.slice(0, 32)).toNumber()
29 | expBytesStart = 96 + baseLen // 96 for base length, then exponent length, and modulus length, then baseLen for the base data, then exponent bytes start
30 | } catch (e) {
31 | expBytesStart = Number.MAX_SAFE_INTEGER - 32
32 | }
33 | var expLen = new BN(data.slice(32, 64))
34 | var firstExpBytes = Buffer.from(data.slice(expBytesStart, expBytesStart + 32)) // first word of the exponent data
35 | firstExpBytes = setLengthRight(firstExpBytes, 32) // reading past the data reads virtual zeros
36 | let firstExpBN = new BN(firstExpBytes)
37 | var max32expLen = 0
38 | if (expLen.ltn(32)) {
39 | max32expLen = 32 - expLen.toNumber()
40 | }
41 | firstExpBN = firstExpBN.shrn(8 * Math.max(max32expLen, 0))
42 |
43 | var bitLen = -1
44 | while (firstExpBN.gtn(0)) {
45 | bitLen = bitLen + 1
46 | firstExpBN = firstExpBN.ushrn(1)
47 | }
48 | var expLenMinus32OrZero = expLen.subn(32)
49 | if (expLenMinus32OrZero.ltn(0)) {
50 | expLenMinus32OrZero = new BN(0)
51 | }
52 | var eightTimesExpLenMinus32OrZero = expLenMinus32OrZero.muln(8)
53 | var adjustedExpLen = eightTimesExpLenMinus32OrZero
54 | if (bitLen > 0) {
55 | adjustedExpLen.iaddn(bitLen)
56 | }
57 | return adjustedExpLen
58 | }
59 |
60 | function expmod(B: BN, E: BN, M: BN): BN {
61 | if (E.isZero()) return new BN(1).mod(M)
62 | // Red asserts M > 1
63 | if (M.lten(1)) return new BN(0)
64 | const red = BN.red(M)
65 | const redB = B.toRed(red)
66 | const res = redB.redPow(E)
67 | return res.fromRed()
68 | }
69 |
70 | export default function(opts: PrecompileInput): ExecResult {
71 | assert(opts.data)
72 |
73 | const data = opts.data
74 |
75 | let adjustedELen = getAdjustedExponentLength(data)
76 | if (adjustedELen.ltn(1)) {
77 | adjustedELen = new BN(1)
78 | }
79 |
80 | const bLen = new BN(data.slice(0, 32))
81 | const eLen = new BN(data.slice(32, 64))
82 | const mLen = new BN(data.slice(64, 96))
83 |
84 | let maxLen = bLen
85 | if (maxLen.lt(mLen)) {
86 | maxLen = mLen
87 | }
88 | const Gquaddivisor = opts._common.param('gasPrices', 'modexpGquaddivisor')
89 | const gasUsed = adjustedELen.mul(multComplexity(maxLen)).divn(Gquaddivisor)
90 |
91 | if (opts.gasLimit.lt(gasUsed)) {
92 | return OOGResult(opts.gasLimit)
93 | }
94 |
95 | if (bLen.isZero()) {
96 | return {
97 | gasUsed,
98 | returnValue: new BN(0).toArrayLike(Buffer, 'be', 1),
99 | }
100 | }
101 |
102 | if (mLen.isZero()) {
103 | return {
104 | gasUsed,
105 | returnValue: Buffer.alloc(0),
106 | }
107 | }
108 |
109 | const maxInt = new BN(Number.MAX_SAFE_INTEGER)
110 | const maxSize = new BN(2147483647) // ethereumjs-util setLengthRight limitation
111 |
112 | if (bLen.gt(maxSize) || eLen.gt(maxSize) || mLen.gt(maxSize)) {
113 | return OOGResult(opts.gasLimit)
114 | }
115 |
116 | const bStart = new BN(96)
117 | const bEnd = bStart.add(bLen)
118 | const eStart = bEnd
119 | const eEnd = eStart.add(eLen)
120 | const mStart = eEnd
121 | const mEnd = mStart.add(mLen)
122 |
123 | if (mEnd.gt(maxInt)) {
124 | return OOGResult(opts.gasLimit)
125 | }
126 |
127 | const B = new BN(setLengthRight(data.slice(bStart.toNumber(), bEnd.toNumber()), bLen.toNumber()))
128 | const E = new BN(setLengthRight(data.slice(eStart.toNumber(), eEnd.toNumber()), eLen.toNumber()))
129 | const M = new BN(setLengthRight(data.slice(mStart.toNumber(), mEnd.toNumber()), mLen.toNumber()))
130 |
131 | let R
132 | if (M.isZero()) {
133 | R = new BN(0)
134 | } else {
135 | R = expmod(B, E, M)
136 | }
137 |
138 | return {
139 | gasUsed,
140 | returnValue: R.toArrayLike(Buffer, 'be', mLen.toNumber()),
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/lib/evm/precompiles/06-ecadd.ts:
--------------------------------------------------------------------------------
1 | import BN = require('bn.js')
2 | import { PrecompileInput } from './types'
3 | import { OOGResult, ExecResult } from '../evm'
4 | const assert = require('assert')
5 | const bn128 = require('rustbn.js')
6 |
7 | export default function(opts: PrecompileInput): ExecResult {
8 | assert(opts.data)
9 |
10 | let inputData = opts.data
11 |
12 | const gasUsed = new BN(opts._common.param('gasPrices', 'ecAdd'))
13 | if (opts.gasLimit.lt(gasUsed)) {
14 | return OOGResult(opts.gasLimit)
15 | }
16 |
17 | const returnData = bn128.add(inputData)
18 |
19 | // check ecadd success or failure by comparing the output length
20 | if (returnData.length !== 64) {
21 | return OOGResult(opts.gasLimit)
22 | }
23 |
24 | return {
25 | gasUsed,
26 | returnValue: returnData,
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/evm/precompiles/07-ecmul.ts:
--------------------------------------------------------------------------------
1 | import BN = require('bn.js')
2 | import { PrecompileInput } from './types'
3 | import { OOGResult, ExecResult } from '../evm'
4 | const assert = require('assert')
5 | const bn128 = require('rustbn.js')
6 |
7 | export default function(opts: PrecompileInput): ExecResult {
8 | assert(opts.data)
9 |
10 | const inputData = opts.data
11 | const gasUsed = new BN(opts._common.param('gasPrices', 'ecMul'))
12 |
13 | if (opts.gasLimit.lt(gasUsed)) {
14 | return OOGResult(opts.gasLimit)
15 | }
16 |
17 | let returnData = bn128.mul(inputData)
18 | // check ecmul success or failure by comparing the output length
19 | if (returnData.length !== 64) {
20 | return OOGResult(opts.gasLimit)
21 | }
22 |
23 | return {
24 | gasUsed,
25 | returnValue: returnData,
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/evm/precompiles/08-ecpairing.ts:
--------------------------------------------------------------------------------
1 | import BN = require('bn.js')
2 | import { PrecompileInput } from './types'
3 | import { OOGResult, ExecResult } from '../evm'
4 | const assert = require('assert')
5 | const bn128 = require('rustbn.js')
6 |
7 | export default function(opts: PrecompileInput): ExecResult {
8 | assert(opts.data)
9 |
10 | const inputData = opts.data
11 | // no need to care about non-divisible-by-192, because bn128.pairing will properly fail in that case
12 | const inputDataSize = Math.floor(inputData.length / 192)
13 | const gasUsed = new BN(
14 | opts._common.param('gasPrices', 'ecPairing') +
15 | inputDataSize * opts._common.param('gasPrices', 'ecPairingWord'),
16 | )
17 |
18 | if (opts.gasLimit.lt(gasUsed)) {
19 | return OOGResult(opts.gasLimit)
20 | }
21 |
22 | const returnData = bn128.pairing(inputData)
23 |
24 | // check ecpairing success or failure by comparing the output length
25 | if (returnData.length !== 32) {
26 | return OOGResult(opts.gasLimit)
27 | }
28 |
29 | return {
30 | gasUsed,
31 | returnValue: returnData,
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/evm/precompiles/index.ts:
--------------------------------------------------------------------------------
1 | import { PrecompileInput, PrecompileFunc } from './types'
2 | import { default as p1 } from './01-ecrecover'
3 | import { default as p2 } from './02-sha256'
4 | import { default as p3 } from './03-ripemd160'
5 | import { default as p4 } from './04-identity'
6 | import { default as p5 } from './05-modexp'
7 | import { default as p6 } from './06-ecadd'
8 | import { default as p7 } from './07-ecmul'
9 | import { default as p8 } from './08-ecpairing'
10 | import { default as p9 } from './09-blake2f'
11 |
12 | interface Precompiles {
13 | [key: string]: PrecompileFunc
14 | }
15 |
16 | const ripemdPrecompileAddress = '0000000000000000000000000000000000000003'
17 | const precompiles: Precompiles = {
18 | '0000000000000000000000000000000000000001': p1,
19 | '0000000000000000000000000000000000000002': p2,
20 | [ripemdPrecompileAddress]: p3,
21 | '0000000000000000000000000000000000000004': p4,
22 | '0000000000000000000000000000000000000005': p5,
23 | '0000000000000000000000000000000000000006': p6,
24 | '0000000000000000000000000000000000000007': p7,
25 | '0000000000000000000000000000000000000008': p8,
26 | '0000000000000000000000000000000000000009': p9,
27 | }
28 |
29 | function getPrecompile(address: string): PrecompileFunc {
30 | return precompiles[address]
31 | }
32 |
33 | export { precompiles, getPrecompile, PrecompileFunc, PrecompileInput, ripemdPrecompileAddress }
34 |
--------------------------------------------------------------------------------
/lib/evm/precompiles/types.ts:
--------------------------------------------------------------------------------
1 | import BN = require('bn.js')
2 | import Common from 'ethereumjs-common'
3 | import { ExecResult } from '../evm'
4 |
5 | export interface PrecompileFunc {
6 | (opts: PrecompileInput): ExecResult
7 | }
8 |
9 | export interface PrecompileInput {
10 | data: Buffer
11 | gasLimit: BN
12 | _common: Common
13 | }
14 |
--------------------------------------------------------------------------------
/lib/evm/stack.ts:
--------------------------------------------------------------------------------
1 | import BN = require('bn.js')
2 | import { MAX_INTEGER } from 'ethereumjs-util'
3 | const { ERROR, VmError } = require('../exceptions')
4 |
5 | /**
6 | * Implementation of the stack used in evm.
7 | */
8 | export default class Stack {
9 | _store: BN[]
10 |
11 | constructor() {
12 | this._store = []
13 | }
14 |
15 | get length() {
16 | return this._store.length
17 | }
18 |
19 | push(value: BN) {
20 | if (!BN.isBN(value)) {
21 | throw new VmError(ERROR.INTERNAL_ERROR)
22 | }
23 |
24 | if (value.gt(MAX_INTEGER)) {
25 | throw new VmError(ERROR.OUT_OF_RANGE)
26 | }
27 |
28 | if (this._store.length > 1023) {
29 | throw new VmError(ERROR.STACK_OVERFLOW)
30 | }
31 |
32 | this._store.push(value)
33 | }
34 |
35 | pop(): BN {
36 | if (this._store.length < 1) {
37 | throw new VmError(ERROR.STACK_UNDERFLOW)
38 | }
39 |
40 | // Length is checked above, so pop shouldn't return undefined
41 | return this._store.pop()!
42 | }
43 |
44 | /**
45 | * Pop multiple items from stack. Top of stack is first item
46 | * in returned array.
47 | * @param num - Number of items to pop
48 | */
49 | popN(num: number = 1): BN[] {
50 | if (this._store.length < num) {
51 | throw new VmError(ERROR.STACK_UNDERFLOW)
52 | }
53 |
54 | if (num === 0) {
55 | return []
56 | }
57 |
58 | return this._store.splice(-1 * num).reverse()
59 | }
60 |
61 | /**
62 | * Swap top of stack with an item in the stack.
63 | * @param position - Index of item from top of the stack (0-indexed)
64 | */
65 | swap(position: number) {
66 | if (this._store.length <= position) {
67 | throw new VmError(ERROR.STACK_UNDERFLOW)
68 | }
69 |
70 | const head = this._store.length - 1
71 | const i = this._store.length - position - 1
72 |
73 | const tmp = this._store[head]
74 | this._store[head] = this._store[i]
75 | this._store[i] = tmp
76 | }
77 |
78 | /**
79 | * Pushes a copy of an item in the stack.
80 | * @param position - Index of item to be copied (1-indexed)
81 | */
82 | dup(position: number) {
83 | if (this._store.length < position) {
84 | throw new VmError(ERROR.STACK_UNDERFLOW)
85 | }
86 |
87 | const i = this._store.length - position
88 | this.push(this._store[i])
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/lib/evm/txContext.ts:
--------------------------------------------------------------------------------
1 | export default class TxContext {
2 | gasPrice: Buffer
3 | origin: Buffer
4 |
5 | constructor(gasPrice: Buffer, origin: Buffer) {
6 | this.gasPrice = gasPrice
7 | this.origin = origin
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/lib/exceptions.ts:
--------------------------------------------------------------------------------
1 | export enum ERROR {
2 | OUT_OF_GAS = 'out of gas',
3 | STACK_UNDERFLOW = 'stack underflow',
4 | STACK_OVERFLOW = 'stack overflow',
5 | INVALID_JUMP = 'invalid JUMP',
6 | INVALID_OPCODE = 'invalid opcode',
7 | OUT_OF_RANGE = 'value out of range',
8 | REVERT = 'revert',
9 | STATIC_STATE_CHANGE = 'static state change',
10 | INTERNAL_ERROR = 'internal error',
11 | CREATE_COLLISION = 'create collision',
12 | STOP = 'stop',
13 | REFUND_EXHAUSTED = 'refund exhausted',
14 | }
15 |
16 | export class VmError {
17 | error: ERROR
18 | errorType: string
19 |
20 | constructor(error: ERROR) {
21 | this.error = error
22 | this.errorType = 'VmError'
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/runBlockchain.ts:
--------------------------------------------------------------------------------
1 | import Blockchain from 'ethereumjs-blockchain'
2 | import VM from './index'
3 | const async = require('async')
4 |
5 | /**
6 | * @ignore
7 | */
8 | export default function runBlockchain(this: VM, blockchain: Blockchain): Promise {
9 | return new Promise((resolve, reject) => {
10 | const self = this
11 | let headBlock: any
12 | let parentState: Buffer
13 |
14 | blockchain = blockchain || this.blockchain
15 |
16 | // setup blockchain iterator
17 | blockchain.iterator('vm', processBlock, (err: Error) => {
18 | if (err) {
19 | reject(err)
20 | } else {
21 | resolve()
22 | }
23 | })
24 |
25 | function processBlock(block: any, reorg: boolean, cb: any) {
26 | async.series([getStartingState, runBlock], cb)
27 |
28 | // determine starting state for block run
29 | function getStartingState(cb: any) {
30 | // if we are just starting or if a chain re-org has happened
31 | if (!headBlock || reorg) {
32 | blockchain.getBlock(block.header.parentHash, function(err: any, parentBlock: any) {
33 | parentState = parentBlock.header.stateRoot
34 | // generate genesis state if we are at the genesis block
35 | // we don't have the genesis state
36 | if (!headBlock) {
37 | return self.stateManager.generateCanonicalGenesis(cb)
38 | } else {
39 | cb(err)
40 | }
41 | })
42 | } else {
43 | parentState = headBlock.header.stateRoot
44 | cb()
45 | }
46 | }
47 |
48 | // run block, update head if valid
49 | function runBlock(cb: any) {
50 | self
51 | .runBlock({
52 | block: block,
53 | root: parentState,
54 | })
55 | .then(() => {
56 | // set as new head block
57 | headBlock = block
58 | cb()
59 | })
60 | .catch(err => {
61 | // remove invalid block
62 | blockchain.delBlock(block.header.hash(), function() {
63 | cb(err)
64 | })
65 | })
66 | }
67 | }
68 | })
69 | }
70 |
--------------------------------------------------------------------------------
/lib/runCall.ts:
--------------------------------------------------------------------------------
1 | import BN = require('bn.js')
2 | import { zeros } from 'ethereumjs-util'
3 | import VM from './index'
4 | import TxContext from './evm/txContext'
5 | import Message from './evm/message'
6 | import { default as EVM, EVMResult } from './evm/evm'
7 | const Block = require('ethereumjs-block')
8 |
9 | /**
10 | * Options for running a call (or create) operation
11 | */
12 | export interface RunCallOpts {
13 | block?: any
14 | gasPrice?: Buffer
15 | origin?: Buffer
16 | caller?: Buffer
17 | gasLimit?: Buffer
18 | to?: Buffer
19 | value?: Buffer
20 | data?: Buffer
21 | /**
22 | * This is for CALLCODE where the code to load is different than the code from the to account
23 | */
24 | code?: Buffer
25 | depth?: number
26 | compiled?: boolean
27 | static?: boolean
28 | salt?: Buffer
29 | selfdestruct?: { [k: string]: boolean }
30 | delegatecall?: boolean
31 | }
32 |
33 | /**
34 | * @ignore
35 | */
36 | export default function runCall(this: VM, opts: RunCallOpts): Promise {
37 | const block = opts.block || new Block()
38 |
39 | const txContext = new TxContext(
40 | opts.gasPrice || Buffer.alloc(0),
41 | opts.origin || opts.caller || zeros(32),
42 | )
43 | const message = new Message({
44 | caller: opts.caller,
45 | gasLimit: opts.gasLimit ? new BN(opts.gasLimit) : new BN(0xffffff),
46 | to: opts.to && opts.to.toString('hex') !== '' ? opts.to : undefined,
47 | value: opts.value,
48 | data: opts.data,
49 | code: opts.code,
50 | depth: opts.depth || 0,
51 | isCompiled: opts.compiled || false,
52 | isStatic: opts.static || false,
53 | salt: opts.salt || null,
54 | selfdestruct: opts.selfdestruct || {},
55 | delegatecall: opts.delegatecall || false,
56 | })
57 |
58 | const evm = new EVM(this, txContext, block)
59 | return evm.executeMessage(message)
60 | }
61 |
--------------------------------------------------------------------------------
/lib/runCode.ts:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | This is the core of the Ethereum Virtual Machine (EVM or just VM).
4 |
5 | NOTES:
6 |
7 | stack items are lazily duplicated.
8 | So you must never directly change a buffer from the stack,
9 | instead you should `copy` it first
10 |
11 | not all stack items are 32 bytes, so if the operation relies on the stack
12 | item length then you must use utils.pad(- , 32) first.
13 | */
14 | import { zeros } from 'ethereumjs-util'
15 | import VM from './index'
16 | import TxContext from './evm/txContext'
17 | import Message from './evm/message'
18 | import { default as EVM, ExecResult } from './evm/evm'
19 | const Block = require('ethereumjs-block')
20 |
21 | /**
22 | * Options for the [[runCode]] method.
23 | */
24 | export interface RunCodeOpts {
25 | /**
26 | * The [`Block`](https://github.com/ethereumjs/ethereumjs-block) the `tx` belongs to. If omitted a blank block will be used
27 | */
28 | block?: any
29 | evm?: EVM
30 | txContext?: TxContext
31 | gasPrice?: Buffer
32 | /**
33 | * The address where the call originated from. The address should be a `Buffer` of 20 bits. Defaults to `0`
34 | */
35 | origin?: Buffer
36 | message?: Message
37 | /**
38 | * The address that ran this code. The address should be a `Buffer` of 20 bits. Defaults to `0`
39 | */
40 | caller?: Buffer
41 | /**
42 | * The EVM code to run
43 | */
44 | code?: Buffer
45 | /**
46 | * The input data
47 | */
48 | data?: Buffer
49 | /**
50 | * Gas limit
51 | */
52 | gasLimit?: Buffer
53 | /**
54 | * The value in ether that is being sent to `opt.address`. Defaults to `0`
55 | */
56 | value?: Buffer
57 | depth?: number
58 | isStatic?: boolean
59 | selfdestruct?: { [k: string]: boolean }
60 | /**
61 | * The address of the account that is executing this code. The address should be a `Buffer` of bytes. Defaults to `0`
62 | */
63 | address?: Buffer
64 | /**
65 | * The initial program counter. Defaults to `0`
66 | */
67 | pc?: number
68 | }
69 |
70 | /**
71 | * @ignore
72 | */
73 | export default function runCode(this: VM, opts: RunCodeOpts): Promise {
74 | if (!opts.block) {
75 | opts.block = new Block()
76 | }
77 |
78 | // Backwards compatibility
79 | if (!opts.txContext) {
80 | opts.txContext = new TxContext(
81 | opts.gasPrice || Buffer.alloc(0),
82 | opts.origin || opts.caller || zeros(32),
83 | )
84 | }
85 | if (!opts.message) {
86 | opts.message = new Message({
87 | code: opts.code,
88 | data: opts.data,
89 | gasLimit: opts.gasLimit,
90 | to: opts.address || zeros(32),
91 | caller: opts.caller,
92 | value: opts.value,
93 | depth: opts.depth || 0,
94 | selfdestruct: opts.selfdestruct || {},
95 | isStatic: opts.isStatic || false,
96 | })
97 | }
98 |
99 | let evm = opts.evm
100 | if (!evm) {
101 | evm = new EVM(this, opts.txContext, opts.block)
102 | }
103 |
104 | return evm.runInterpreter(opts.message, { pc: opts.pc })
105 | }
106 |
--------------------------------------------------------------------------------
/lib/runTx.ts:
--------------------------------------------------------------------------------
1 | import BN = require('bn.js')
2 | import { toBuffer } from 'ethereumjs-util'
3 | import Account from 'ethereumjs-account'
4 | import { Transaction } from 'ethereumjs-tx'
5 | import VM from './index'
6 | import Bloom from './bloom'
7 | import { default as EVM, EVMResult } from './evm/evm'
8 | import Message from './evm/message'
9 | import TxContext from './evm/txContext'
10 | import PStateManager from './state/promisified'
11 | const Block = require('ethereumjs-block')
12 |
13 | /**
14 | * Options for the `runTx` method.
15 | */
16 | export interface RunTxOpts {
17 | /**
18 | * The block to which the `tx` belongs
19 | */
20 | block?: any
21 | /**
22 | * A [`Transaction`](https://github.com/ethereum/ethereumjs-tx) to run
23 | */
24 | tx: Transaction
25 | /**
26 | * If true, skips the nonce check
27 | */
28 | skipNonce?: boolean
29 | /**
30 | * If true, skips the balance check
31 | */
32 | skipBalance?: boolean
33 | }
34 |
35 | /**
36 | * Execution result of a transaction
37 | */
38 | export interface RunTxResult extends EVMResult {
39 | /**
40 | * Bloom filter resulted from transaction
41 | */
42 | bloom: Bloom
43 | /**
44 | * The amount of ether used by this transaction
45 | */
46 | amountSpent: BN
47 | /**
48 | * The amount of gas as that was refunded during the transaction (i.e. `gasUsed = totalGasConsumed - gasRefund`)
49 | */
50 | gasRefund?: BN
51 | }
52 |
53 | /**
54 | * @ignore
55 | */
56 | export default async function runTx(this: VM, opts: RunTxOpts): Promise {
57 | if (opts === undefined) {
58 | throw new Error('invalid input, opts must be provided')
59 | }
60 |
61 | // tx is required
62 | if (!opts.tx) {
63 | throw new Error('invalid input, tx is required')
64 | }
65 |
66 | // create a reasonable default if no block is given
67 | if (!opts.block) {
68 | opts.block = new Block()
69 | }
70 |
71 | if (new BN(opts.block.header.gasLimit).lt(new BN(opts.tx.gasLimit))) {
72 | throw new Error('tx has a higher gas limit than the block')
73 | }
74 |
75 | const state = this.pStateManager
76 |
77 | await state.checkpoint()
78 |
79 | try {
80 | const result = await _runTx.bind(this)(opts)
81 | await state.commit()
82 | return result
83 | } catch (e) {
84 | await state.revert()
85 | throw e
86 | }
87 | }
88 |
89 | async function _runTx(this: VM, opts: RunTxOpts): Promise {
90 | const block = opts.block
91 | const tx = opts.tx
92 | const state = this.pStateManager
93 |
94 | /**
95 | * The `beforeTx` event
96 | *
97 | * @event Event: beforeTx
98 | * @type {Object}
99 | * @property {Transaction} tx emits the Transaction that is about to be processed
100 | */
101 | await this._emit('beforeTx', tx)
102 |
103 | // Validate gas limit against base fee
104 | const basefee = tx.getBaseFee()
105 | const gasLimit = new BN(tx.gasLimit)
106 | if (gasLimit.lt(basefee)) {
107 | throw new Error('base fee exceeds gas limit')
108 | }
109 | gasLimit.isub(basefee)
110 |
111 | // Check from account's balance and nonce
112 | let fromAccount = await state.getAccount(tx.getSenderAddress())
113 | if (!opts.skipBalance && new BN(fromAccount.balance).lt(tx.getUpfrontCost())) {
114 | throw new Error(
115 | `sender doesn't have enough funds to send tx. The upfront cost is: ${tx
116 | .getUpfrontCost()
117 | .toString()}` +
118 | ` and the sender's account only has: ${new BN(fromAccount.balance).toString()}`,
119 | )
120 | } else if (!opts.skipNonce && !new BN(fromAccount.nonce).eq(new BN(tx.nonce))) {
121 | throw new Error(
122 | `the tx doesn't have the correct nonce. account has nonce of: ${new BN(
123 | fromAccount.nonce,
124 | ).toString()} tx has nonce of: ${new BN(tx.nonce).toString()}`,
125 | )
126 | }
127 | // Update from account's nonce and balance
128 | fromAccount.nonce = toBuffer(new BN(fromAccount.nonce).addn(1))
129 | fromAccount.balance = toBuffer(
130 | new BN(fromAccount.balance).sub(new BN(tx.gasLimit).mul(new BN(tx.gasPrice))),
131 | )
132 | await state.putAccount(tx.getSenderAddress(), fromAccount)
133 |
134 | /*
135 | * Execute message
136 | */
137 | const txContext = new TxContext(tx.gasPrice, tx.getSenderAddress())
138 | const message = new Message({
139 | caller: tx.getSenderAddress(),
140 | gasLimit: gasLimit,
141 | to: tx.to.toString('hex') !== '' ? tx.to : undefined,
142 | value: tx.value,
143 | data: tx.data,
144 | })
145 | state._wrapped._clearOriginalStorageCache()
146 | const evm = new EVM(this, txContext, block)
147 | const results = (await evm.executeMessage(message)) as RunTxResult
148 |
149 | /*
150 | * Parse results
151 | */
152 | // Generate the bloom for the tx
153 | results.bloom = txLogsBloom(results.execResult.logs)
154 | // Caculate the total gas used
155 | results.gasUsed = results.gasUsed.add(basefee)
156 | // Process any gas refund
157 | const gasRefund = evm._refund
158 | if (gasRefund) {
159 | if (gasRefund.lt(results.gasUsed.divn(2))) {
160 | results.gasUsed.isub(gasRefund)
161 | } else {
162 | results.gasUsed.isub(results.gasUsed.divn(2))
163 | }
164 | }
165 | results.amountSpent = results.gasUsed.mul(new BN(tx.gasPrice))
166 |
167 | // Update sender's balance
168 | fromAccount = await state.getAccount(tx.getSenderAddress())
169 | const finalFromBalance = new BN(tx.gasLimit)
170 | .sub(results.gasUsed)
171 | .mul(new BN(tx.gasPrice))
172 | .add(new BN(fromAccount.balance))
173 | fromAccount.balance = toBuffer(finalFromBalance)
174 | await state.putAccount(toBuffer(tx.getSenderAddress()), fromAccount)
175 |
176 | // Update miner's balance
177 | const minerAccount = await state.getAccount(block.header.coinbase)
178 | // add the amount spent on gas to the miner's account
179 | minerAccount.balance = toBuffer(new BN(minerAccount.balance).add(results.amountSpent))
180 | if (!new BN(minerAccount.balance).isZero()) {
181 | await state.putAccount(block.header.coinbase, minerAccount)
182 | }
183 |
184 | /*
185 | * Cleanup accounts
186 | */
187 | if (results.execResult.selfdestruct) {
188 | const keys = Object.keys(results.execResult.selfdestruct)
189 | for (const k of keys) {
190 | await state.putAccount(Buffer.from(k, 'hex'), new Account())
191 | }
192 | }
193 | await state.cleanupTouchedAccounts()
194 |
195 | /**
196 | * The `afterTx` event
197 | *
198 | * @event Event: afterTx
199 | * @type {Object}
200 | * @property {Object} result result of the transaction
201 | */
202 | await this._emit('afterTx', results)
203 |
204 | return results
205 | }
206 |
207 | /**
208 | * @method txLogsBloom
209 | * @private
210 | */
211 | function txLogsBloom(logs?: any[]): Bloom {
212 | const bloom = new Bloom()
213 | if (logs) {
214 | for (let i = 0; i < logs.length; i++) {
215 | const log = logs[i]
216 | // add the address
217 | bloom.add(log[0])
218 | // add the topics
219 | const topics = log[1]
220 | for (let q = 0; q < topics.length; q++) {
221 | bloom.add(topics[q])
222 | }
223 | }
224 | }
225 | return bloom
226 | }
227 |
--------------------------------------------------------------------------------
/lib/state/cache.ts:
--------------------------------------------------------------------------------
1 | const asyncLib = require('async')
2 | const Tree = require('functional-red-black-tree')
3 | import Account from 'ethereumjs-account'
4 |
5 | /**
6 | * @ignore
7 | */
8 | export default class Cache {
9 | _cache: any
10 | _checkpoints: any[]
11 | _trie: any
12 |
13 | constructor(trie: any) {
14 | this._cache = Tree()
15 | this._checkpoints = []
16 | this._trie = trie
17 | }
18 |
19 | /**
20 | * Puts account to cache under its address.
21 | * @param key - Address of account
22 | * @param val - Account
23 | */
24 | put(key: Buffer, val: Account, fromTrie: boolean = false): void {
25 | const modified = !fromTrie
26 | this._update(key, val, modified, false)
27 | }
28 |
29 | /**
30 | * Returns the queried account or an empty account.
31 | * @param key - Address of account
32 | */
33 | get(key: Buffer): Account {
34 | let account = this.lookup(key)
35 | if (!account) {
36 | account = new Account()
37 | }
38 | return account
39 | }
40 |
41 | /**
42 | * Returns the queried account or undefined.
43 | * @param key - Address of account
44 | */
45 | lookup(key: Buffer): Account | undefined {
46 | const keyStr = key.toString('hex')
47 |
48 | const it = this._cache.find(keyStr)
49 | if (it.node) {
50 | const account = new Account(it.value.val)
51 | return account
52 | }
53 | }
54 |
55 | /**
56 | * Looks up address in underlying trie.
57 | * @param address - Address of account
58 | * @param cb - Callback with params (err, account)
59 | */
60 | _lookupAccount(address: Buffer, cb: any): void {
61 | this._trie.get(address, (err: Error, raw: Buffer) => {
62 | if (err) return cb(err)
63 | var account = new Account(raw)
64 | cb(null, account)
65 | })
66 | }
67 |
68 | /**
69 | * Looks up address in cache, if not found, looks it up
70 | * in the underlying trie.
71 | * @param key - Address of account
72 | * @param cb - Callback with params (err, account)
73 | */
74 | getOrLoad(key: Buffer, cb: any): void {
75 | const account = this.lookup(key)
76 | if (account) {
77 | asyncLib.nextTick(cb, null, account)
78 | } else {
79 | this._lookupAccount(key, (err: Error, account: Account) => {
80 | if (err) return cb(err)
81 | this._update(key, account, false, false)
82 | cb(null, account)
83 | })
84 | }
85 | }
86 |
87 | /**
88 | * Warms cache by loading their respective account from trie
89 | * and putting them in cache.
90 | * @param addresses - Array of addresses
91 | * @param cb - Callback
92 | */
93 | warm(addresses: string[], cb: any): void {
94 | // shim till async supports iterators
95 | const accountArr: string[] = []
96 | addresses.forEach(val => {
97 | if (val) accountArr.push(val)
98 | })
99 |
100 | asyncLib.eachSeries(
101 | accountArr,
102 | (addressHex: string, done: any) => {
103 | var address = Buffer.from(addressHex, 'hex')
104 | this._lookupAccount(address, (err: Error, account: Account) => {
105 | if (err) return done(err)
106 | this._update(address, account, false, false)
107 | done()
108 | })
109 | },
110 | cb,
111 | )
112 | }
113 |
114 | /**
115 | * Flushes cache by updating accounts that have been modified
116 | * and removing accounts that have been deleted.
117 | * @param cb - Callback
118 | */
119 | flush(cb: any): void {
120 | const it = this._cache.begin
121 | let next = true
122 | asyncLib.whilst(
123 | () => next,
124 | (done: any) => {
125 | if (it.value && it.value.modified) {
126 | it.value.modified = false
127 | it.value.val = it.value.val.serialize()
128 | this._trie.put(Buffer.from(it.key, 'hex'), it.value.val, (err: Error) => {
129 | if (err) return done(err)
130 | next = it.hasNext
131 | it.next()
132 | done()
133 | })
134 | } else if (it.value && it.value.deleted) {
135 | it.value.modified = false
136 | it.value.deleted = false
137 | it.value.val = new Account().serialize()
138 | this._trie.del(Buffer.from(it.key, 'hex'), (err: Error) => {
139 | if (err) return done(err)
140 | next = it.hasNext
141 | it.next()
142 | done()
143 | })
144 | } else {
145 | next = it.hasNext
146 | it.next()
147 | asyncLib.nextTick(done)
148 | }
149 | },
150 | cb,
151 | )
152 | }
153 |
154 | /**
155 | * Marks current state of cache as checkpoint, which can
156 | * later on be reverted or commited.
157 | */
158 | checkpoint(): void {
159 | this._checkpoints.push(this._cache)
160 | }
161 |
162 | /**
163 | * Revert changes to cache last checkpoint (no effect on trie).
164 | */
165 | revert(): void {
166 | this._cache = this._checkpoints.pop()
167 | }
168 |
169 | /**
170 | * Commits to current state of cache (no effect on trie).
171 | */
172 | commit(): void {
173 | this._checkpoints.pop()
174 | }
175 |
176 | /**
177 | * Clears cache.
178 | */
179 | clear(): void {
180 | this._cache = Tree()
181 | }
182 |
183 | /**
184 | * Marks address as deleted in cache.
185 | * @param key - Address
186 | */
187 | del(key: Buffer): void {
188 | this._update(key, new Account(), false, true)
189 | }
190 |
191 | _update(key: Buffer, val: Account, modified: boolean, deleted: boolean): void {
192 | const keyHex = key.toString('hex')
193 | const it = this._cache.find(keyHex)
194 | if (it.node) {
195 | this._cache = it.update({
196 | val: val,
197 | modified: modified,
198 | deleted: deleted,
199 | })
200 | } else {
201 | this._cache = this._cache.insert(keyHex, {
202 | val: val,
203 | modified: modified,
204 | deleted: deleted,
205 | })
206 | }
207 | }
208 | }
209 |
--------------------------------------------------------------------------------
/lib/state/index.ts:
--------------------------------------------------------------------------------
1 | export { default as StateManager } from './stateManager'
2 |
--------------------------------------------------------------------------------
/lib/state/promisified.ts:
--------------------------------------------------------------------------------
1 | const promisify = require('util.promisify')
2 | import Account from 'ethereumjs-account'
3 | import { default as StateManager, StorageDump } from './stateManager'
4 |
5 | /**
6 | * Promisified wrapper around [[StateManager]]
7 | * @ignore
8 | */
9 | export default class PStateManager {
10 | _wrapped: StateManager
11 |
12 | public readonly getAccount: (addr: Buffer) => Promise
13 | public readonly putAccount: (addr: Buffer, account: Account) => Promise
14 | public readonly putContractCode: (addr: Buffer, code: Buffer) => Promise
15 | public readonly getContractCode: (addr: Buffer) => Promise
16 | public readonly getContractStorage: (addr: Buffer, key: Buffer) => Promise
17 | public readonly getOriginalContractStorage: (addr: Buffer, key: Buffer) => Promise
18 | public readonly putContractStorage: (addr: Buffer, key: Buffer, value: Buffer) => Promise
19 | public readonly clearContractStorage: (addr: Buffer) => Promise
20 | public readonly checkpoint: () => Promise
21 | public readonly commit: () => Promise
22 | public readonly revert: () => Promise
23 | public readonly getStateRoot: () => Promise
24 | public readonly setStateRoot: (root: Buffer) => Promise
25 | public readonly dumpStorage: (address: Buffer) => Promise
26 | public readonly hasGenesisState: () => Promise
27 | public readonly generateCanonicalGenesis: () => Promise
28 | public readonly generateGenesis: (initState: any) => Promise
29 | public readonly accountIsEmpty: (address: Buffer) => Promise
30 | public readonly cleanupTouchedAccounts: () => Promise
31 |
32 | constructor(wrapped: StateManager) {
33 | this._wrapped = wrapped
34 |
35 | // We cache these promisified function as they are called lots of times during the VM execution,
36 | // and promisifying them each time has degrades its performance.
37 | this.getAccount = promisify(this._wrapped.getAccount.bind(this._wrapped))
38 |
39 | this.putAccount = promisify(this._wrapped.putAccount.bind(this._wrapped))
40 |
41 | this.putContractCode = promisify(this._wrapped.putContractCode.bind(this._wrapped))
42 |
43 | this.getContractCode = promisify(this._wrapped.getContractCode.bind(this._wrapped))
44 |
45 | this.getContractStorage = promisify(this._wrapped.getContractStorage.bind(this._wrapped))
46 |
47 | this.getOriginalContractStorage = promisify(
48 | this._wrapped.getOriginalContractStorage.bind(this._wrapped),
49 | )
50 |
51 | this.putContractStorage = promisify(this._wrapped.putContractStorage.bind(this._wrapped))
52 |
53 | this.clearContractStorage = promisify(this._wrapped.clearContractStorage.bind(this._wrapped))
54 |
55 | this.checkpoint = promisify(this._wrapped.checkpoint.bind(this._wrapped))
56 |
57 | this.commit = promisify(this._wrapped.commit.bind(this._wrapped))
58 |
59 | this.revert = promisify(this._wrapped.revert.bind(this._wrapped))
60 |
61 | this.getStateRoot = promisify(this._wrapped.getStateRoot.bind(this._wrapped))
62 |
63 | this.setStateRoot = promisify(this._wrapped.setStateRoot.bind(this._wrapped))
64 |
65 | this.dumpStorage = promisify(this._wrapped.dumpStorage.bind(this._wrapped))
66 |
67 | this.hasGenesisState = promisify(this._wrapped.hasGenesisState.bind(this._wrapped))
68 |
69 | this.generateCanonicalGenesis = promisify(
70 | this._wrapped.generateCanonicalGenesis.bind(this._wrapped),
71 | )
72 |
73 | this.generateGenesis = promisify(this._wrapped.generateGenesis.bind(this._wrapped))
74 |
75 | this.accountIsEmpty = promisify(this._wrapped.accountIsEmpty.bind(this._wrapped))
76 |
77 | this.cleanupTouchedAccounts = promisify(
78 | this._wrapped.cleanupTouchedAccounts.bind(this._wrapped),
79 | )
80 | }
81 |
82 | copy(): PStateManager {
83 | return new PStateManager(this._wrapped.copy())
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ethereumjs-vm",
3 | "version": "4.1.3",
4 | "description": "An Ethereum VM implementation",
5 | "main": "dist/index.js",
6 | "types": "dist/index.d.ts",
7 | "files": [
8 | "dist/**/*"
9 | ],
10 | "scripts": {
11 | "build": "ethereumjs-config-build",
12 | "prepublishOnly": "npm run lint && npm run build && npm run test:buildIntegrity",
13 | "coverage": "nyc npm run coverage:test && nyc report --reporter=lcov",
14 | "coverage:test": "npm run build && tape './tests/api/**/*.js' ./tests/tester.js --state --dist",
15 | "docs:build": "typedoc lib",
16 | "test:vm": "node ./tests/tester --vm",
17 | "test:state": "ts-node ./tests/tester --state",
18 | "test:state:allForks": "npm run test:state -- --fork=Byzantium && npm run test:state -- --fork=Constantinople && npm run test:state -- --fork=Petersburg && npm run test:state -- --fork=Istanbul && npm run test:state -- --fork=MuirGlacier",
19 | "test:state:selectedForks": "npm run test:state -- --fork=Petersburg && npm run test:state -- --fork=Istanbul && npm run test:state -- --fork=MuirGlacier",
20 | "test:state:slow": "npm run test:state -- --runSkipped=slow",
21 | "test:buildIntegrity": "npm run test:state -- --test='stackOverflow'",
22 | "test:blockchain": "node -r ts-node/register --stack-size=1500 ./tests/tester --blockchain",
23 | "test:API": "npm run build && ts-node ./node_modules/tape/bin/tape './tests/api/**/*.js'",
24 | "test:API:browser": "npm run build && karma start karma.conf.js",
25 | "test": "echo \"[INFO] Generic test cmd not used. See package.json for more specific test run cmds.\"",
26 | "tslint": "ethereumjs-config-tslint",
27 | "tslint:fix": "ethereumjs-config-tslint-fix",
28 | "lint": "ethereumjs-config-lint",
29 | "lint:fix": "ethereumjs-config-lint-fix",
30 | "format": "ethereumjs-config-format",
31 | "format:fix": "ethereumjs-config-format-fix",
32 | "formatTest": "node ./scripts/formatTest",
33 | "tsc": "ethereumjs-config-tsc"
34 | },
35 | "husky": {
36 | "hooks": {
37 | "pre-push": "npm run lint"
38 | }
39 | },
40 | "repository": {
41 | "type": "git",
42 | "url": "git+https://github.com/ethereumjs/ethereumjs-vm.git"
43 | },
44 | "keywords": [
45 | "ethereum",
46 | "VM"
47 | ],
48 | "dependencies": {
49 | "async": "^2.1.2",
50 | "async-eventemitter": "^0.2.2",
51 | "core-js-pure": "^3.0.1",
52 | "ethereumjs-account": "^3.0.0",
53 | "ethereumjs-block": "^2.2.2",
54 | "ethereumjs-blockchain": "^4.0.3",
55 | "ethereumjs-common": "^1.5.0",
56 | "ethereumjs-tx": "^2.1.2",
57 | "ethereumjs-util": "^6.2.0",
58 | "fake-merkle-patricia-tree": "^1.0.1",
59 | "functional-red-black-tree": "^1.0.1",
60 | "merkle-patricia-tree": "^2.3.2",
61 | "rustbn.js": "~0.2.0",
62 | "safe-buffer": "^5.1.1",
63 | "util.promisify": "^1.0.0"
64 | },
65 | "devDependencies": {
66 | "@ethereumjs/config-nyc": "^1.1.1",
67 | "@ethereumjs/config-prettier": "^1.1.1",
68 | "@ethereumjs/config-tsc": "^1.1.1",
69 | "@ethereumjs/config-tslint": "^1.1.1",
70 | "@types/bn.js": "^4.11.5",
71 | "@types/core-js": "^2.5.0",
72 | "@types/lru-cache": "^5.1.0",
73 | "@types/node": "^11.13.4",
74 | "@types/tape": "^4.2.33",
75 | "browserify": "^16.2.3",
76 | "ethereumjs-testing": "git+https://github.com/ethereumjs/ethereumjs-testing.git#v1.3.0",
77 | "husky": "^2.1.0",
78 | "karma": "^4.0.1",
79 | "karma-browserify": "^6.0.0",
80 | "karma-chrome-launcher": "^2.2.0",
81 | "karma-firefox-launcher": "^1.1.0",
82 | "karma-tap": "^4.1.4",
83 | "level": "^4.0.0",
84 | "level-mem": "^3.0.1",
85 | "minimist": "^1.1.1",
86 | "nyc": "^12.0.2",
87 | "prettier": "^1.16.4",
88 | "rlp": "^2.2.3",
89 | "standard": "^10.0.0",
90 | "tap-spec": "^5.0.0",
91 | "tape": "4.6.3",
92 | "ts-node": "^8.6.2",
93 | "tslint": "^5.16.0",
94 | "typedoc": "^0.14.2",
95 | "typedoc-plugin-markdown": "^1.2.1",
96 | "typescript": "^3.4.3",
97 | "typestrict": "^1.0.2"
98 | },
99 | "author": "mjbecze ",
100 | "contributors": [
101 | "Alex Beregszaszi "
102 | ],
103 | "license": "MPL-2.0",
104 | "bugs": {
105 | "url": "https://github.com/ethereumjs/ethereumjs-vm/issues"
106 | },
107 | "homepage": "https://github.com/ethereumjs/ethereumjs-vm",
108 | "nyc": {
109 | "exclude": [
110 | "tests"
111 | ]
112 | },
113 | "standard": {
114 | "ignore": [
115 | "dist/**",
116 | "examples/runcode-browserify.js"
117 | ]
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require('@ethereumjs/config-prettier')
2 |
--------------------------------------------------------------------------------
/scripts/formatTest.js:
--------------------------------------------------------------------------------
1 | const { spawn } = require('child_process')
2 | const fs = require('fs')
3 | const path = require('path')
4 |
5 | const testScript = process.argv.find((arg, i, array) => array[i - 1] === '-t')
6 | const formatter = process.argv.find((arg, i, array) => array[i - 1] === '-with')
7 |
8 | runTestsWithFormatter(testScript, formatter)
9 |
10 | function runTestsWithFormatter (testScript, formatter = './node_modules/.bin/tap-spec') {
11 | if (!testScript) {
12 | console.log('No test script specified!')
13 | return
14 | }
15 |
16 | const packageJson = fs.readFileSync(path.dirname(__dirname) + '/package.json', 'utf8')
17 | const parsedPackageJson = JSON.parse(packageJson)
18 | const npmTestScriptNames = Object.keys(parsedPackageJson.scripts)
19 |
20 | const commandToRun = npmTestScriptNames.find(name => name === testScript)
21 | ? `npm run ${testScript}`
22 | : `node ${testScript}`
23 |
24 | const child = spawn('sh', ['-c', `${commandToRun} | ${formatter}`])
25 |
26 | child.stdout.on('data', (data) => {
27 | process.stdout.write(data)
28 | })
29 |
30 | child.stderr.on('data', (data) => {
31 | process.stdout.write(data)
32 | })
33 |
34 | child.on('exit', (data) => {
35 | process.stdout.write('Done')
36 | })
37 | }
38 |
--------------------------------------------------------------------------------
/tests/BlockchainTestsRunner.js:
--------------------------------------------------------------------------------
1 | const async = require('async')
2 | const testUtil = require('./util.js')
3 | const ethUtil = require('ethereumjs-util')
4 | const Trie = require('merkle-patricia-tree/secure')
5 | const Block = require('ethereumjs-block')
6 | const Blockchain = require('ethereumjs-blockchain').default
7 | const BlockHeader = require('ethereumjs-block/header.js')
8 | const level = require('level')
9 | const levelMem = require('level-mem')
10 |
11 | var cacheDB = level('./.cachedb')
12 | module.exports = function runBlockchainTest (options, testData, t, cb) {
13 | var blockchainDB = levelMem()
14 | var state = new Trie()
15 | var validate = false
16 | // Only run with block validation when sealEngine present in test file
17 | // and being set to Ethash PoW validation
18 | if (testData.sealEngine && testData.sealEngine === 'Ethash') {
19 | validate = true
20 | }
21 | var blockchain = new Blockchain({
22 | db: blockchainDB,
23 | hardfork: options.forkConfigVM,
24 | validate: validate
25 | })
26 | if (validate) {
27 | blockchain.ethash.cacheDB = cacheDB
28 | }
29 | var VM
30 | if (options.dist) {
31 | VM = require('../dist/index.js').default
32 | } else {
33 | VM = require('../lib/index').default
34 | }
35 | var vm = new VM({
36 | state: state,
37 | blockchain: blockchain,
38 | hardfork: options.forkConfigVM
39 | })
40 | var genesisBlock = new Block({ hardfork: options.forkConfigVM })
41 |
42 | testData.homestead = true
43 | if (testData.homestead) {
44 | vm.on('beforeTx', function (tx) {
45 | tx._homestead = true
46 | })
47 | vm.on('beforeBlock', function (block) {
48 | block.header.isHomestead = function () {
49 | return true
50 | }
51 | })
52 | }
53 | async.series([
54 | // set up pre-state
55 | function (done) {
56 | testUtil.setupPreConditions(state, testData, function () {
57 | done()
58 | })
59 | },
60 | function (done) {
61 | // create and add genesis block
62 | genesisBlock.header = new BlockHeader(formatBlockHeader(testData.genesisBlockHeader), {
63 | hardfork: options.forkConfigVM
64 | })
65 | t.equal(state.root.toString('hex'), genesisBlock.header.stateRoot.toString('hex'), 'correct pre stateRoot')
66 | if (testData.genesisRLP) {
67 | t.equal(genesisBlock.serialize().toString('hex'), testData.genesisRLP.slice(2), 'correct genesis RLP')
68 | }
69 | blockchain.putGenesis(genesisBlock, function (err) {
70 | done(err)
71 | })
72 | },
73 | function (done) {
74 | async.eachSeries(testData.blocks, function (raw, cb) {
75 | try {
76 | var block = new Block(Buffer.from(raw.rlp.slice(2), 'hex'), {
77 | hardfork: options.forkConfigVM
78 | })
79 | // forces the block into thinking they are homestead
80 | if (testData.homestead) {
81 | block.header.isHomestead = function () {
82 | return true
83 | }
84 | block.uncleHeaders.forEach(function (uncle) {
85 | uncle.isHomestead = function () {
86 | return true
87 | }
88 | })
89 | }
90 | blockchain.putBlock(block, function (err) {
91 | cb(err)
92 | })
93 | } catch (err) {
94 | if (err) {
95 | t.fail(err)
96 | }
97 | cb()
98 | }
99 | }, function () {
100 | done()
101 | })
102 | },
103 | function setGenesisStateRoot (done) {
104 | // This is a trick to avoid generating the canonical genesis
105 | // state. Generating the genesis state is not needed because
106 | // blockchain tests come with their own `pre` world state.
107 | // TODO: Add option to `runBlockchain` not to generate genesis state.
108 | vm._common.genesis().stateRoot = state.root
109 | done()
110 | },
111 | function runBlockchain (done) {
112 | vm.runBlockchain()
113 | .then(() => done())
114 | .catch(() => done())
115 | },
116 | function getHead (done) {
117 | vm.blockchain.getHead(function (err, block) {
118 | if (testData.lastblockhash.substr(0, 2) === '0x') {
119 | // fix for BlockchainTests/GeneralStateTests/stRandom/*
120 | testData.lastblockhash = testData.lastblockhash.substr(2)
121 | }
122 | t.equal(block.hash().toString('hex'), testData.lastblockhash, 'last block hash')
123 | // if the test fails, then block.header is the preState because
124 | // vm.runBlock has a check that prevents the actual postState from being
125 | // imported if it is not equal to the expected postState. it is useful
126 | // for debugging to skip this, so that verifyPostConditions will compare
127 | // testData.postState to the actual postState, rather than to the preState.
128 | if (!options.debug) {
129 | // make sure the state is set before checking post conditions
130 | state.root = block.header.stateRoot
131 | }
132 | done(err)
133 | })
134 | },
135 | function (done) {
136 | if (options.debug) {
137 | testUtil.verifyPostConditions(state, testData.postState, t, done)
138 | } else {
139 | done()
140 | }
141 | }
142 | ], function () {
143 | t.equal(blockchain.meta.rawHead.toString('hex'), testData.lastblockhash, 'correct header block')
144 | cb()
145 | })
146 | }
147 |
148 | function formatBlockHeader (data) {
149 | var r = {}
150 | var keys = Object.keys(data)
151 | keys.forEach(function (key) {
152 | r[key] = ethUtil.addHexPrefix(data[key])
153 | })
154 | return r
155 | }
156 |
--------------------------------------------------------------------------------
/tests/GeneralStateTestsRunner.js:
--------------------------------------------------------------------------------
1 | const async = require('async')
2 | const testUtil = require('./util')
3 | const Trie = require('merkle-patricia-tree/secure')
4 | const ethUtil = require('ethereumjs-util')
5 | const Account = require('ethereumjs-account').default
6 | const BN = ethUtil.BN
7 |
8 | function parseTestCases (forkConfigTestSuite, testData, data, gasLimit, value) {
9 | let testCases = []
10 | if (testData['post'][forkConfigTestSuite]) {
11 | testCases = testData['post'][forkConfigTestSuite].map(testCase => {
12 | let testIndexes = testCase['indexes']
13 | let tx = { ...testData.transaction }
14 | if (data !== undefined && testIndexes['data'] !== data) {
15 | return null
16 | }
17 |
18 | if (value !== undefined && testIndexes['value'] !== value) {
19 | return null
20 | }
21 |
22 | if (gasLimit !== undefined && testIndexes['gas'] !== gasLimit) {
23 | return null
24 | }
25 |
26 | tx.data = testData.transaction.data[testIndexes['data']]
27 | tx.gasLimit = testData.transaction.gasLimit[testIndexes['gas']]
28 | tx.value = testData.transaction.value[testIndexes['value']]
29 | return {
30 | 'transaction': tx,
31 | 'postStateRoot': testCase['hash'],
32 | 'env': testData['env'],
33 | 'pre': testData['pre']
34 | }
35 | })
36 | }
37 |
38 | testCases = testCases.filter(testCase => {
39 | return testCase != null
40 | })
41 |
42 | return testCases
43 | }
44 |
45 | function runTestCase (options, testData, t, cb) {
46 | const state = new Trie()
47 | let block, vm
48 |
49 | async.series([
50 | function (done) {
51 | var VM
52 | if (options.dist) {
53 | VM = require('../dist/index.js').default
54 | } else {
55 | VM = require('../lib/index').default
56 | }
57 | vm = new VM({
58 | state: state,
59 | hardfork: options.forkConfigVM
60 | })
61 | testUtil.setupPreConditions(state, testData, done)
62 | },
63 | function (done) {
64 | var tx = testUtil.makeTx(testData.transaction, options.forkConfigVM)
65 | block = testUtil.makeBlockFromEnv(testData.env)
66 | tx._homestead = true
67 | tx.enableHomestead = true
68 | block.isHomestead = function () {
69 | return true
70 | }
71 |
72 | if (!tx.validate()) {
73 | return done()
74 | }
75 |
76 | if (options.jsontrace) {
77 | vm.on('step', function (e) {
78 | let hexStack = []
79 | hexStack = e.stack.map(item => {
80 | return '0x' + new BN(item).toString(16, 0)
81 | })
82 |
83 | var opTrace = {
84 | 'pc': e.pc,
85 | 'op': e.opcode.opcode,
86 | 'gas': '0x' + e.gasLeft.toString('hex'),
87 | 'gasCost': '0x' + e.opcode.fee.toString(16),
88 | 'stack': hexStack,
89 | 'depth': e.depth,
90 | 'opName': e.opcode.name
91 | }
92 |
93 | t.comment(JSON.stringify(opTrace))
94 | })
95 | vm.on('afterTx', function (results) {
96 | let stateRoot = {
97 | 'stateRoot': vm.stateManager._trie.root.toString('hex')
98 | }
99 | t.comment(JSON.stringify(stateRoot))
100 | })
101 | }
102 |
103 | vm.runTx({ tx: tx, block: block })
104 | .then(() => done())
105 | .catch((err) => {
106 | // If tx is invalid and coinbase is empty, the test harness
107 | // expects the coinbase account to be deleted from state.
108 | // Without this ecmul_0-3_5616_28000_96 would fail.
109 | vm.stateManager.getAccount(block.header.coinbase, function (err, account) {
110 | if (err) {
111 | done()
112 | return
113 | }
114 | if (new BN(account.balance).isZero()) {
115 | async.series([
116 | (cb) => vm.stateManager.putAccount(block.header.coinbase, new Account(), cb),
117 | (cb) => vm.stateManager.cleanupTouchedAccounts(cb),
118 | (cb) => vm.stateManager._cache.flush(cb)
119 | ], (err) => {
120 | err = null
121 | done()
122 | })
123 | } else {
124 | done()
125 | }
126 | })
127 | })
128 | },
129 | function (done) {
130 | if (testData.postStateRoot.substr(0, 2) === '0x') {
131 | testData.postStateRoot = testData.postStateRoot.substr(2)
132 | }
133 | t.equal(state.root.toString('hex'), testData.postStateRoot, 'the state roots should match')
134 |
135 | if (state.root.toString('hex') !== testData.postStateRoot.toString('hex')) {
136 | // since General State Tests, postState keys are no longer included in
137 | // the state test format. only postStateRoot, so can't debug expected post conditions
138 | // testUtil.verifyPostConditions(state, testData.post, t, done)
139 | done()
140 | } else {
141 | done()
142 | }
143 | }
144 | ], cb)
145 | }
146 |
147 | module.exports = function runStateTest (options, testData, t, cb) {
148 | try {
149 | const testCases = parseTestCases(options.forkConfigTestSuite, testData, options.data, options.gasLimit, options.value)
150 | if (testCases.length > 0) {
151 | async.eachSeries(testCases,
152 | (testCase, done) => runTestCase(options, testCase, t, done),
153 | cb)
154 | } else {
155 | t.comment(`No ${options.forkConfigTestSuite} post state defined, skip test`)
156 | cb()
157 | }
158 | } catch (e) {
159 | t.fail('error running test case for fork: ' + options.forkConfigTestSuite)
160 | console.log('error:', e)
161 | cb()
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/tests/VMTestsRunner.js:
--------------------------------------------------------------------------------
1 | const async = require('async')
2 | const VM = require('../')
3 | const Account = require('ethereumjs-account').default
4 | const testUtil = require('./util')
5 | const Trie = require('merkle-patricia-tree/secure')
6 | const ethUtil = require('ethereumjs-util')
7 | const BN = ethUtil.BN
8 |
9 | module.exports = function runVMTest (options, testData, t, cb) {
10 | let state = new Trie()
11 | let results
12 | let account
13 |
14 | async.series([
15 | function (done) {
16 | let acctData = testData.pre[testData.exec.address]
17 | account = new Account()
18 | account.nonce = testUtil.format(acctData.nonce)
19 | account.balance = testUtil.format(acctData.balance)
20 | testUtil.setupPreConditions(state, testData, done)
21 | },
22 | function (done) {
23 | state.get(Buffer.from(testData.exec.address, 'hex'), function (err, data) {
24 | let a = new Account(data)
25 | account.stateRoot = a.stateRoot
26 | // console.log(account.toJSON(true))
27 | done(err)
28 | })
29 | },
30 | function (done) {
31 | let block = testUtil.makeBlockFromEnv(testData.env)
32 | let vm = new VM({state: state})
33 | let runCodeData = testUtil.makeRunCodeData(testData.exec, account, block)
34 | if (options.vmtrace) {
35 | vm.on('step', (op) => {
36 | console.log(`(stack before: ${op.stack.length} items)`)
37 | op.stack.forEach((item, i) => {
38 | console.log(`${i}: ${item.toString('hex')}`)
39 | })
40 | const string = `${op.opcode.name} (gas left: ${op.gasLeft.toString()})`
41 | console.log(string)
42 | })
43 | }
44 |
45 | vm.runCode(runCodeData, function (err, r) {
46 | if (r) {
47 | results = r
48 | }
49 | done(err)
50 | })
51 | },
52 | function (done) {
53 | if (options.vmtrace) {
54 | console.log(results.runState.gasLeft.toString())
55 | }
56 |
57 | if (testData.out.slice(2)) {
58 | t.equal(results.returnValue.toString('hex'), testData.out.slice(2), 'valid return value')
59 | }
60 |
61 | if (testData.log && testData.logs.length !== 0) {
62 | testUtil.verifyLogs(results.logs, testData, t)
63 | }
64 |
65 | if (testData.gas) {
66 | let actualGas, expectedGas
67 | if (!results.exceptionError) {
68 | actualGas = results.gas.toString()
69 | expectedGas = new BN(testUtil.format(testData.gas)).toString()
70 | } else {
71 | // OOG
72 | actualGas = results.gasUsed.toString()
73 | expectedGas = new BN(testUtil.format(testData.exec.gas)).toString()
74 | }
75 |
76 | // compress output message for passing test cases
77 | const successMsg = `valid gas usage [file: ${testData.fileName}]`
78 | const failMsg = `valid gas usage [file: ${testData.fileName}, test: ${testData.testName}]`
79 | if (actualGas === expectedGas) {
80 | t.equal(actualGas, expectedGas, successMsg)
81 | } else {
82 | t.equal(actualGas, expectedGas, failMsg)
83 | }
84 | }
85 |
86 | done()
87 | }
88 | ], cb)
89 | }
90 |
--------------------------------------------------------------------------------
/tests/api/bloom.js:
--------------------------------------------------------------------------------
1 | const tape = require('tape')
2 | const Bloom = require('../../dist/bloom').default
3 | const utils = require('ethereumjs-util')
4 |
5 | const byteSize = 256
6 |
7 | tape('bloom', (t) => {
8 | t.test('should initialize without params', (st) => {
9 | const b = new Bloom()
10 | st.deepEqual(b.bitvector, utils.zeros(byteSize), 'should be empty')
11 | st.end()
12 | })
13 |
14 | t.test('shouldnt initialize with invalid bitvector', (st) => {
15 | st.throws(() => new Bloom('invalid'), /AssertionError/, 'should fail for invalid type')
16 | st.throws(() => new Bloom(utils.zeros(byteSize / 2), /AssertionError/), 'should fail for invalid length')
17 | st.end()
18 | })
19 |
20 | t.test('should contain values of hardcoded bitvector', (st) => {
21 | const hex = '00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000'
22 | const vector = Buffer.from(hex, 'hex')
23 |
24 | const b = new Bloom(vector)
25 | st.true(b.check(Buffer.from('value 1', 'utf8')), 'should contain string "value 1"')
26 | st.true(b.check(Buffer.from('value 2', 'utf8')), 'should contain string "value 2"')
27 | st.end()
28 | })
29 |
30 | t.test('check shouldnt be tautology', (st) => {
31 | const b = new Bloom()
32 | st.false(b.check(Buffer.from('random value', 'utf8')), 'should not contain string "random value"')
33 | st.end()
34 | })
35 |
36 | t.test('should correctly add value', (st) => {
37 | const b = new Bloom()
38 | b.add(Buffer.from('value', 'utf8'))
39 | let found = b.check(Buffer.from('value', 'utf8'))
40 | st.true(found, 'should contain added value')
41 | st.end()
42 | })
43 |
44 | t.test('should check multiple values', (st) => {
45 | const b = new Bloom()
46 | b.add(Buffer.from('value 1', 'utf8'))
47 | b.add(Buffer.from('value 2', 'utf8'))
48 | let found = b.multiCheck([Buffer.from('value 1'), Buffer.from('value 2')])
49 | st.true(found, 'should contain both values')
50 | st.end()
51 | })
52 |
53 | t.test('should or two filters', (st) => {
54 | const b1 = new Bloom()
55 | b1.add(Buffer.from('value 1', 'utf8'))
56 | const b2 = new Bloom()
57 | b2.add(Buffer.from('value 2', 'utf8'))
58 |
59 | b1.or(b2)
60 | st.true(b1.check(Buffer.from('value 2', 'utf-8')), 'should contain "value 2" after or')
61 | st.end()
62 | })
63 |
64 | t.test('should generate the correct bloom filter value', (st) => {
65 | let bloom = new Bloom()
66 | bloom.add(Buffer.from('1d7022f5b17d2f8b695918fb48fa1089c9f85401', 'hex'))
67 | bloom.add(Buffer.from('8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925', 'hex'))
68 | bloom.add(Buffer.from('0000000000000000000000005409ed021d9299bf6814279a6a1411a7e866a631', 'hex'))
69 | bloom.add(Buffer.from('0000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48', 'hex'))
70 | st.equal(
71 | bloom.bitvector.toString('hex'),
72 | '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000081100200000000000000000000000000000000000000000000000000000000008000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000002000000000000000004000000000000000000000'
73 | )
74 | st.end()
75 | })
76 | })
77 |
--------------------------------------------------------------------------------
/tests/api/events.js:
--------------------------------------------------------------------------------
1 | const tape = require('tape')
2 | const util = require('ethereumjs-util')
3 | const { Transaction } = require('ethereumjs-tx')
4 | const Block = require('ethereumjs-block')
5 | const VM = require('../../dist/index').default
6 |
7 | tape('VM events', t => {
8 | t.test('should the Block before running it', async st => {
9 | const vm = new VM()
10 |
11 | let emitted
12 | vm.on('beforeBlock', val => {
13 | emitted = val
14 | })
15 |
16 | const block = new Block()
17 |
18 | await vm.runBlock({
19 | block,
20 | generate: true,
21 | skipBlockValidation: true
22 | })
23 |
24 | st.equal(emitted, block)
25 |
26 | st.end()
27 | })
28 |
29 | t.test('should emit a RunBlockResult after running a block', async st => {
30 | const vm = new VM()
31 |
32 | let emitted
33 | vm.on('afterBlock', val => {
34 | emitted = val
35 | })
36 |
37 | const block = new Block()
38 |
39 | await vm.runBlock({
40 | block,
41 | generate: true,
42 | skipBlockValidation: true
43 | })
44 |
45 | st.deepEqual(emitted.receipts, [])
46 | st.deepEqual(emitted.results, [])
47 |
48 | st.end()
49 | })
50 |
51 | t.test('should the Transaction before running it', async st => {
52 | const vm = new VM()
53 |
54 | let emitted
55 | vm.on('beforeTx', val => {
56 | emitted = val
57 | })
58 |
59 | const tx = new Transaction({ gas: 200000, to: '0x1111111111111111111111111111111111111111' })
60 | tx.sign(util.toBuffer('0xa5737ecdc1b89ca0091647e727ba082ed8953f29182e94adc397210dda643b07'))
61 | await vm.runTx({ tx, skipBalance: true })
62 |
63 | st.equal(emitted, tx)
64 |
65 | st.end()
66 | })
67 |
68 | t.test('should emit RunTxResult after running a tx', async st => {
69 | const vm = new VM()
70 |
71 | let emitted
72 | vm.on('afterTx', val => {
73 | emitted = val
74 | })
75 |
76 | const tx = new Transaction({
77 | gas: 200000,
78 | to: '0x1111111111111111111111111111111111111111',
79 | value: 1
80 | })
81 | tx.sign(util.toBuffer('0xa5737ecdc1b89ca0091647e727ba082ed8953f29182e94adc397210dda643b07'))
82 | await vm.runTx({ tx, skipBalance: true })
83 |
84 | st.equal(util.bufferToHex(emitted.execResult.returnValue), '0x')
85 |
86 | st.end()
87 | })
88 |
89 | t.test('should emit the Message before running it', async st => {
90 | const vm = new VM()
91 |
92 | let emitted
93 | vm.on('beforeMessage', val => {
94 | emitted = val
95 | })
96 |
97 | const tx = new Transaction({
98 | gas: 200000,
99 | to: '0x1111111111111111111111111111111111111111',
100 | value: 1
101 | })
102 | tx.sign(util.toBuffer('0xa5737ecdc1b89ca0091647e727ba082ed8953f29182e94adc397210dda643b07'))
103 | await vm.runTx({ tx, skipBalance: true })
104 |
105 | st.equal(util.bufferToHex(emitted.to), '0x1111111111111111111111111111111111111111')
106 | st.equal(util.bufferToHex(emitted.code), '0x')
107 |
108 | st.end()
109 | })
110 |
111 | t.test('should emit EVMResult after running a message', async st => {
112 | const vm = new VM()
113 |
114 | let emitted
115 | vm.on('beforeMessage', val => {
116 | emitted = val
117 | })
118 |
119 | const tx = new Transaction({
120 | gas: 200000,
121 | to: '0x1111111111111111111111111111111111111111',
122 | value: 1
123 | })
124 | tx.sign(util.toBuffer('0xa5737ecdc1b89ca0091647e727ba082ed8953f29182e94adc397210dda643b07'))
125 | await vm.runTx({ tx, skipBalance: true })
126 |
127 | st.equal(util.bufferToHex(emitted.createdAddress), '0x')
128 |
129 | st.end()
130 | })
131 |
132 | t.test('should emit InterpreterStep on each step', async st => {
133 | const vm = new VM()
134 |
135 | let lastEmitted
136 | vm.on('step', val => {
137 | lastEmitted = val
138 | })
139 |
140 | // This a deployment transaction that pushes 0x41 (i.e. ascii A) followed by 31 0s to
141 | // the stack, stores that in memory, and then returns the first byte from memory.
142 | // This deploys a contract which a single byte of code, 0x41.
143 | const tx = new Transaction({
144 | gas: 200000,
145 | data: '0x7f410000000000000000000000000000000000000000000000000000000000000060005260016000f3'
146 | })
147 | tx.sign(util.toBuffer('0xa5737ecdc1b89ca0091647e727ba082ed8953f29182e94adc397210dda643b07'))
148 | await vm.runTx({ tx, skipBalance: true })
149 |
150 | st.equal(lastEmitted.opcode.name, 'RETURN')
151 |
152 | st.end()
153 | })
154 |
155 | t.test('should emit a NewContractEvent on new contracts', async st => {
156 | const vm = new VM()
157 |
158 | let emitted
159 | vm.on('newContract', val => {
160 | emitted = val
161 | })
162 |
163 | // This a deployment transaction that pushes 0x41 (i.e. ascii A) followed by 31 0s to
164 | // the stack, stores that in memory, and then returns the first byte from memory.
165 | // This deploys a contract which a single byte of code, 0x41.
166 | const tx = new Transaction({
167 | gas: 200000,
168 | data: '0x7f410000000000000000000000000000000000000000000000000000000000000060005260016000f3'
169 | })
170 | tx.sign(util.toBuffer('0xa5737ecdc1b89ca0091647e727ba082ed8953f29182e94adc397210dda643b07'))
171 | await vm.runTx({ tx, skipBalance: true })
172 |
173 | st.equal(
174 | util.bufferToHex(emitted.code),
175 | '0x7f410000000000000000000000000000000000000000000000000000000000000060005260016000f3'
176 | )
177 |
178 | st.end()
179 | })
180 | })
181 |
--------------------------------------------------------------------------------
/tests/api/evm/memory.js:
--------------------------------------------------------------------------------
1 | const tape = require('tape')
2 | const Memory = require('../../../dist/evm/memory').default
3 |
4 | tape('Memory', t => {
5 | const m = new Memory()
6 | t.test('should have 0 capacity initially', st => {
7 | st.equal(m._store.length, 0)
8 | st.throws(() => m.write(0, 3, Buffer.from([1, 2, 3])), /capacity/)
9 | st.end()
10 | })
11 |
12 | t.test('should return zeros from empty memory', st => {
13 | st.deepEqual(m.read(0, 3), Buffer.from([0, 0, 0]))
14 | st.end()
15 | })
16 |
17 | t.test('should extend capacity to word boundary', st => {
18 | m.extend(0, 3)
19 | st.equal(m._store.length, 32)
20 | st.end()
21 | })
22 |
23 | t.test('should return zeros before writing', st => {
24 | st.deepEqual(m.read(0, 2), Buffer.from([0, 0]))
25 | st.end()
26 | })
27 |
28 | t.test('should not write value beyond capacity', st => {
29 | st.throws(() => m.write(30, 3, Buffer.from([1, 2, 3])), /capacity/)
30 | st.end()
31 | })
32 |
33 | t.test('should write value', st => {
34 | m.write(29, 3, Buffer.from([1, 2, 3]))
35 | st.deepEqual(m.read(29, 5), Buffer.from([1, 2, 3, 0, 0]))
36 | st.end()
37 | })
38 |
39 | t.test('should fail when value len and size are inconsistent', st => {
40 | st.throws(() => m.write(0, 5, Buffer.from([8, 8, 8])), /size/)
41 | st.end()
42 | })
43 | })
44 |
--------------------------------------------------------------------------------
/tests/api/evm/precompiles/06-ecadd.js:
--------------------------------------------------------------------------------
1 | const BN = require('bn.js')
2 | const tape = require('tape')
3 | const Common = require('ethereumjs-common').default
4 | const util = require('ethereumjs-util')
5 | const VM = require('../../../../dist/index').default
6 | const { getPrecompile } = require('../../../../dist/evm/precompiles')
7 |
8 | tape('Precompiles: ECADD', (t) => {
9 | t.test('ECADD', (st) => {
10 | const common = new Common('mainnet', 'petersburg')
11 | let vm = new VM({ common: common })
12 | let ECADD = getPrecompile('0000000000000000000000000000000000000006')
13 |
14 | let result = ECADD({
15 | data: Buffer.alloc(0),
16 | gasLimit: new BN(0xffff),
17 | _common: common
18 | })
19 | st.deepEqual(result.gasUsed.toNumber(), 500, 'should use petersburg gas costs')
20 | st.end()
21 | })
22 | })
--------------------------------------------------------------------------------
/tests/api/evm/precompiles/07-ecmul.js:
--------------------------------------------------------------------------------
1 | const BN = require('bn.js')
2 | const tape = require('tape')
3 | const Common = require('ethereumjs-common').default
4 | const util = require('ethereumjs-util')
5 | const VM = require('../../../../dist/index').default
6 | const { getPrecompile } = require('../../../../dist/evm/precompiles')
7 |
8 | tape('Precompiles: ECMUL', (t) => {
9 | t.test('ECMUL', (st) => {
10 | const common = new Common('mainnet', 'petersburg')
11 | let vm = new VM({ common: common })
12 | let ECMUL = getPrecompile('0000000000000000000000000000000000000007')
13 |
14 | let result = ECMUL({
15 | data: Buffer.alloc(0),
16 | gasLimit: new BN(0xffff),
17 | _common: common
18 | })
19 | st.deepEqual(result.gasUsed.toNumber(), 40000, 'should use petersburg gas costs')
20 | st.end()
21 | })
22 | })
--------------------------------------------------------------------------------
/tests/api/evm/precompiles/08-ecpairing.js:
--------------------------------------------------------------------------------
1 | const BN = require('bn.js')
2 | const tape = require('tape')
3 | const Common = require('ethereumjs-common').default
4 | const util = require('ethereumjs-util')
5 | const VM = require('../../../../dist/index').default
6 | const { getPrecompile } = require('../../../../dist/evm/precompiles')
7 |
8 | tape('Precompiles: ECPAIRING', (t) => {
9 | t.test('ECPAIRING', (st) => {
10 | const common = new Common('mainnet', 'petersburg')
11 | let vm = new VM({ common: common })
12 | let ECPAIRING = getPrecompile('0000000000000000000000000000000000000008')
13 |
14 | let result = ECPAIRING({
15 | data: Buffer.from('00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa', 'hex'),
16 | gasLimit: new BN(0xffffff),
17 | _common: common
18 | })
19 | st.deepEqual(result.gasUsed.toNumber(), 260000, 'should use petersburg gas costs (k ^= 2 pairings)')
20 | st.end()
21 | })
22 | })
--------------------------------------------------------------------------------
/tests/api/evm/stack.js:
--------------------------------------------------------------------------------
1 | const tape = require('tape')
2 | const BN = require('bn.js')
3 | const Stack = require('../../../dist/evm/stack').default
4 |
5 | tape('Stack', t => {
6 | t.test('should be empty initially', st => {
7 | const s = new Stack()
8 | st.equal(s._store.length, 0)
9 | st.throws(() => s.pop())
10 | st.end()
11 | })
12 |
13 | t.test('popN should throw for empty stack', st => {
14 | const s = new Stack()
15 | st.deepEqual(s.popN(0), [])
16 | st.throws(() => s.popN(1))
17 | st.end()
18 | })
19 |
20 | t.test('should not push invalid type values', st => {
21 | const s = new Stack()
22 | st.throws(() => s.push('str'))
23 | st.throws(() => s.push(5))
24 | st.end()
25 | })
26 |
27 | t.test('should push item', st => {
28 | const s = new Stack()
29 | s.push(new BN(5))
30 | st.equal(s.pop().toNumber(), 5)
31 | st.end()
32 | })
33 |
34 | t.test('popN should return array for n = 1', st => {
35 | const s = new Stack()
36 | s.push(new BN(5))
37 | st.deepEqual(s.popN(1), [new BN(5)])
38 | st.end()
39 | })
40 |
41 | t.test('popN should fail on underflow', st => {
42 | const s = new Stack()
43 | s.push(new BN(5))
44 | st.throws(() => s.popN(2))
45 | st.end()
46 | })
47 |
48 | t.test('popN should return in correct order', st => {
49 | const s = new Stack()
50 | s.push(new BN(5))
51 | s.push(new BN(7))
52 | st.deepEqual(s.popN(2), [new BN(7), new BN(5)])
53 | st.end()
54 | })
55 |
56 | t.test('should throw on overflow', st => {
57 | const s = new Stack()
58 | for (let i = 0; i < 1024; i++) {
59 | s.push(new BN(i))
60 | }
61 | st.throws(() => s.push(new BN(1024)))
62 | st.end()
63 | })
64 |
65 | t.test('should swap top with itself', st => {
66 | const s = new Stack()
67 | s.push(new BN(5))
68 | s.swap(0)
69 | st.deepEqual(s.pop(), new BN(5))
70 | st.end()
71 | })
72 |
73 | t.test('swap should throw on underflow', st => {
74 | const s = new Stack()
75 | s.push(new BN(5))
76 | st.throws(() => s.swap(1))
77 | st.end()
78 | })
79 |
80 | t.test('should swap', st => {
81 | const s = new Stack()
82 | s.push(new BN(5))
83 | s.push(new BN(7))
84 | s.swap(1)
85 | st.deepEqual(s.pop(), new BN(5))
86 | st.end()
87 | })
88 |
89 | t.test('dup should throw on underflow', st => {
90 | const s = new Stack()
91 | st.throws(() => st.dup(0))
92 | s.push(new BN(5))
93 | st.throws(() => st.dup(1))
94 | st.end()
95 | })
96 |
97 | t.test('should dup', st => {
98 | const s = new Stack()
99 | s.push(new BN(5))
100 | s.push(new BN(7))
101 | s.dup(2)
102 | st.deepEqual(s.pop(), new BN(5))
103 | st.end()
104 | })
105 |
106 | t.test('should validate value overflow', st => {
107 | const s = new Stack()
108 | const max = new BN(2).pow(new BN(256)).subn(1)
109 | s.push(max)
110 | st.deepEqual(s.pop(), max)
111 | st.throws(() => s.push(max.addn(1)))
112 | st.end()
113 | })
114 | })
115 |
--------------------------------------------------------------------------------
/tests/api/index.js:
--------------------------------------------------------------------------------
1 | const promisify = require('util.promisify')
2 | const tape = require('tape')
3 | const util = require('ethereumjs-util')
4 | const Block = require('ethereumjs-block')
5 | const Common = require('ethereumjs-common').default
6 | const Trie = require('merkle-patricia-tree/secure')
7 | const VM = require('../../dist/index').default
8 | const { setupVM } = require('./utils')
9 | const { setupPreConditions } = require('../util')
10 | const testData = require('./testdata.json')
11 |
12 | tape('VM with default blockchain', (t) => {
13 | t.test('should instantiate without params', (st) => {
14 | const vm = new VM()
15 | st.ok(vm.stateManager)
16 | st.deepEqual(vm.stateManager._trie.root, util.KECCAK256_RLP, 'it has default trie')
17 | st.end()
18 | })
19 |
20 | t.test('should be able to activate precompiles', (st) => {
21 | let vm = new VM({ activatePrecompiles: true })
22 | st.notEqual(vm.stateManager._trie.root, util.KECCAK256_RLP, 'it has different root')
23 | st.end()
24 | })
25 |
26 | t.test('should work with trie (state) provided', (st) => {
27 | let trie = new Trie()
28 | trie.isTestTrie = true
29 | let vm = new VM({ state: trie, activatePrecompiles: true })
30 | st.notEqual(vm.stateManager._trie.root, util.KECCAK256_RLP, 'it has different root')
31 | st.ok(vm.stateManager._trie.isTestTrie, 'it works on trie provided')
32 | st.end()
33 | })
34 |
35 | t.test('should only accept common or chain and fork', (st) => {
36 | const common = new Common('mainnet')
37 |
38 | st.throws(() => new VM({ chain: 'a', common }))
39 | st.throws(() => new VM({ hardfork: 'a', common }))
40 | st.throws(() => new VM({ chain: 'a', hardfork: 'a', common }))
41 |
42 | st.end()
43 | })
44 |
45 | t.test('should accept a common object as option', (st) => {
46 | const common = new Common('mainnet', 'istanbul')
47 |
48 | const vm = new VM({ common })
49 | st.equal(vm._common, common)
50 |
51 | st.end()
52 | })
53 |
54 | t.test('should only accept valid chain and fork', (st) => {
55 | let vm = new VM({ chain: 'ropsten', hardfork: 'byzantium' })
56 | st.equal(vm.stateManager._common.param('gasPrices', 'ecAdd'), 500)
57 |
58 | try {
59 | vm = new VM({ chain: 'mainchain', hardfork: 'homestead' })
60 | st.fail('should have failed for invalid chain')
61 | } catch (e) {
62 | st.ok(e.message.includes('not supported'))
63 | }
64 |
65 | st.end()
66 | })
67 |
68 | t.test('should run blockchain without blocks', async (st) => {
69 | const vm = new VM()
70 | await vm.runBlockchain()
71 | st.end()
72 | })
73 | })
74 |
75 | tape('VM with blockchain', (t) => {
76 | t.test('should instantiate', (st) => {
77 | const vm = setupVM()
78 | st.deepEqual(vm.stateManager._trie.root, util.KECCAK256_RLP, 'it has default trie')
79 | st.end()
80 | })
81 |
82 | t.test('should run blockchain without blocks', async (st) => {
83 | const vm = setupVM()
84 | await vm.runBlockchain()
85 | st.end()
86 | })
87 |
88 | t.test('should run blockchain with mocked runBlock', async (st) => {
89 | const vm = setupVM({ chain: 'goerli' })
90 | const genesis = new Block(Buffer.from(testData.genesisRLP.slice(2), 'hex'), { common: vm._common })
91 | const block = new Block(Buffer.from(testData.blocks[0].rlp.slice(2), 'hex'), { common: vm._common })
92 |
93 | await putGenesisP(vm.blockchain, genesis)
94 | st.equal(vm.blockchain.meta.genesis.toString('hex'), testData.genesisBlockHeader.hash.slice(2))
95 |
96 | await putBlockP(vm.blockchain, block)
97 | const head = await getHeadP(vm.blockchain)
98 | st.equal(
99 | head.hash().toString('hex'),
100 | testData.blocks[0].blockHeader.hash.slice(2)
101 | )
102 |
103 | const setupPreP = promisify(setupPreConditions)
104 | await setupPreP(vm.stateManager._trie, testData)
105 |
106 | vm.runBlock = (block) => new Promise((resolve, reject) => reject(new Error('test')))
107 | vm.runBlockchain()
108 | .then(() => st.fail('it hasn\'t returned any errors'))
109 | .catch((e) => {
110 | st.equal(e.message, 'test', 'it has correctly propagated runBlock\'s error')
111 | st.end()
112 | })
113 | })
114 |
115 | t.test('should run blockchain with blocks', async (st) => {
116 | const vm = setupVM({ chain: 'goerli' })
117 | const genesis = new Block(Buffer.from(testData.genesisRLP.slice(2), 'hex'), { common: vm._common })
118 | const block = new Block(Buffer.from(testData.blocks[0].rlp.slice(2), 'hex'), { common: vm._common })
119 |
120 | await putGenesisP(vm.blockchain, genesis)
121 | st.equal(vm.blockchain.meta.genesis.toString('hex'), testData.genesisBlockHeader.hash.slice(2))
122 |
123 | await putBlockP(vm.blockchain, block)
124 | const head = await getHeadP(vm.blockchain)
125 | st.equal(
126 | head.hash().toString('hex'),
127 | testData.blocks[0].blockHeader.hash.slice(2)
128 | )
129 |
130 | const setupPreP = promisify(setupPreConditions)
131 | await setupPreP(vm.stateManager._trie, testData)
132 |
133 | await vm.runBlockchain()
134 |
135 | st.end()
136 | })
137 |
138 | t.test('should pass the correct Common object when copying the VM', st => {
139 | const vm = setupVM({ chain: 'goerli', hardfork: 'byzantium' })
140 | st.equal(vm._common.chainName(), 'goerli')
141 | st.equal(vm._common.hardfork(), 'byzantium')
142 |
143 | const copiedVM = vm.copy()
144 | st.equal(copiedVM._common.chainName(), 'goerli')
145 | st.equal(copiedVM._common.hardfork(), 'byzantium')
146 |
147 | st.end()
148 | })
149 | })
150 |
151 | const putGenesisP = (blockchain, genesis) => promisify(blockchain.putGenesis.bind(blockchain))(genesis)
152 | const putBlockP = (blockchain, block) => promisify(blockchain.putBlock.bind(blockchain))(block)
153 | const getHeadP = (blockchain) => promisify(blockchain.getHead.bind(blockchain))()
154 |
--------------------------------------------------------------------------------
/tests/api/istanbul/eip-1108.js:
--------------------------------------------------------------------------------
1 | const BN = require('bn.js')
2 | const tape = require('tape')
3 | const Common = require('ethereumjs-common').default
4 | const util = require('ethereumjs-util')
5 | const VM = require('../../../dist/index').default
6 | const { getPrecompile } = require('../../../dist/evm/precompiles')
7 |
8 | tape('Istanbul: EIP-1108 tests', (t) => {
9 | t.test('ECADD', (st) => {
10 | const common = new Common('mainnet', 'istanbul')
11 | let vm = new VM({ common: common })
12 | let ECADD = getPrecompile('0000000000000000000000000000000000000006')
13 |
14 | let result = ECADD({
15 | data: Buffer.alloc(0),
16 | gasLimit: new BN(0xffff),
17 | _common: common
18 | })
19 | st.deepEqual(result.gasUsed.toNumber(), 150, 'should use istanbul gas costs')
20 | st.end()
21 | })
22 |
23 | t.test('ECMUL', (st) => {
24 | const common = new Common('mainnet', 'istanbul')
25 | let vm = new VM({ common: common })
26 | let ECMUL = getPrecompile('0000000000000000000000000000000000000007')
27 |
28 | let result = ECMUL({
29 | data: Buffer.alloc(0),
30 | gasLimit: new BN(0xffff),
31 | _common: common
32 | })
33 | st.deepEqual(result.gasUsed.toNumber(), 6000, 'should use istanbul gas costs')
34 | st.end()
35 | })
36 |
37 | t.test('ECPAIRING', (st) => {
38 | const common = new Common('mainnet', 'istanbul')
39 | let vm = new VM({ common: common })
40 | let ECPAIRING = getPrecompile('0000000000000000000000000000000000000008')
41 |
42 | let result = ECPAIRING({
43 | data: Buffer.from('00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa', 'hex'),
44 | gasLimit: new BN(0xffffff),
45 | _common: common
46 | })
47 | st.deepEqual(result.gasUsed.toNumber(), 113000, 'should use petersburg gas costs (k ^= 2 pairings)')
48 | st.end()
49 | })
50 | })
51 |
--------------------------------------------------------------------------------
/tests/api/istanbul/eip-1344.js:
--------------------------------------------------------------------------------
1 | const tape = require('tape')
2 | const BN = require('bn.js')
3 | const Common = require('ethereumjs-common').default
4 | const VM = require('../../../dist/index').default
5 | const { ERROR } = require('../../../dist/exceptions')
6 |
7 | const testCases = [
8 | { chain: 'mainnet', hardfork: 'istanbul', chainId: new BN(1) },
9 | { chain: 'mainnet', hardfork: 'constantinople', err: ERROR.INVALID_OPCODE },
10 | { chain: 'ropsten', hardfork: 'istanbul', chainId: new BN(3) }
11 | ]
12 |
13 | // CHAINID PUSH8 0x00 MSTORE8 PUSH8 0x01 PUSH8 0x00 RETURN
14 | const code = ['46', '60', '00', '53', '60', '01', '60', '00', 'f3']
15 | tape('Istanbul: EIP-1344 CHAINID', async (t) => {
16 | const runCodeArgs = {
17 | code: Buffer.from(code.join(''), 'hex'),
18 | gasLimit: new BN(0xffff)
19 | }
20 |
21 | for (const testCase of testCases) {
22 | const common = new Common(testCase.chain, testCase.hardfork)
23 | const vm = new VM({ common })
24 | try {
25 | const res = await vm.runCode(runCodeArgs)
26 | if (testCase.err) {
27 | t.equal(res.exceptionError.error, testCase.err)
28 | } else {
29 | t.assert(res.exceptionError === undefined)
30 | t.assert(testCase.chainId.eq(new BN(res.returnValue)))
31 | }
32 | } catch (e) {
33 | t.fail(e.message)
34 | }
35 | }
36 |
37 | t.end()
38 | })
39 |
--------------------------------------------------------------------------------
/tests/api/istanbul/eip-152.js:
--------------------------------------------------------------------------------
1 | const tape = require('tape')
2 | const BN = require('bn.js')
3 | const Common = require('ethereumjs-common').default
4 | const blake2f = require('../../../dist/evm/precompiles/09-blake2f').default
5 | const F = require('../../../dist/evm/precompiles/09-blake2f').F
6 | const { ERROR } = require('../../../dist/exceptions')
7 |
8 | // Test cases from:
9 | // https://github.com/keep-network/go-ethereum/blob/1bccafe5ef54ba849e414ce7c90f7b7130634a9a/core/vm/contracts_test.go
10 | const failingtestCases = [
11 | {
12 | input: '',
13 | err: ERROR.OUT_OF_RANGE,
14 | name: 'vector 0: empty input'
15 | },
16 | {
17 | input: '00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001',
18 | err: ERROR.OUT_OF_RANGE,
19 | name: 'vector 1: less than 213 bytes input'
20 | },
21 | {
22 | input: '000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001',
23 | err: ERROR.OUT_OF_RANGE,
24 | name: 'vector 2: more than 213 bytes input'
25 | },
26 | {
27 | input: '0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002',
28 | err: ERROR.OUT_OF_RANGE,
29 | name: 'vector 3: malformed final block indicator flag'
30 | }
31 | ]
32 |
33 | const testCases = [
34 | {
35 | input: '0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001',
36 | expected: '08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b',
37 | name: 'vector 4'
38 | },
39 | {
40 | input: '0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001',
41 | expected: 'ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923',
42 | name: 'vector 5'
43 | },
44 | {
45 | input: '0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000',
46 | expected: '75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735',
47 | name: 'vector 6'
48 | },
49 | {
50 | input: '0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001',
51 | expected: 'b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421',
52 | name: 'vector 7'
53 | },
54 | {
55 | input: '007A120048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001',
56 | expected: '6d2ce9e534d50e18ff866ae92d70cceba79bbcd14c63819fe48752c8aca87a4bb7dcc230d22a4047f0486cfcfb50a17b24b2899eb8fca370f22240adb5170189',
57 | name: 'vector 8'
58 | }
59 | ]
60 |
61 | tape('Istanbul: EIP-152 Blake2f', async (t) => {
62 | const common = new Common('mainnet', 'istanbul')
63 | for (const testCase of failingtestCases) {
64 | t.comment(testCase.name)
65 | const res = blake2f({ data: Buffer.from(testCase.input, 'hex'), gasLimit: new BN(20), _common: common })
66 | t.equal(res.exceptionError.error, testCase.err)
67 | }
68 |
69 | for (const testCase of testCases) {
70 | t.comment(testCase.name)
71 | const res = blake2f({ data: Buffer.from(testCase.input, 'hex'), gasLimit: new BN(10000000), _common: common })
72 | t.equal(res.returnValue.toString('hex'), testCase.expected)
73 | }
74 |
75 | t.end()
76 | })
77 |
78 | // Test case from:
79 | // https://github.com/keep-network/go-ethereum/blob/1bccafe5ef54ba849e414ce7c90f7b7130634a9a/crypto/blake2b/blake2b_f_test.go
80 | const fTestCases = [{
81 | hIn: new Uint32Array([
82 | 0xf2bdc948, 0x6a09e667, 0x84caa73b, 0xbb67ae85,
83 | 0xfe94f82b, 0x3c6ef372, 0x5f1d36f1, 0xa54ff53a,
84 | 0xade682d1, 0x510e527f, 0x2b3e6c1f, 0x9b05688c,
85 | 0xfb41bd6b, 0x1f83d9ab, 0x137e2179, 0x5be0cd19
86 | ]),
87 | m: new Uint32Array([
88 | 0x00636261, 0, 0, 0, 0, 0, 0, 0,
89 | 0, 0, 0, 0, 0, 0, 0, 0,
90 | 0, 0, 0, 0, 0, 0, 0, 0,
91 | 0, 0, 0, 0, 0, 0, 0, 0
92 | ]),
93 | t: new Uint32Array([3, 0, 0, 0]),
94 | f: true,
95 | rounds: 12,
96 | hOut: new Uint32Array([
97 | 0x3FA580BA, 0x0D4D1C98, 0xB697276A, 0xE9F6129F,
98 | 0x142F214C, 0xB7C45A68, 0x6FBB124B, 0xD1A2FFDB,
99 | 0x39C5877D, 0x2D79AB2A, 0xDED552C2, 0x95CC3345,
100 | 0xA88AD318, 0x5A92F1DB, 0xED8623B9, 0x239900D4
101 | ])
102 | }]
103 |
104 | tape('Blake2 F', async (t) => {
105 | for (const testCase of fTestCases) {
106 | F(testCase.hIn, testCase.m, testCase.t, testCase.f, testCase.rounds)
107 | t.deepEqual(testCase.hIn, testCase.hOut)
108 | }
109 |
110 | t.end()
111 | })
112 |
--------------------------------------------------------------------------------
/tests/api/istanbul/eip-1884.js:
--------------------------------------------------------------------------------
1 | const tape = require('tape')
2 | const BN = require('bn.js')
3 | const Common = require('ethereumjs-common').default
4 | const VM = require('../../../dist/index').default
5 | const PStateManager = require('../../../dist/state/promisified').default
6 | const { ERROR } = require('../../../dist/exceptions')
7 | const { createAccount } = require('../utils')
8 |
9 | const testCases = [
10 | { chain: 'mainnet', hardfork: 'istanbul', selfbalance: '0xf1' },
11 | { chain: 'mainnet', hardfork: 'constantinople', err: ERROR.INVALID_OPCODE }
12 | ]
13 |
14 | // SELFBALANCE PUSH8 0x00 MSTORE8 PUSH8 0x01 PUSH8 0x00 RETURN
15 | const code = ['47', '60', '00', '53', '60', '01', '60', '00', 'f3']
16 | tape('Istanbul: EIP-1884: SELFBALANCE', async (t) => {
17 | const addr = Buffer.from('00000000000000000000000000000000000000ff', 'hex')
18 | const runCodeArgs = {
19 | code: Buffer.from(code.join(''), 'hex'),
20 | gasLimit: new BN(0xffff),
21 | address: addr
22 | }
23 |
24 | for (const testCase of testCases) {
25 | const common = new Common(testCase.chain, testCase.hardfork)
26 | const vm = new VM({ common })
27 | const state = new PStateManager(vm.stateManager)
28 | const account = createAccount('0x00', testCase.selfbalance)
29 | await state.putAccount(addr, account)
30 | try {
31 | const res = await vm.runCode(runCodeArgs)
32 | if (testCase.err) {
33 | t.equal(res.exceptionError.error, testCase.err)
34 | } else {
35 | t.assert(res.exceptionError === undefined)
36 | t.assert(new BN(Buffer.from(testCase.selfbalance.slice(2), 'hex')).eq(new BN(res.returnValue)))
37 | }
38 | } catch (e) {
39 | t.fail(e.message)
40 | }
41 | }
42 |
43 | t.end()
44 | })
45 |
--------------------------------------------------------------------------------
/tests/api/istanbul/eip-2200.js:
--------------------------------------------------------------------------------
1 | const tape = require('tape')
2 | const BN = require('bn.js')
3 | const Common = require('ethereumjs-common').default
4 | const VM = require('../../../dist/index').default
5 | const PStateManager = require('../../../dist/state/promisified').default
6 | const { ERROR } = require('../../../dist/exceptions')
7 | const { createAccount } = require('../utils')
8 |
9 | const testCases = [
10 | { original: new BN(0), code: '60006000556000600055', used: 1612, refund: 0 }, // 0 -> 0 -> 0
11 | { original: new BN(0), code: '60006000556001600055', used: 20812, refund: 0 }, // 0 -> 0 -> 1
12 | { original: new BN(0), code: '60016000556000600055', used: 20812, refund: 19200 }, // 0 -> 1 -> 0
13 | { original: new BN(0), code: '60016000556002600055', used: 20812, refund: 0 }, // 0 -> 1 -> 2
14 | { original: new BN(0), code: '60016000556001600055', used: 20812, refund: 0 }, // 0 -> 1 -> 1
15 | { original: new BN(1), code: '60006000556000600055', used: 5812, refund: 15000 }, // 1 -> 0 -> 0
16 | { original: new BN(1), code: '60006000556001600055', used: 5812, refund: 4200 }, // 1 -> 0 -> 1
17 | { original: new BN(1), code: '60006000556002600055', used: 5812, refund: 0 }, // 1 -> 0 -> 2
18 | { original: new BN(1), code: '60026000556000600055', used: 5812, refund: 15000 }, // 1 -> 2 -> 0
19 | { original: new BN(1), code: '60026000556003600055', used: 5812, refund: 0 }, // 1 -> 2 -> 3
20 | { original: new BN(1), code: '60026000556001600055', used: 5812, refund: 4200 }, // 1 -> 2 -> 1
21 | { original: new BN(1), code: '60026000556002600055', used: 5812, refund: 0 }, // 1 -> 2 -> 2
22 | { original: new BN(1), code: '60016000556000600055', used: 5812, refund: 15000 }, // 1 -> 1 -> 0
23 | { original: new BN(1), code: '60016000556002600055', used: 5812, refund: 0 }, // 1 -> 1 -> 2
24 | { original: new BN(1), code: '60016000556001600055', used: 1612, refund: 0 }, // 1 -> 1 -> 1
25 | { original: new BN(0), code: '600160005560006000556001600055', used: 40818, refund: 19200 }, // 0 -> 1 -> 0 -> 1
26 | { original: new BN(1), code: '600060005560016000556000600055', used: 10818, refund: 19200 }, // 1 -> 0 -> 1 -> 0
27 | { original: new BN(1), gas: new BN(2306), code: '6001600055', used: 2306, refund: 0, err: ERROR.OUT_OF_GAS }, // 1 -> 1 (2300 sentry + 2xPUSH)
28 | { original: new BN(1), gas: new BN(2307), code: '6001600055', used: 806, refund: 0 } // 1 -> 1 (2301 sentry + 2xPUSH)
29 | ]
30 |
31 | tape('Istanbul: EIP-2200: net-metering SSTORE', async (t) => {
32 | const caller = Buffer.from('0000000000000000000000000000000000000000', 'hex')
33 | const addr = Buffer.from('00000000000000000000000000000000000000ff', 'hex')
34 | const key = new BN(0).toArrayLike(Buffer, 'be', 32)
35 | for (const testCase of testCases) {
36 | const common = new Common('mainnet', 'istanbul')
37 | const vm = new VM({ common })
38 | const state = new PStateManager(vm.stateManager)
39 |
40 | const account = createAccount('0x00', '0x00')
41 | await state.putAccount(addr, account)
42 | await state.putContractCode(addr, Buffer.from(testCase.code, 'hex'))
43 | if (!testCase.original.isZero()) {
44 | await state.putContractStorage(addr, key, testCase.original)
45 | }
46 |
47 | const runCallArgs = {
48 | caller,
49 | gasLimit: testCase.gas ? testCase.gas : new BN(0xffffffffff),
50 | to: addr
51 | }
52 |
53 | try {
54 | const res = await vm.runCall(runCallArgs)
55 | if (testCase.err) {
56 | t.equal(res.execResult.exceptionError.error, testCase.err)
57 | } else {
58 | t.assert(res.execResult.exceptionError === undefined)
59 | }
60 | t.assert(new BN(testCase.used).eq(res.gasUsed))
61 | t.assert(new BN(testCase.refund).eq(res.execResult.gasRefund))
62 | } catch (e) {
63 | t.fail(e.message)
64 | }
65 | }
66 |
67 | t.end()
68 | })
69 |
--------------------------------------------------------------------------------
/tests/api/istanbul/index.js:
--------------------------------------------------------------------------------
1 | const tape = require('tape')
2 | const util = require('ethereumjs-util')
3 | const VM = require('../../../dist/index').default
4 |
5 | tape('General Istanbul VM tests', (t) => {
6 | t.test('should accept istanbul harfork option', (st) => {
7 | const vm = new VM({ hardfork: 'istanbul' })
8 | st.ok(vm.stateManager)
9 | st.deepEqual(vm.stateManager._trie.root, util.KECCAK256_RLP, 'it has default trie')
10 | st.end()
11 | })
12 | })
--------------------------------------------------------------------------------
/tests/api/muirGlacier/index.js:
--------------------------------------------------------------------------------
1 | const tape = require('tape')
2 | const util = require('ethereumjs-util')
3 | const VM = require('../../../dist/index').default
4 |
5 | tape('General MuirGlacier VM tests', (t) => {
6 | t.test('should accept muirGlacier harfork option for supported chains', (st) => {
7 | let vm = new VM({ hardfork: 'muirGlacier' })
8 | st.ok(vm.stateManager)
9 | st.deepEqual(vm.stateManager._trie.root, util.KECCAK256_RLP, 'it has default trie')
10 | st.end()
11 | })
12 | })
--------------------------------------------------------------------------------
/tests/api/opcodes.js:
--------------------------------------------------------------------------------
1 | const tape = require('tape')
2 | const { getOpcodesForHF } = require('../../dist/evm/opcodes')
3 | const Common = require('ethereumjs-common').default
4 |
5 | const CHAINID = 0x46
6 |
7 | tape('getOpcodesForHF', (t) => {
8 | t.test('shouldnt apply istanbul opcode changes for petersburg', (st) => {
9 | const c = new Common('mainnet', 'petersburg')
10 | const opcodes = getOpcodesForHF(c)
11 | st.assert(opcodes[CHAINID] === undefined)
12 | st.end()
13 | })
14 |
15 | t.test('should correctly apply istanbul opcode when hf >= istanbul', (st) => {
16 | let c = new Common('mainnet', 'istanbul')
17 | let opcodes = getOpcodesForHF(c)
18 | st.equal(opcodes[CHAINID].name, 'CHAINID')
19 |
20 | c = new Common('mainnet', 'muirGlacier')
21 | opcodes = getOpcodesForHF(c)
22 | st.equal(opcodes[CHAINID].name, 'CHAINID')
23 |
24 | st.end()
25 | })
26 | })
27 |
--------------------------------------------------------------------------------
/tests/api/runBlock.js:
--------------------------------------------------------------------------------
1 | const promisify = require('util.promisify')
2 | const tape = require('tape')
3 | const Block = require('ethereumjs-block')
4 | const Common = require('ethereumjs-common').default
5 | const util = require('ethereumjs-util')
6 | const runBlock = require('../../dist/runBlock').default
7 | const PStateManager = require('../../dist/state/promisified').default
8 | const { StateManager } = require('../../dist/state')
9 | const testData = require('./testdata.json')
10 | const { setupVM } = require('./utils')
11 | const { setupPreConditions } = require('../util')
12 |
13 | function setup (vm = null) {
14 | // Create a mock, if no real VM object provided.
15 | // The mock includes mocked runTx and runCall which
16 | // always return an error.
17 | if (vm === null) {
18 | const stateManager = new StateManager()
19 | vm = {
20 | stateManager,
21 | pStateManager: new PStateManager(stateManager),
22 | emit: (e, val, cb) => cb(),
23 | _emit: (e, val) => new Promise((resolve, reject) => resolve()),
24 | runTx: (opts) => new Promise((resolve, reject) => reject(new Error('test'))),
25 | _common: new Common('mainnet', 'byzantium')
26 | }
27 | }
28 |
29 | return {
30 | vm,
31 | data: testData,
32 | p: {
33 | runBlock: runBlock.bind(vm),
34 | putAccount: promisify(vm.stateManager.putAccount.bind(vm.stateManager))
35 | }
36 | }
37 | }
38 |
39 | tape('runBlock', async (t) => {
40 | const suite = setup()
41 |
42 | t.test('should fail without params', async (st) => {
43 | await suite.p.runBlock()
44 | .then(() => st.fail('should have returned error'))
45 | .catch((e) => st.ok(e.message.includes('invalid input'), 'correct error'))
46 |
47 | st.end()
48 | })
49 |
50 | t.test('should fail without opts', async (st) => {
51 | await suite.p.runBlock({})
52 | .then(() => st.fail('should have returned error'))
53 | .catch((e) => st.ok(e.message.includes('invalid input'), 'correct error'))
54 |
55 | st.end()
56 | })
57 |
58 | t.test('should fail when runTx fails', async (st) => {
59 | const block = new Block(util.rlp.decode(suite.data.blocks[0].rlp))
60 |
61 | // The mocked VM uses a mocked runTx
62 | // which always returns an error.
63 | await suite.p.runBlock({ block, skipBlockValidation: true })
64 | .then(() => t.fail('should have returned error'))
65 | .catch((e) => t.equal(e.message, 'test'))
66 |
67 | st.end()
68 | })
69 | })
70 |
71 | tape('should fail when block gas limit higher than 2^63-1', async (t) => {
72 | const suite = setup()
73 |
74 | const block = new Block({
75 | header: {
76 | ...suite.data.blocks[0].header,
77 | gasLimit: Buffer.from('8000000000000000', 16)
78 | }
79 | })
80 | await suite.p.runBlock({ block })
81 | .then(() => t.fail('should have returned error'))
82 | .catch((e) => t.ok(e.message.includes('Invalid block')))
83 |
84 | t.end()
85 | })
86 |
87 | tape('should fail when block validation fails', async (t) => {
88 | const suite = setup()
89 |
90 | const block = new Block(util.rlp.decode(suite.data.blocks[0].rlp))
91 | block.validate = (_, cb) => cb(new Error('test'))
92 |
93 | await suite.p.runBlock({ block })
94 | .then(() => t.fail('should have returned error'))
95 | .catch((e) => t.ok(e.message.includes('test')))
96 |
97 | t.end()
98 | })
99 |
100 | tape('should fail when tx gas limit higher than block gas limit', async (t) => {
101 | const suite = setup()
102 |
103 | const block = new Block(util.rlp.decode(suite.data.blocks[0].rlp))
104 | block.transactions[0].gasLimit = Buffer.from('3fefba', 'hex')
105 |
106 | await suite.p.runBlock({ block, skipBlockValidation: true })
107 | .then(() => t.fail('should have returned error'))
108 | .catch((e) => t.ok(e.message.includes('higher gas limit')))
109 |
110 | t.end()
111 | })
112 |
113 | tape('should run valid block', async (t) => {
114 | const vm = setupVM()
115 | const suite = setup(vm)
116 |
117 | const genesis = new Block(util.rlp.decode(suite.data.genesisRLP))
118 | const block = new Block(util.rlp.decode(suite.data.blocks[0].rlp))
119 |
120 | const setupPreP = promisify(setupPreConditions)
121 | await setupPreP(suite.vm.stateManager._trie, suite.data)
122 |
123 | t.equal(
124 | suite.vm.stateManager._trie.root.toString('hex'),
125 | genesis.header.stateRoot.toString('hex'),
126 | 'genesis state root should match calculated state root'
127 | )
128 |
129 | let res = await suite.p.runBlock({ block, root: suite.vm.stateManager._trie.root, skipBlockValidation: true })
130 |
131 | t.error(res.error, 'runBlock shouldn\'t have returned error')
132 | t.equal(res.results[0].gasUsed.toString('hex'), '5208', 'actual gas used should equal blockHeader gasUsed')
133 |
134 | t.end()
135 | })
136 |
--------------------------------------------------------------------------------
/tests/api/runBlockchain.js:
--------------------------------------------------------------------------------
1 | const tape = require('tape')
2 | const level = require('level-mem')
3 | const promisify = require('util.promisify')
4 | const Blockchain = require('ethereumjs-blockchain').default
5 | const Block = require('ethereumjs-block')
6 | const Common = require('ethereumjs-common').default
7 | const util = require('ethereumjs-util')
8 | const runBlockchain = require('../../dist/runBlockchain').default
9 | const PStateManager = require('../../dist/state/promisified').default
10 | const { StateManager } = require('../../dist/state')
11 | const { createGenesis } = require('./utils')
12 |
13 | tape('runBlockchain', (t) => {
14 | const blockchainDB = level()
15 | const blockchain = new Blockchain({
16 | db: blockchainDB,
17 | chain: 'goerli',
18 | validate: false
19 | })
20 | const stateManager = new StateManager({ common: new Common('goerli') });
21 | const vm = {
22 | stateManager,
23 | pStateManager: new PStateManager(stateManager),
24 | blockchain: blockchain
25 | }
26 |
27 | const putGenesisP = promisify(blockchain.putGenesis.bind(blockchain))
28 | const putBlockP = promisify(blockchain.putBlock.bind(blockchain))
29 | const getHeadP = promisify(blockchain.getHead.bind(blockchain))
30 |
31 | t.test('should run without a blockchain parameter', async (st) => {
32 | await runBlockchain.bind(vm)()
33 | st.end()
34 | })
35 |
36 | t.test('should run without blocks', async (st) => {
37 | await runBlockchain.bind(vm)(blockchain)
38 | st.end()
39 | })
40 |
41 | t.test('should run with genesis block', async (st) => {
42 | const genesis = createGenesis({ chain: 'goerli' })
43 |
44 | await putGenesisP(genesis)
45 | st.ok(blockchain.meta.genesis, 'genesis should be set for blockchain')
46 |
47 | await runBlockchain.bind(vm)(blockchain)
48 | st.end()
49 | })
50 |
51 | t.test('should run with valid and invalid blocks', async (st) => {
52 | // Produce error on the third time runBlock is called
53 | let runBlockInvocations = 0
54 | vm.runBlock = (opts) => new Promise((resolve, reject) => {
55 | runBlockInvocations++
56 | if (runBlockInvocations === 3) {
57 | return reject(new Error('test'))
58 | }
59 | resolve({})
60 | })
61 |
62 | const genesis = createGenesis({ chain: 'goerli' })
63 | await putGenesisP(genesis)
64 |
65 | const b1 = createBlock(genesis, 1, { chain: 'goerli' })
66 | const b2 = createBlock(b1, 2, { chain: 'goerli' })
67 | const b3 = createBlock(b2, 3, { chain: 'goerli' })
68 |
69 | blockchain.validate = false
70 |
71 | await putBlockP(b1)
72 | await putBlockP(b2)
73 | await putBlockP(b3)
74 |
75 | let head = await getHeadP()
76 | st.deepEqual(head.hash(), b3.hash(), 'block3 should be the current head')
77 |
78 | try {
79 | await runBlockchain.bind(vm)(blockchain)
80 | st.fail('should have returned error')
81 | } catch (e) {
82 | st.equal(e.message, 'test')
83 |
84 | head = await getHeadP()
85 | st.deepEqual(head.hash(), b2.hash(), 'should have removed invalid block from head')
86 |
87 | st.end()
88 | }
89 | })
90 | })
91 |
92 | function createBlock (parent = null, n = 0, opts = {}) {
93 | opts.chain = opts.chain ? opts.chain : 'mainnet'
94 | if (parent === null) {
95 | return createGenesis(opts)
96 | }
97 |
98 | const b = new Block(null, opts)
99 | b.header.number = util.toBuffer(n)
100 | b.header.parentHash = parent.hash()
101 | b.header.difficulty = '0xfffffff'
102 | b.header.stateRoot = parent.header.stateRoot
103 |
104 | return b
105 | }
106 |
--------------------------------------------------------------------------------
/tests/api/runCode.js:
--------------------------------------------------------------------------------
1 | const tape = require('tape')
2 | const async = require('async')
3 | const BN = require('bn.js')
4 | const VM = require('../../dist/index').default
5 |
6 | const STOP = '00'
7 | const JUMP = '56'
8 | const JUMPDEST = '5b'
9 | const PUSH1 = '60'
10 |
11 | const testCases = [
12 | { code: [STOP, JUMPDEST, PUSH1, '05', JUMP, JUMPDEST], pc: 1, resultPC: 6 },
13 | { code: [STOP, JUMPDEST, PUSH1, '05', JUMP, JUMPDEST], pc: -1, error: 'Internal error: program counter not in range' },
14 | { code: [STOP], pc: 3, error: 'Internal error: program counter not in range' },
15 | { code: [STOP], resultPC: 1 }
16 | ]
17 |
18 | tape('VM.runcode: initial program counter', t => {
19 | const vm = new VM()
20 |
21 | testCases.forEach((testData, i) => {
22 | t.test('should start the execution at the specified pc or 0 #' + i, async st => {
23 | const runCodeArgs = {
24 | code: Buffer.from(testData.code.join(''), 'hex'),
25 | pc: testData.pc,
26 | gasLimit: new BN(0xffff)
27 | }
28 |
29 | let err
30 | try {
31 | const result = await vm.runCode(runCodeArgs)
32 | if (testData.resultPC !== undefined) {
33 | t.equals(result.runState.programCounter, testData.resultPC, 'runstate.programCounter')
34 | }
35 | } catch (e) {
36 | err = e
37 | }
38 |
39 | if (testData.error) {
40 | err = err ? err.message : 'no error thrown'
41 | st.equals(err, testData.error, 'error message should match')
42 | err = false
43 | }
44 |
45 | st.assert(!err)
46 | st.end()
47 | })
48 | })
49 | })
50 |
--------------------------------------------------------------------------------
/tests/api/runTx.js:
--------------------------------------------------------------------------------
1 | const promisify = require('util.promisify')
2 | const tape = require('tape')
3 | const Transaction = require('ethereumjs-tx').Transaction
4 | const ethUtil = require('ethereumjs-util')
5 | const runTx = require('../../dist/runTx').default
6 | const PStateManager = require('../../dist/state/promisified').default
7 | const { StateManager } = require('../../dist/state')
8 | const VM = require('../../dist/index').default
9 | const { createAccount } = require('./utils')
10 |
11 | function setup (vm = null) {
12 | if (vm === null) {
13 | const stateManager = new StateManager({ })
14 | vm = {
15 | stateManager,
16 | pStateManager: new PStateManager(stateManager),
17 | emit: (e, val, cb) => { cb() },
18 | _emit: (e, val) => new Promise((resolve, reject) => resolve())
19 | }
20 | }
21 |
22 | return {
23 | vm,
24 | runTx: runTx.bind(vm),
25 | putAccount: promisify(vm.stateManager.putAccount.bind(vm.stateManager))
26 | }
27 | }
28 |
29 | tape('runTx', (t) => {
30 | const suite = setup()
31 |
32 | t.test('should fail to run without opts', async (st) => {
33 | shouldFail(st, suite.runTx(),
34 | (e) => st.ok(e.message.includes('invalid input'), 'should fail with appropriate error')
35 | )
36 | st.end()
37 | })
38 |
39 | t.test('should fail to run without tx', async (st) => {
40 | shouldFail(st, suite.runTx({}),
41 | (e) => st.ok(e.message.includes('invalid input'), 'should fail with appropriate error')
42 | )
43 | st.end()
44 | })
45 |
46 | t.test('should fail to run without signature', async (st) => {
47 | const tx = getTransaction(false, true)
48 | shouldFail(st, suite.runTx({ tx }),
49 | (e) => st.ok(e.message.toLowerCase().includes('signature'), 'should fail with appropriate error')
50 | )
51 | st.end()
52 | })
53 |
54 | t.test('should fail without sufficient funds', async (st) => {
55 | const tx = getTransaction(true, true)
56 | shouldFail(st, suite.runTx({ tx }),
57 | (e) => st.ok(e.message.toLowerCase().includes('enough funds'), 'error should include "enough funds"')
58 | )
59 | st.end()
60 | })
61 | })
62 |
63 | tape('should run simple tx without errors', async (t) => {
64 | let vm = new VM()
65 | const suite = setup(vm)
66 |
67 | const tx = getTransaction(true, true)
68 | const acc = createAccount()
69 | await suite.putAccount(tx.from.toString('hex'), acc)
70 |
71 | let res = await suite.runTx({ tx, populateCache: true })
72 | t.true(res.gasUsed.gt(0), 'should have used some gas')
73 |
74 | t.end()
75 | })
76 |
77 | tape('should fail when account balance overflows', async t => {
78 | const vm = new VM()
79 | const suite = setup(vm)
80 |
81 | const tx = getTransaction(true, true, '0x01')
82 | const from = createAccount()
83 | const to = createAccount('0x00', ethUtil.MAX_INTEGER)
84 | await suite.putAccount(tx.from.toString('hex'), from)
85 | await suite.putAccount(tx.to, to)
86 |
87 | shouldFail(t,
88 | suite.runTx({ tx }),
89 | (e) => t.equal(e.message, 'Value overflow')
90 | )
91 |
92 | t.end()
93 | })
94 |
95 | // The following test tries to verify that running a tx
96 | // would work, even when stateManager is not using a cache.
97 | // It fails at the moment, and has been therefore commented.
98 | // Please refer to https://github.com/ethereumjs/ethereumjs-vm/issues/353
99 | /* tape('should behave the same when not using cache', async (t) => {
100 | const suite = setup()
101 |
102 | const tx = getTransaction(true, true)
103 | const acc = createAccount()
104 | await suite.putAccount(tx.from.toString('hex'), acc)
105 | await suite.cacheFlush()
106 | suite.vm.stateManager.cache.clear()
107 |
108 | shouldFail(t,
109 | suite.runTx({ tx, populateCache: false }),
110 | (e) => t.equal(e.message, 'test', 'error should be equal to what the mock runCall returns')
111 | )
112 |
113 | t.end()
114 | }) */
115 |
116 | function shouldFail (st, p, onErr) {
117 | p.then(() => st.fail('runTx didnt return any errors')).catch(onErr)
118 | }
119 |
120 | function getTransaction (sign = false, calculageGas = false, value = '0x00') {
121 | const privateKey = Buffer.from('e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', 'hex')
122 | const txParams = {
123 | nonce: '0x00',
124 | gasPrice: 100,
125 | gasLimit: 1000,
126 | to: '0x0000000000000000000000000000000000000000',
127 | value: value,
128 | data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057',
129 | chainId: 3
130 | }
131 |
132 | const tx = new Transaction(txParams)
133 | if (sign) {
134 | tx.sign(privateKey)
135 | }
136 |
137 | if (calculageGas) {
138 | tx.gas = tx.getUpfrontCost()
139 | }
140 |
141 | return tx
142 | }
143 |
--------------------------------------------------------------------------------
/tests/api/state/cache.js:
--------------------------------------------------------------------------------
1 | const promisify = require('util.promisify')
2 | const tape = require('tape')
3 | const Trie = require('merkle-patricia-tree/secure.js')
4 | const Account = require('ethereumjs-account').default
5 | const Cache = require('../../../dist/state/cache').default
6 | const utils = require('../utils')
7 |
8 | tape('cache initialization', (t) => {
9 | t.test('should initialize', async (st) => {
10 | const trie = new Trie()
11 | const c = new Cache(trie)
12 | st.ok(trie.root.equals(c._trie.root), 'initializes given trie')
13 | st.end()
14 | })
15 | })
16 |
17 | tape('cache put and get account', (t) => {
18 | const trie = new Trie()
19 | const c = new Cache(trie)
20 | const flushP = promisify(c.flush.bind(c))
21 | const trieGetP = promisify(trie.get.bind(trie))
22 |
23 | const addr = Buffer.from('cd2a3d9f938e13cd947ec05abc7fe734df8dd826', 'hex')
24 | const acc = utils.createAccount('0x00', '0xff11')
25 |
26 | t.test('should fail to get non-existent account', async (st) => {
27 | const res = c.get(addr)
28 | st.notOk(res.balance.equals(acc.balance))
29 | st.end()
30 | })
31 |
32 | t.test('should put account', async (st) => {
33 | c.put(addr, acc)
34 | const res = c.get(addr)
35 | st.ok(res.balance.equals(acc.balance))
36 | st.end()
37 | })
38 |
39 | t.test('should not have flushed to trie', async (st) => {
40 | const res = await trieGetP(addr)
41 | st.notOk(res)
42 | st.end()
43 | })
44 |
45 | t.test('should flush to trie', async (st) => {
46 | await flushP()
47 | st.end()
48 | })
49 |
50 | t.test('trie should contain flushed account', async (st) => {
51 | const raw = await trieGetP(addr)
52 | const res = new Account(raw)
53 | st.ok(res.balance.equals(acc.balance))
54 | st.end()
55 | })
56 |
57 | t.test('should delete account from cache', async (st) => {
58 | c.del(addr)
59 |
60 | const res = c.get(addr)
61 | st.notOk(res.balance.equals(acc.balance))
62 | st.end()
63 | })
64 |
65 | t.test('should warm cache and load account from trie', async (st) => {
66 | await promisify(c.warm.bind(c))([addr])
67 |
68 | const res = c.get(addr)
69 | st.ok(res.balance.equals(acc.balance))
70 | st.end()
71 | })
72 |
73 | t.test('should update loaded account and flush it', async (st) => {
74 | const updatedAcc = utils.createAccount('0x00', '0xff00')
75 | c.put(addr, updatedAcc)
76 | await flushP()
77 |
78 | const raw = await trieGetP(addr)
79 | const res = new Account(raw)
80 | st.ok(res.balance.equals(updatedAcc.balance))
81 | st.end()
82 | })
83 | })
84 |
85 | tape('cache checkpointing', (t) => {
86 | const trie = new Trie()
87 | const c = new Cache(trie)
88 |
89 | const addr = Buffer.from('cd2a3d9f938e13cd947ec05abc7fe734df8dd826', 'hex')
90 | const acc = utils.createAccount('0x00', '0xff11')
91 | const updatedAcc = utils.createAccount('0x00', '0xff00')
92 |
93 | t.test('should revert to correct state', async (st) => {
94 | c.put(addr, acc)
95 | c.checkpoint()
96 | c.put(addr, updatedAcc)
97 |
98 | let res = c.get(addr)
99 | st.ok(res.balance.equals(updatedAcc.balance))
100 |
101 | c.revert()
102 |
103 | res = c.get(addr)
104 | st.ok(res.balance.equals(acc.balance))
105 |
106 | st.end()
107 | })
108 | })
109 |
--------------------------------------------------------------------------------
/tests/api/utils.js:
--------------------------------------------------------------------------------
1 | const Block = require('ethereumjs-block')
2 | const Account = require('ethereumjs-account').default
3 | const level = require('level-mem')
4 | const Blockchain = require('ethereumjs-blockchain').default
5 | const VM = require('../../dist/index').default
6 |
7 | function createGenesis (opts = {}) {
8 | opts.chain = opts.chain ? opts.chain : 'mainnet'
9 | const genesis = new Block(null, opts)
10 | genesis.setGenesisParams()
11 |
12 | return genesis
13 | }
14 |
15 | function createAccount (nonce, balance) {
16 | const raw = {
17 | nonce: nonce || '0x00',
18 | balance: balance || '0xfff384'
19 | }
20 | const acc = new Account(raw)
21 | return acc
22 | }
23 |
24 | function setupVM (opts = {}) {
25 | const db = level()
26 | opts.blockchain = opts.blockchain ? opts.blockchain : new Blockchain({ db, validate: false })
27 | const vm = new VM(opts)
28 | vm.blockchain._common = vm._common
29 | vm.blockchain.dbManager._common = vm._common
30 |
31 | return vm
32 | }
33 |
34 | module.exports = {
35 | createGenesis,
36 | createAccount,
37 | setupVM
38 | }
39 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@ethereumjs/config-tsc",
3 | "include": ["lib/**/*.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/tsconfig.prod.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@ethereumjs/config-tsc",
3 | "compilerOptions": {
4 | "outDir": "./dist"
5 | },
6 | "include": ["lib/**/*.ts"]
7 | }
8 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@ethereumjs/config-tslint"
3 | }
4 |
--------------------------------------------------------------------------------
/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "out": "docs",
3 | "mode": "file",
4 | "readme": "none",
5 | "theme": "markdown",
6 | "mdEngine": "github",
7 | "excludeNotExported": true,
8 | "exclude": ["lib/bloom/*.ts", "lib/evm/precompiles/*.ts", "lib/evm/eei.ts", "lib/evm/interpreter.ts", "lib/evm/memory.ts", "lib/evm/message.ts", "lib/evm/opcodes.ts", "lib/evm/opFns.ts", "lib/evm/stack.ts", "lib/evm/txContext.ts"]
9 | }
10 |
--------------------------------------------------------------------------------
/utils/diffTestOutput.py:
--------------------------------------------------------------------------------
1 | import sys, re
2 |
3 | '''
4 | given the name (or path) of a file, returns a 'summary' object containing which tests pass/fail
5 | '''
6 | def getTestSummary(f):
7 | summary = {
8 | 'success': set(),
9 | 'fail': set()
10 | }
11 | curTestName = ''
12 | fp = open(f)
13 |
14 | for i, line in enumerate(fp):
15 | if line.startswith("# file"):
16 | if curTestName != '':
17 | if not curTestName in summary['fail']:
18 | summary['success'].add(curTestName)
19 | curTestName = getTestName(line)
20 | elif line.startswith("ok"):
21 | continue
22 | elif line.startswith("1.."):
23 | break
24 | elif line.startswith("not ok"):
25 | summary['fail'].add(curTestName)
26 | elif line.startswith(" "):
27 | if not curTestName in summary['fail']:
28 | summary['fail'].add(curTestName)
29 |
30 | return summary
31 |
32 | def getDiff(summary1, summary2):
33 | all_failed = summary1['fail'] | summary2['fail'] # set union
34 | all_successful = summary1['success'] | summary2['success']
35 |
36 | print("\n\nDiff of failed tests:\n")
37 | for failed_test in all_failed:
38 | if not failed_test in summary2['fail']:
39 | print("< "+failed_test)
40 | elif not failed_test in summary1['fail']:
41 | print("> "+failed_test)
42 |
43 | print("\n\nDiff of successful tests:\n")
44 | for successful_test in all_successful:
45 | if not successful_test in summary2['success']:
46 | print("< "+successful_test)
47 | elif not successful_test in summary1['success']:
48 | print("> "+successful_test)
49 |
50 |
51 | def getTestName(line):
52 | r = re.compile("^.*test: (.*)$")
53 | x = r.search(line)
54 |
55 | if not x.group(1):
56 | raise Exception(line)
57 | else:
58 | s = x.group(1).replace('_EIP158', '').replace('_Byzantium', '')
59 | return s
60 |
61 | if __name__ == "__main__":
62 | if len(sys.argv) < 3:
63 | print("need two files to diff..")
64 | sys.exit(-1)
65 |
66 | file1Name = sys.argv[1]
67 | file2Name = sys.argv[2]
68 |
69 | summary1 = getTestSummary(file1Name)
70 | summary2 = getTestSummary(file2Name)
71 |
72 | getDiff(summary1, summary2)
73 |
--------------------------------------------------------------------------------