├── .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 | --------------------------------------------------------------------------------