Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor tx lib #812

Merged
merged 33 commits into from
Sep 21, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f8671fe
Refactor tx lib
ryanio Jul 13, 2020
e425377
introduce Common.forBlockNumber(chain, blockNumber)
ryanio Jul 23, 2020
ce8fbaf
add example for Fake Transaction to readme
ryanio Jul 23, 2020
97caeb9
remove need for bufferToHex
ryanio Jul 23, 2020
d6cc6bf
only accept 6 or 9 values for fromValuesArray
ryanio Jul 23, 2020
20fd30a
remove unnecessary validation of data being a Buffer
ryanio Jul 23, 2020
34bd639
move param outside of loop
ryanio Jul 23, 2020
420d20b
update tx.validate stringError to return string[]
ryanio Jul 23, 2020
3261f7f
fix for undefined hardfork
ryanio Jul 23, 2020
6aa475c
lint
ryanio Jul 23, 2020
d364eb9
Merge branch 'master' into tx-refactor
ryanio Jul 23, 2020
43bbb11
Merge branch 'master' into tx-refactor
ryanio Sep 8, 2020
616865c
add changelog entry
ryanio Sep 8, 2020
dd6dfa0
update package-lock
ryanio Sep 8, 2020
3b591cf
add common changelog entry
ryanio Sep 8, 2020
049e750
add toBuffer to require
ryanio Sep 8, 2020
b415f46
Merge branch 'master' into tx-refactor
ryanio Sep 15, 2020
2860cbf
update runTx test to new api
ryanio Sep 15, 2020
c82032c
update common changelog
ryanio Sep 15, 2020
0dceea8
use new Address type from ethereumjs-util 7.0.5
ryanio Sep 15, 2020
525d385
cleaner default syntax
ryanio Sep 15, 2020
e9bfc93
update tx test case name
ryanio Sep 15, 2020
d88e2b3
use buf instead of toBuffer for new address class
ryanio Sep 15, 2020
b9c2a1d
lint, update package-lock
ryanio Sep 15, 2020
e765669
update common examples to use dict in constructor
ryanio Sep 15, 2020
0cc1f0d
test fixes
ryanio Sep 15, 2020
bdcc5b8
lint
ryanio Sep 15, 2020
e9cf49c
fixups
ryanio Sep 15, 2020
bc3cc3f
Merge branch 'master' into tx-refactor
ryanio Sep 17, 2020
349c8eb
common is already setHardforkByBlockNumber in header constructor
ryanio Sep 17, 2020
73e4a10
Merge branch 'master' into tx-refactor
ryanio Sep 21, 2020
d5fed0a
fixups
ryanio Sep 21, 2020
4491218
Merge branch 'master' into tx-refactor
ryanio Sep 21, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 2 additions & 7 deletions packages/account/test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,8 @@ tape('serialize', function (tester) {
codeHash: '0xc5d2461236f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470',
}
const account = new Account(raw)
t.equals(
Buffer.compare(
account.serialize(),
rlp.encode([raw.nonce, raw.balance, raw.stateRoot, raw.codeHash]),
),
0,
)
const accountRlp = rlp.encode([raw.nonce, raw.balance, raw.stateRoot, raw.codeHash])
t.ok(account.serialize().equals(accountRlp))
t.end()
})
})
Expand Down
39 changes: 29 additions & 10 deletions packages/block/src/block.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BaseTrie as Trie } from 'merkle-patricia-tree'
import Common from '@ethereumjs/common'
import { BN, rlp, keccak256, KECCAK256_RLP, baToJSON } from 'ethereumjs-util'
import { Transaction, TransactionOptions } from '@ethereumjs/tx'
import { Transaction } from '@ethereumjs/tx'
import { BlockHeader } from './header'
import { Blockchain, BlockData, ChainOptions } from './types'

Expand Down Expand Up @@ -41,7 +41,7 @@ export class Block {
this._common = chainOptions.common
} else {
const chain = chainOptions.chain ? chainOptions.chain : 'mainnet'
// TODO: Compute the hardfork based on this block's number. It can be implemented right now
// TODO: Compute the hardfork based on this block's number. It can't be implemented right now
// because the block number is not immutable, so the Common can get out of sync.
const hardfork = chainOptions.hardfork ? chainOptions.hardfork : null
this._common = new Common(chain, hardfork)
Expand Down Expand Up @@ -73,10 +73,29 @@ export class Block {
}

// parse transactions

// get common based on block's number
// since hardfork param may not be set
// (see TODO above)
let common = this._common
alcuadrado marked this conversation as resolved.
Show resolved Hide resolved
if (!common.hardfork()) {
const blockNumber = parseInt(this.header.number.toString('hex'), 16)
const chainId = this._common.chainId()
if (blockNumber) {
const hfs = this._common.activeHardforks(blockNumber)
const hf = hfs[hfs.length - 1].name
common = new Common(chainId, hf)
} else {
// fall back to default hf
common = new Common(chainId, 'petersburg')
ryanio marked this conversation as resolved.
Show resolved Hide resolved
}
}

ryanio marked this conversation as resolved.
Show resolved Hide resolved
for (let i = 0; i < rawTransactions.length; i++) {
// TODO: Pass the common object instead of the options. It can't be implemented right now
// because the hardfork may be `null`. Read the above TODO for more info.
const tx = new Transaction(rawTransactions[i], chainOptions as TransactionOptions)
const txData = rawTransactions[i]
const tx = Array.isArray(txData)
? Transaction.fromValuesArray(txData as Buffer[], common)
ryanio marked this conversation as resolved.
Show resolved Hide resolved
: Transaction.fromRlpSerializedTx(txData as Buffer, common)
this.transactions.push(tx)
}
}
Expand Down Expand Up @@ -119,7 +138,7 @@ export class Block {
serialize(rlpEncode = true) {
const raw = [
this.header.raw,
this.transactions.map((tx) => tx.raw),
this.transactions.map((tx) => tx.serialize()),
this.uncleHeaders.map((uh) => uh.raw),
]

Expand All @@ -141,11 +160,11 @@ export class Block {
* Validates the transaction trie
*/
validateTransactionsTrie(): boolean {
const txT = this.header.transactionsTrie.toString('hex')
const txT = this.header.transactionsTrie
if (this.transactions.length) {
return txT === this.txTrie.root.toString('hex')
return txT.equals(this.txTrie.root)
} else {
return txT === KECCAK256_RLP.toString('hex')
return txT.equals(KECCAK256_RLP)
}
}

Expand Down Expand Up @@ -243,7 +262,7 @@ export class Block {
if (labeled) {
return {
header: this.header.toJSON(true),
transactions: this.transactions.map((tx) => tx.toJSON(true)),
transactions: this.transactions.map((tx) => tx.toJSON()),
uncleHeaders: this.uncleHeaders.forEach((uh) => uh.toJSON(true)),
}
} else {
Expand Down
27 changes: 20 additions & 7 deletions packages/block/src/from-rpc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { FakeTransaction, TransactionOptions } from '@ethereumjs/tx'
import { Transaction, TxData, Address } from '@ethereumjs/tx'
import Common from '@ethereumjs/common'
import { toBuffer, setLengthLeft } from 'ethereumjs-util'
import { Block, ChainOptions } from './index'

Expand Down Expand Up @@ -32,19 +33,30 @@ export default function blockFromRpc(
if (blockParams.transactions) {
for (const _txParams of blockParams.transactions) {
const txParams = normalizeTxParams(_txParams)

// override from address
const fromAddress = toBuffer(txParams.from)
const fromAddress = new Address(toBuffer(txParams.from))
delete txParams.from

const tx = new FakeTransaction(txParams, chainOptions as TransactionOptions)
tx.from = fromAddress
// get common based on block's number
// since hardfork param may not be set
// (see TODO in block.constructor)
const blockNumber = parseInt(block.header.number.toString('hex'), 16)
ryanio marked this conversation as resolved.
Show resolved Hide resolved
const hfs = (block as any)._common.activeHardforks(blockNumber)
const hf = hfs[hfs.length - 1].name
const common = new Common((block as any)._common.chainId(), hf)

const frozenTx = Transaction.fromTxData(txParams as TxData, common)
const tx = Object.create(frozenTx)

// override getSenderAddress
tx.getSenderAddress = function () {
return fromAddress
}

// override hash
const txHash = toBuffer(txParams.hash)
tx.hash = function () {
return txHash
return toBuffer(txParams.hash)
}

block.transactions.push(tx)
Expand All @@ -55,9 +67,10 @@ export default function blockFromRpc(

function normalizeTxParams(_txParams: any) {
const txParams = Object.assign({}, _txParams)
// hot fix for https://github.com/ethereumjs/ethereumjs-util/issues/40

txParams.gasLimit = txParams.gasLimit === undefined ? txParams.gas : txParams.gasLimit
txParams.data = txParams.data === undefined ? txParams.input : txParams.data

// strict byte length checking
txParams.to = txParams.to ? setLengthLeft(toBuffer(txParams.to), 20) : null

Expand Down
3 changes: 2 additions & 1 deletion packages/block/test/from-rpc.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ tape('[fromRPC]: block #2924874', function (t) {

t.test('should create a block header with the correct hash', function (st) {
const block = blockHeaderFromRpc(blockData)
st.ok(block.hash().compare(Buffer.from(blockData.hash)))
const hash = Buffer.from(blockData.hash.slice(2), 'hex')
st.ok(block.hash().equals(hash))
st.end()
})

Expand Down
4 changes: 3 additions & 1 deletion packages/blockchain/test/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ export const isConsecutive = (blocks: Block[]) => {
if (index === 0) {
return false
}
return Buffer.compare(block.header.parentHash, blocks[index - 1].hash()) !== 0
const { parentHash } = block.header
const lastBlockHash = blocks[index - 1].hash()
return !parentHash.equals(lastBlockHash)
})
}

Expand Down
38 changes: 17 additions & 21 deletions packages/tx/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ethereumjs-tx
# @ethereumjs/tx

[![NPM Package][tx-npm-badge]][tx-npm-link]
[![GitHub Issues][tx-issues-badge]][tx-issues-link]
Expand All @@ -10,18 +10,14 @@

# INSTALL

`npm install ethereumjs-tx`
`npm install @ethereumjs/tx`

# USAGE

- [example](https://github.com/ethereumjs/ethereumjs-tx/blob/master/examples/transactions.ts)
- [Example](./examples/transactions.ts)

```javascript
const EthereumTx = require('@ethereumjs/tx').Transaction
const privateKey = Buffer.from(
'e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109',
'hex',
)
import Transaction from '@ethereumjs/tx'

const txParams = {
nonce: '0x00',
Expand All @@ -32,21 +28,22 @@ const txParams = {
data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057',
}

// The second parameter is not necessary if these values are used
const tx = new EthereumTx(txParams, { chain: 'mainnet', hardfork: 'petersburg' })
tx.sign(privateKey)
const serializedTx = tx.serialize()
```
const common = new Common('mainnet', 'petersburg')
const tx = Transaction.fromTxData(txParams, common)

# Chain and Hardfork Support
const privateKey = Buffer.from(
'e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109',
'hex',
)

The `Transaction` and `FakeTransaction` constructors receives a second parameter that lets you specify the chain and hardfork
to be used. By default, `mainnet` and `petersburg` will be used.
const signedTx = tx.sign(privateKey)

There are two ways of customizing these. The first one, as shown in the previous section, is by
using an object with `chain` and `hardfork` names. You can see en example of this in [./examples/ropsten-tx.ts](./examples/ropsten-tx.ts).
const serializedTx = signedTx.serialize()
```

# Chain and Hardfork Support

The second option is by passing the option `common` set to an instance of [@ethereumjs/common](https://github.com/ethereumjs/ethereumjs-common)' Common. This is specially useful for custom networks or chains/hardforks not yet supported by `ethereumjs-common`. You can see en example of this in [./examples/custom-chain-tx.ts](./examples/custom-chain-tx.ts).
The `Transaction` constructor receives a second parameter of an [`@ethereumjs/common`](https://github.com/ethereumjs/ethereumjs-vm/blob/master/packages/common) object that lets you specify the chain and hardfork to be used. By default, `mainnet` and `petersburg` will be used.

## MuirGlacier Support

Expand All @@ -60,8 +57,7 @@ along with the `v2.1.1` release.

# EIP-155 support

`EIP-155` replay protection is activated since the `spuriousDragon` hardfork. To disable it, set the
hardfork in the `Transaction`'s constructor.
`EIP-155` replay protection is activated since the `spuriousDragon` hardfork. To disable it, set the hardfork to one earlier than `spuriousDragon`.

# API

Expand Down
14 changes: 7 additions & 7 deletions packages/tx/examples/custom-chain-tx.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Transaction } from '../src'
import Common from '@ethereumjs/common'
import { bufferToHex, privateToAddress } from 'ethereumjs-util'
import { privateToAddress } from 'ethereumjs-util'

// In this example we create a transaction for a custom network.
//
Expand All @@ -18,14 +18,14 @@ const customCommon = Common.forCustomChain(

// We pass our custom Common object whenever we create a transaction

const tx = new Transaction(
const tx = Transaction.fromTxData(
{
nonce: 0,
gasPrice: 100,
gasLimit: 1000000000,
value: 100000,
},
{ common: customCommon },
customCommon,
)

// Once we created the transaction using the custom Common object, we can use it as a normal tx.
Expand All @@ -36,15 +36,15 @@ const privateKey = Buffer.from(
'hex',
)

tx.sign(privateKey)
const signedTx = tx.sign(privateKey)

if (
tx.validate() &&
bufferToHex(tx.getSenderAddress()) === bufferToHex(privateToAddress(privateKey))
signedTx.validate() &&
signedTx.getSenderAddress().toBuffer().equals(privateToAddress(privateKey))
) {
console.log('Valid signature')
} else {
console.log('Invalid signature')
}

console.log("The transaction's chain id is", tx.getChainId())
console.log("The transaction's chain id is ", signedTx.getChainId())
10 changes: 6 additions & 4 deletions packages/tx/examples/ropsten-tx.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { Transaction } from '../src'
import { bufferToHex } from 'ethereumjs-util'
import { toBuffer } from 'ethereumjs-util'
import Common from '@ethereumjs/common'

const tx = new Transaction(
const txData = toBuffer(
'0xf9010b82930284d09dc30083419ce0942d18de92e0f9aee1a29770c3b15c6cf8ac5498e580b8a42f43f4fb0000000000000000000000000000000000000000000000000000016b78998da900000000000000000000000000000000000000000000000000000000000cb1b70000000000000000000000000000000000000000000000000000000000000fa00000000000000000000000000000000000000000000000000000000001363e4f00000000000000000000000000000000000000000000000000000000000186a029a0fac36e66d329af0e831b2e61179b3ec8d7c7a8a2179e303cfed3364aff2bc3e4a07cb73d56e561ccbd838818dd3dea5fa0b5158577ffc61c0e6ec1f0ed55716891',
{ chain: 'ropsten', hardfork: 'petersburg' },
)

const tx = Transaction.fromRlpSerializedTx(txData, new Common('ropsten', 'petersburg'))

if (
tx.validate() &&
bufferToHex(tx.getSenderAddress()) === '0x9dfd2d2b2ed960923f7bf2e8883d73f213f3b24b'
tx.getSenderAddress().toString() === '0x9dfd2d2b2ed960923f7bf2e8883d73f213f3b24b'
) {
console.log('Correctly created the tx')
} else {
Expand Down
Loading