Skip to content

Commit 7371fdf

Browse files
authored
Merge pull request #941 from ethereumjs/block-tx-freeze-optionality
New freeze option to deactivate block, tx freeze / Fix block options passing
2 parents 5f46d14 + a8351ec commit 7371fdf

File tree

10 files changed

+149
-9
lines changed

10 files changed

+149
-9
lines changed

packages/block/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
(modification: no type change headlines) and this project adheres to
77
[Semantic Versioning](http://semver.org/spec/v2.0.0.html).
88

9+
## 3.0.0-beta.2 - UNRELEASED
10+
11+
- Added `freeze` option to allow for block freeze deactivation (e.g. to allow for subclassing block and adding additional parameters), see PR [#941](https://github.com/ethereumjs/ethereumjs-vm/pull/941)
12+
- Fixed bug where block options have not been passed on to the main constructor from the static factory methods, see PR [#941](https://github.com/ethereumjs/ethereumjs-vm/pull/941)
13+
914
## 3.0.0-beta.1 - 2020-10-22
1015

1116
### New Package Name

packages/block/src/block.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export class Block {
3636
uncleHeaders.push(uh)
3737
}
3838

39-
return new Block(header, transactions, uncleHeaders)
39+
return new Block(header, transactions, uncleHeaders, opts)
4040
}
4141

4242
public static fromRLPSerializedBlock(serialized: Buffer, opts?: BlockOptions) {
@@ -70,7 +70,7 @@ export class Block {
7070
uncleHeaders.push(BlockHeader.fromValuesArray(uncleHeaderData, opts))
7171
}
7272

73-
return new Block(header, transactions, uncleHeaders)
73+
return new Block(header, transactions, uncleHeaders, opts)
7474
}
7575

7676
/**
@@ -96,7 +96,10 @@ export class Block {
9696
this.uncleHeaders = uncleHeaders
9797
this._common = this.header._common
9898

99-
Object.freeze(this)
99+
const freeze = opts?.freeze ?? true
100+
if (freeze) {
101+
Object.freeze(this)
102+
}
100103
}
101104

102105
/**

packages/block/src/header.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,10 @@ export class BlockHeader {
230230
this.difficulty = this.canonicalDifficulty(options.calcDifficultyFromHeader)
231231
}
232232

233-
Object.freeze(this)
233+
const freeze = options?.freeze ?? true
234+
if (freeze) {
235+
Object.freeze(this)
236+
}
234237
}
235238

236239
/**

packages/block/src/types.ts

+11
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ export interface BlockOptions {
4343
* difficulty takes precedence over a provided static `difficulty` value.
4444
*/
4545
calcDifficultyFromHeader?: BlockHeader
46+
/**
47+
* A block object by default gets frozen along initialization. This gives you
48+
* strong additional security guarantees on the consistency of the block parameters.
49+
*
50+
* If you need to deactivate the block freeze - e.g. because you want to subclass block and
51+
* add aditional properties - it is strongly encouraged that you do the freeze yourself
52+
* within your code instead.
53+
*
54+
* Default: true
55+
*/
56+
freeze?: boolean
4657
}
4758

4859
/**

packages/block/test/block.spec.ts

+41-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,52 @@
11
import tape from 'tape'
2-
import { rlp } from 'ethereumjs-util'
2+
import { rlp, zeros } from 'ethereumjs-util'
33
import Common from '@ethereumjs/common'
4-
import { Block } from '../src'
4+
import { Block, BlockBuffer } from '../src'
55

66
tape('[Block]: block functions', function (t) {
77
t.test('should test block initialization', function (st) {
88
const common = new Common({ chain: 'ropsten', hardfork: 'chainstart' })
99
const genesis = Block.genesis({}, { common })
1010
st.ok(genesis.hash().toString('hex'), 'block should initialize')
11+
12+
// test default freeze values
13+
// also test if the options are carried over to the constructor
14+
let block = Block.fromBlockData({})
15+
st.ok(Object.isFrozen(block), 'block should be frozen by default')
16+
17+
block = Block.fromBlockData({}, { freeze: false })
18+
st.ok(!Object.isFrozen(block), 'block should not be frozen when freeze deactivated in options')
19+
20+
const rlpBlock = block.serialize()
21+
block = Block.fromRLPSerializedBlock(rlpBlock)
22+
st.ok(Object.isFrozen(block), 'block should be frozen by default')
23+
24+
block = Block.fromRLPSerializedBlock(rlpBlock, { freeze: false })
25+
st.ok(!Object.isFrozen(block), 'block should not be frozen when freeze deactivated in options')
26+
27+
const zero = Buffer.alloc(0)
28+
const headerArray = []
29+
for (let item = 0; item < 15; item++) {
30+
headerArray.push(zero)
31+
}
32+
33+
// mock header data (if set to zeros(0) header throws)
34+
headerArray[0] = zeros(32) //parentHash
35+
headerArray[2] = zeros(20) //coinbase
36+
headerArray[3] = zeros(32) //stateRoot
37+
headerArray[4] = zeros(32) //transactionsTrie
38+
headerArray[5] = zeros(32) //receiptTrie
39+
headerArray[13] = zeros(32) // mixHash
40+
headerArray[14] = zeros(8) // nonce
41+
42+
const valuesArray = <BlockBuffer>[headerArray, [], []]
43+
44+
block = Block.fromValuesArray(valuesArray)
45+
st.ok(Object.isFrozen(block), 'block should be frozen by default')
46+
47+
block = Block.fromValuesArray(valuesArray, { freeze: false })
48+
st.ok(!Object.isFrozen(block), 'block should not be frozen when freeze deactivated in options')
49+
1150
st.end()
1251
})
1352

packages/block/test/header.spec.ts

+38-1
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,45 @@ tape('[Block]: Header functions', function (t) {
3535

3636
t.test('should test header initialization', function (st) {
3737
const common = new Common({ chain: 'ropsten', hardfork: 'chainstart' })
38-
const header = BlockHeader.genesis(undefined, { common })
38+
let header = BlockHeader.genesis(undefined, { common })
3939
st.ok(header.hash().toString('hex'), 'block should initialize')
40+
41+
// test default freeze values
42+
// also test if the options are carried over to the constructor
43+
header = BlockHeader.fromHeaderData({})
44+
st.ok(Object.isFrozen(header), 'block should be frozen by default')
45+
46+
header = BlockHeader.fromHeaderData({}, { freeze: false })
47+
st.ok(!Object.isFrozen(header), 'block should not be frozen when freeze deactivated in options')
48+
49+
const rlpHeader = header.serialize()
50+
header = BlockHeader.fromRLPSerializedHeader(rlpHeader)
51+
st.ok(Object.isFrozen(header), 'block should be frozen by default')
52+
53+
header = BlockHeader.fromRLPSerializedHeader(rlpHeader, { freeze: false })
54+
st.ok(!Object.isFrozen(header), 'block should not be frozen when freeze deactivated in options')
55+
56+
const zero = Buffer.alloc(0)
57+
const headerArray = []
58+
for (let item = 0; item < 15; item++) {
59+
headerArray.push(zero)
60+
}
61+
62+
// mock header data (if set to zeros(0) header throws)
63+
headerArray[0] = zeros(32) //parentHash
64+
headerArray[2] = zeros(20) //coinbase
65+
headerArray[3] = zeros(32) //stateRoot
66+
headerArray[4] = zeros(32) //transactionsTrie
67+
headerArray[5] = zeros(32) //receiptTrie
68+
headerArray[13] = zeros(32) // mixHash
69+
headerArray[14] = zeros(8) // nonce
70+
71+
header = BlockHeader.fromValuesArray(headerArray)
72+
st.ok(Object.isFrozen(header), 'block should be frozen by default')
73+
74+
header = BlockHeader.fromValuesArray(headerArray, { freeze: false })
75+
st.ok(!Object.isFrozen(header), 'block should not be frozen when freeze deactivated in options')
76+
4077
st.end()
4178
})
4279

packages/tx/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
(modification: no type change headlines) and this project adheres to
77
[Semantic Versioning](http://semver.org/spec/v2.0.0.html).
88

9+
## 3.0.0-beta.2 - UNRELEASED
10+
11+
- Added `freeze` option to allow for transaction freeze deactivation (e.g. to allow for subclassing tx and adding additional parameters), see PR [#941](https://github.com/ethereumjs/ethereumjs-vm/pull/941)
12+
913
## 3.0.0-beta.1 - 2020-10-22
1014

1115
### New Package Name

packages/tx/src/transaction.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,10 @@ export default class Transaction {
136136
this.r = r
137137
this.s = s
138138

139-
Object.freeze(this)
139+
const freeze = opts?.freeze ?? true
140+
if (freeze) {
141+
Object.freeze(this)
142+
}
140143
}
141144

142145
/**

packages/tx/src/types.ts

+11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@ export interface TxOptions {
1313
* Current default hardfork: `istanbul`
1414
*/
1515
common?: Common
16+
/**
17+
* A transaction object by default gets frozen along initialization. This gives you
18+
* strong additional security guarantees on the consistency of the tx parameters.
19+
*
20+
* If you need to deactivate the tx freeze - e.g. because you want to subclass tx and
21+
* add aditional properties - it is strongly encouraged that you do the freeze yourself
22+
* within your code instead.
23+
*
24+
* Default: true
25+
*/
26+
freeze?: boolean
1627
}
1728

1829
/**

packages/tx/test/api.ts

+25-1
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,32 @@ tape('[Transaction]: Basic functions', function (t) {
2020
const transactions: Transaction[] = []
2121

2222
t.test('should initialize correctly', function (st) {
23-
const tx = Transaction.fromTxData({})
23+
let tx = Transaction.fromTxData({})
2424
st.equal(tx.common.hardfork(), 'istanbul', 'should initialize with correct default HF')
25+
st.ok(Object.isFrozen(tx), 'tx should be frozen by default')
26+
27+
tx = Transaction.fromTxData({}, { freeze: false })
28+
st.ok(!Object.isFrozen(tx), 'tx should not be frozen when freeze deactivated in options')
29+
30+
// Perform the same test as above, but now using a different construction method. This also implies that passing on the
31+
// options object works as expected.
32+
const rlpData = tx.serialize()
33+
34+
const zero = Buffer.alloc(0)
35+
const valuesArray = [zero, zero, zero, zero, zero, zero]
36+
37+
tx = Transaction.fromRlpSerializedTx(rlpData)
38+
st.ok(Object.isFrozen(tx), 'tx should be frozen by default')
39+
40+
tx = Transaction.fromRlpSerializedTx(rlpData, { freeze: false })
41+
st.ok(!Object.isFrozen(tx), 'tx should not be frozen when freeze deactivated in options')
42+
43+
tx = Transaction.fromValuesArray(valuesArray)
44+
st.ok(Object.isFrozen(tx), 'tx should be frozen by default')
45+
46+
tx = Transaction.fromValuesArray(valuesArray, { freeze: false })
47+
st.ok(!Object.isFrozen(tx), 'tx should not be frozen when freeze deactivated in options')
48+
2549
st.end()
2650
})
2751

0 commit comments

Comments
 (0)