Skip to content

Commit 41f158b

Browse files
Tx: get rid of BaseTransaction (#3744)
* tx: remove basetx [WIP] [no ci] * tx: prep legacy tx to remove basetx [no ci] * tx: move basetx constructor to shared constructor fn * tx: move json stuff to shared * tx: add comment * tx: 2930 remove basetx * tx: rename AccessList2930Transaction -> AccessList2930Tx * tx: legacy use shared legacy isSigned * tx: mini cleanup * tx: 2930 remove validateArray * tx: fix comment * tx: 2930 move methods around * tx: 1559 remove basetx * tx: 1559 group data part * tx: 4844 remove basetx * tx: legacy/2930 clarify data part * tx: 7702 remove basetx and rename to EOACode7702Tx * tx: fix build/imports * vm: fix build * tx: use correct PrefixedHexString for toJSON * tx: fix tests * vm/tx: fix more tests * tx: tests comment out failing tsc line * tx: cleanup error msgs * throw when gasPrice passed to 1559 tx * Revert "throw when gasPrice passed to 1559 tx" This reverts commit 6a9b15e. --------- Co-authored-by: acolytec3 <[email protected]>
1 parent 287f960 commit 41f158b

File tree

20 files changed

+984
-723
lines changed

20 files changed

+984
-723
lines changed

packages/tx/src/1559/tx.ts

Lines changed: 115 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Common } from '@ethereumjs/common'
21
import {
32
BIGINT_0,
43
BIGINT_27,
@@ -9,14 +8,13 @@ import {
98
toBytes,
109
} from '@ethereumjs/util'
1110

12-
import { BaseTransaction } from '../baseTransaction.js'
1311
import * as EIP1559 from '../capabilities/eip1559.js'
1412
import * as EIP2718 from '../capabilities/eip2718.js'
1513
import * as EIP2930 from '../capabilities/eip2930.js'
1614
import * as Legacy from '../capabilities/legacy.js'
17-
import { paramsTx } from '../params.js'
15+
import { getBaseJSON, sharedConstructor, valueBoundaryCheck } from '../features/util.js'
1816
import { TransactionType } from '../types.js'
19-
import { AccessLists, validateNotArray } from '../util.js'
17+
import { AccessLists } from '../util.js'
2018

2119
import { createFeeMarket1559Tx } from './constructors.js'
2220

@@ -25,9 +23,14 @@ import type {
2523
AccessListBytes,
2624
TxData as AllTypesTxData,
2725
TxValuesArray as AllTypesTxValuesArray,
26+
Capability,
2827
JSONTx,
28+
TransactionCache,
29+
TransactionInterface,
2930
TxOptions,
3031
} from '../types.js'
32+
import type { Common } from '@ethereumjs/common'
33+
import type { Address } from '@ethereumjs/util'
3134

3235
export type TxData = AllTypesTxData[TransactionType.FeeMarketEIP1559]
3336
export type TxValuesArray = AllTypesTxValuesArray[TransactionType.FeeMarketEIP1559]
@@ -38,15 +41,42 @@ export type TxValuesArray = AllTypesTxValuesArray[TransactionType.FeeMarketEIP15
3841
* - TransactionType: 2
3942
* - EIP: [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)
4043
*/
41-
export class FeeMarket1559Tx extends BaseTransaction<TransactionType.FeeMarketEIP1559> {
44+
export class FeeMarket1559Tx implements TransactionInterface<TransactionType.FeeMarketEIP1559> {
4245
// implements EIP1559CompatibleTx<TransactionType.FeeMarketEIP1559>
43-
public readonly chainId: bigint
46+
public type: number = TransactionType.FeeMarketEIP1559 // 1559 tx type
47+
48+
// Tx data part (part of the RLP)
49+
public readonly nonce!: bigint
50+
public readonly gasLimit!: bigint
51+
public readonly value!: bigint
52+
public readonly data!: Uint8Array
53+
public readonly to?: Address
4454
public readonly accessList: AccessListBytes
45-
public readonly AccessListJSON: AccessList
55+
public readonly chainId: bigint
4656
public readonly maxPriorityFeePerGas: bigint
4757
public readonly maxFeePerGas: bigint
4858

49-
public readonly common: Common
59+
// Props only for signed txs
60+
public readonly v?: bigint
61+
public readonly r?: bigint
62+
public readonly s?: bigint
63+
64+
// End of Tx data part
65+
66+
public readonly AccessListJSON: AccessList
67+
68+
public readonly common!: Common
69+
70+
readonly txOptions!: TxOptions
71+
72+
readonly cache: TransactionCache = {}
73+
74+
/**
75+
* List of tx type defining EIPs,
76+
* e.g. 1559 (fee market) and 2930 (access lists)
77+
* for FeeMarket1559Tx objects
78+
*/
79+
protected activeCapabilities: number[] = []
5080

5181
/**
5282
* This constructor takes the values, validates them, assigns them and freezes the object.
@@ -56,16 +86,14 @@ export class FeeMarket1559Tx extends BaseTransaction<TransactionType.FeeMarketEI
5686
* varying data types.
5787
*/
5888
public constructor(txData: TxData, opts: TxOptions = {}) {
59-
super({ ...txData, type: TransactionType.FeeMarketEIP1559 }, opts)
89+
sharedConstructor(this, { ...txData, type: TransactionType.FeeMarketEIP1559 }, opts)
6090
const { chainId, accessList, maxFeePerGas, maxPriorityFeePerGas } = txData
6191

62-
this.common = opts.common?.copy() ?? new Common({ chain: this.DEFAULT_CHAIN })
6392
if (chainId !== undefined && bytesToBigInt(toBytes(chainId)) !== this.common.chainId()) {
6493
throw new Error(
6594
`Common chain ID ${this.common.chainId} not matching the derived chain ID ${chainId}`,
6695
)
6796
}
68-
this.common.updateParams(opts.params ?? paramsTx)
6997
this.chainId = this.common.chainId()
7098

7199
if (!this.common.isActivatedEIP(1559)) {
@@ -83,20 +111,22 @@ export class FeeMarket1559Tx extends BaseTransaction<TransactionType.FeeMarketEI
83111
this.maxFeePerGas = bytesToBigInt(toBytes(maxFeePerGas))
84112
this.maxPriorityFeePerGas = bytesToBigInt(toBytes(maxPriorityFeePerGas))
85113

86-
this._validateCannotExceedMaxInteger({
114+
valueBoundaryCheck({
87115
maxFeePerGas: this.maxFeePerGas,
88116
maxPriorityFeePerGas: this.maxPriorityFeePerGas,
89117
})
90118

91-
validateNotArray(txData)
92-
93119
if (this.gasLimit * this.maxFeePerGas > MAX_INTEGER) {
94-
const msg = this._errorMsg('gasLimit * maxFeePerGas cannot exceed MAX_INTEGER (2^256-1)')
120+
const msg = Legacy.errorMsg(
121+
this,
122+
'gasLimit * maxFeePerGas cannot exceed MAX_INTEGER (2^256-1)',
123+
)
95124
throw new Error(msg)
96125
}
97126

98127
if (this.maxFeePerGas < this.maxPriorityFeePerGas) {
99-
const msg = this._errorMsg(
128+
const msg = Legacy.errorMsg(
129+
this,
100130
'maxFeePerGas cannot be less than maxPriorityFeePerGas (The total must be the larger of the two)',
101131
)
102132
throw new Error(msg)
@@ -111,6 +141,26 @@ export class FeeMarket1559Tx extends BaseTransaction<TransactionType.FeeMarketEI
111141
}
112142
}
113143

144+
/**
145+
* Checks if a tx type defining capability is active
146+
* on a tx, for example the EIP-1559 fee market mechanism
147+
* or the EIP-2930 access list feature.
148+
*
149+
* Note that this is different from the tx type itself,
150+
* so EIP-2930 access lists can very well be active
151+
* on an EIP-1559 tx for example.
152+
*
153+
* This method can be useful for feature checks if the
154+
* tx type is unknown (e.g. when instantiated with
155+
* the tx factory).
156+
*
157+
* See `Capabilities` in the `types` module for a reference
158+
* on all supported capabilities.
159+
*/
160+
supports(capability: Capability) {
161+
return this.activeCapabilities.includes(capability)
162+
}
163+
114164
/**
115165
* The amount of gas paid for the data in this tx
116166
*/
@@ -134,6 +184,24 @@ export class FeeMarket1559Tx extends BaseTransaction<TransactionType.FeeMarketEI
134184
return EIP1559.getUpfrontCost(this, baseFee)
135185
}
136186

187+
/**
188+
* The minimum gas limit which the tx to have to be valid.
189+
* This covers costs as the standard fee (21000 gas), the data fee (paid for each calldata byte),
190+
* the optional creation fee (if the transaction creates a contract), and if relevant the gas
191+
* to be paid for access lists (EIP-2930) and authority lists (EIP-7702).
192+
*/
193+
getIntrinsicGas(): bigint {
194+
return Legacy.getIntrinsicGas(this)
195+
}
196+
197+
// TODO figure out if this is necessary
198+
/**
199+
* If the tx's `to` is to the creation address
200+
*/
201+
toCreationAddress(): boolean {
202+
return Legacy.toCreationAddress(this)
203+
}
204+
137205
/**
138206
* Returns a Uint8Array Array of the raw Bytes of the EIP-1559 transaction, in order.
139207
*
@@ -262,7 +330,7 @@ export class FeeMarket1559Tx extends BaseTransaction<TransactionType.FeeMarketEI
262330
*/
263331
toJSON(): JSONTx {
264332
const accessListJSON = AccessLists.getAccessListJSON(this.accessList)
265-
const baseJSON = super.toJSON()
333+
const baseJSON = getBaseJSON(this)
266334

267335
return {
268336
...baseJSON,
@@ -273,22 +341,41 @@ export class FeeMarket1559Tx extends BaseTransaction<TransactionType.FeeMarketEI
273341
}
274342
}
275343

344+
getValidationErrors(): string[] {
345+
return Legacy.getValidationErrors(this)
346+
}
347+
348+
isValid(): boolean {
349+
return Legacy.isValid(this)
350+
}
351+
352+
verifySignature(): boolean {
353+
return Legacy.verifySignature(this)
354+
}
355+
356+
getSenderAddress(): Address {
357+
return Legacy.getSenderAddress(this)
358+
}
359+
360+
sign(privateKey: Uint8Array): FeeMarket1559Tx {
361+
return <FeeMarket1559Tx>Legacy.sign(this, privateKey)
362+
}
363+
364+
public isSigned(): boolean {
365+
const { v, r, s } = this
366+
if (v === undefined || r === undefined || s === undefined) {
367+
return false
368+
} else {
369+
return true
370+
}
371+
}
372+
276373
/**
277374
* Return a compact error string representation of the object
278375
*/
279376
public errorStr() {
280-
let errorStr = this._getSharedErrorPostfix()
377+
let errorStr = Legacy.getSharedErrorPostfix(this)
281378
errorStr += ` maxFeePerGas=${this.maxFeePerGas} maxPriorityFeePerGas=${this.maxPriorityFeePerGas}`
282379
return errorStr
283380
}
284-
285-
/**
286-
* Internal helper function to create an annotated error message
287-
*
288-
* @param msg Base error message
289-
* @hidden
290-
*/
291-
protected _errorMsg(msg: string) {
292-
return Legacy.errorMsg(this, msg)
293-
}
294381
}

packages/tx/src/2930/constructors.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { bytesToBigInt, bytesToHex, equalsBytes, validateNoLeadingZeroes } from
44
import { TransactionType } from '../types.js'
55
import { txTypeBytes, validateNotArray } from '../util.js'
66

7-
import { AccessList2930Transaction } from './tx.js'
7+
import { AccessList2930Tx } from './tx.js'
88

99
import type { AccessList, TxOptions } from '../types.js'
1010
import type { TxData, TxValuesArray } from './tx.js'
@@ -20,7 +20,7 @@ import type { TxData, TxValuesArray } from './tx.js'
2020
* - All parameters are optional and have some basic default values
2121
*/
2222
export function createAccessList2930Tx(txData: TxData, opts: TxOptions = {}) {
23-
return new AccessList2930Transaction(txData, opts)
23+
return new AccessList2930Tx(txData, opts)
2424
}
2525

2626
/**
@@ -43,7 +43,7 @@ export function createAccessList2930TxFromBytesArray(values: TxValuesArray, opts
4343

4444
const emptyAccessList: AccessList = []
4545

46-
return new AccessList2930Transaction(
46+
return new AccessList2930Tx(
4747
{
4848
chainId: bytesToBigInt(chainId),
4949
nonce,

packages/tx/src/2930/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export * from './constructors.js'
2-
export { AccessList2930Transaction } from './tx.js'
2+
export { AccessList2930Tx } from './tx.js'

0 commit comments

Comments
 (0)