Skip to content

Commit

Permalink
tx: consolidate generic tx capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrocheleau committed Aug 26, 2023
1 parent 35ec012 commit 414afdc
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 173 deletions.
62 changes: 62 additions & 0 deletions packages/tx/src/capabilities/generic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { bigIntToUnpaddedBytes, ecrecover } from '@ethereumjs/util'
import { keccak256 } from 'ethereum-cryptography/keccak.js'

import { Capability, type TypedTransaction } from '../types.js'

export function isSigned(this: TypedTransaction): boolean {
const { v, r, s } = this
if (v === undefined || r === undefined || s === undefined) {
return false
} else {
return true
}
}

export function errorMsg(this: TypedTransaction, msg: string) {
return `${msg} (${this.errorStr()})`
}

export function hash(this: TypedTransaction): Uint8Array {
if (!this.isSigned()) {
const msg = errorMsg.bind(this)('Cannot call hash method if transaction is not signed')
throw new Error(msg)
}

if (Object.isFrozen(this)) {
if (!this['cache'].hash) {
this['cache'].hash = keccak256(this.serialize())
}
return this['cache'].hash
}

return keccak256(this.serialize())
}

export function getSenderPublicKey(this: TypedTransaction): Uint8Array {
if (this['cache'].senderPubKey !== undefined) {
return this['cache'].senderPubKey
}

const msgHash = this.getMessageToVerifySignature()

const { v, r, s } = this

this['_validateHighS']()

try {
const sender = ecrecover(
msgHash,
v!,
bigIntToUnpaddedBytes(r!),
bigIntToUnpaddedBytes(s!),
this.supports(Capability.EIP155ReplayProtection) ? this.common.chainId() : undefined
)
if (Object.isFrozen(this)) {
this['cache'].senderPubKey = sender
}
return sender
} catch (e: any) {
const msg = errorMsg.bind(this)('Invalid Signature')
throw new Error(msg)
}
}
48 changes: 4 additions & 44 deletions packages/tx/src/eip1559Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
bytesToBigInt,
bytesToHex,
concatBytes,
ecrecover,
equalsBytes,
hexToBytes,
toBytes,
Expand All @@ -15,6 +14,7 @@ import {
import { keccak256 } from 'ethereum-cryptography/keccak.js'

import { BaseTransaction } from './baseTransaction.js'
import * as Generic from './capabilities/generic.js'
import { TransactionType } from './types.js'
import { AccessLists } from './util.js'

Expand Down Expand Up @@ -310,19 +310,7 @@ export class FeeMarketEIP1559Transaction extends BaseTransaction<TransactionType
* Use {@link FeeMarketEIP1559Transaction.getMessageToSign} to get a tx hash for the purpose of signing.
*/
public hash(): Uint8Array {
if (!this.isSigned()) {
const msg = this._errorMsg('Cannot call hash method if transaction is not signed')
throw new Error(msg)
}

if (Object.isFrozen(this)) {
if (!this.cache.hash) {
this.cache.hash = keccak256(this.serialize())
}
return this.cache.hash
}

return keccak256(this.serialize())
return Generic.hash.bind(this)()
}

/**
Expand All @@ -336,35 +324,7 @@ export class FeeMarketEIP1559Transaction extends BaseTransaction<TransactionType
* Returns the public key of the sender
*/
public getSenderPublicKey(): Uint8Array {
if (this.cache.senderPubKey !== undefined) {
return this.cache.senderPubKey
}

if (!this.isSigned()) {
const msg = this._errorMsg('Cannot call this method if transaction is not signed')
throw new Error(msg)
}

const msgHash = this.getMessageToVerifySignature()
const { v, r, s } = this

this._validateHighS()

try {
const sender = ecrecover(
msgHash,
v! + BigInt(27), // Recover the 27 which was stripped from ecsign
bigIntToUnpaddedBytes(r!),
bigIntToUnpaddedBytes(s!)
)
if (Object.isFrozen(this)) {
this.cache.senderPubKey = sender
}
return sender
} catch (e: any) {
const msg = this._errorMsg('Invalid Signature')
throw new Error(msg)
}
return Generic.getSenderPublicKey.bind(this)()
}

protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array) {
Expand Down Expand Up @@ -421,6 +381,6 @@ export class FeeMarketEIP1559Transaction extends BaseTransaction<TransactionType
* @hidden
*/
protected _errorMsg(msg: string) {
return `${msg} (${this.errorStr()})`
return Generic.errorMsg.bind(this)(msg)
}
}
48 changes: 4 additions & 44 deletions packages/tx/src/eip2930Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
bytesToBigInt,
bytesToHex,
concatBytes,
ecrecover,
equalsBytes,
hexToBytes,
toBytes,
Expand All @@ -15,6 +14,7 @@ import {
import { keccak256 } from 'ethereum-cryptography/keccak.js'

import { BaseTransaction } from './baseTransaction.js'
import * as Generic from './capabilities/generic.js'
import { TransactionType } from './types.js'
import { AccessLists } from './util.js'

Expand Down Expand Up @@ -281,19 +281,7 @@ export class AccessListEIP2930Transaction extends BaseTransaction<TransactionTyp
* Use {@link AccessListEIP2930Transaction.getMessageToSign} to get a tx hash for the purpose of signing.
*/
public hash(): Uint8Array {
if (!this.isSigned()) {
const msg = this._errorMsg('Cannot call hash method if transaction is not signed')
throw new Error(msg)
}

if (Object.isFrozen(this)) {
if (!this.cache.hash) {
this.cache.hash = keccak256(this.serialize())
}
return this.cache.hash
}

return keccak256(this.serialize())
return Generic.hash.bind(this)()
}

/**
Expand All @@ -307,35 +295,7 @@ export class AccessListEIP2930Transaction extends BaseTransaction<TransactionTyp
* Returns the public key of the sender
*/
public getSenderPublicKey(): Uint8Array {
if (this.cache.senderPubKey !== undefined) {
return this.cache.senderPubKey
}

if (!this.isSigned()) {
const msg = this._errorMsg('Cannot call this method if transaction is not signed')
throw new Error(msg)
}

const msgHash = this.getMessageToVerifySignature()
const { v, r, s } = this

this._validateHighS()

try {
const sender = ecrecover(
msgHash,
v! + BigInt(27), // Recover the 27 which was stripped from ecsign
bigIntToUnpaddedBytes(r!),
bigIntToUnpaddedBytes(s!)
)
if (Object.isFrozen(this)) {
this.cache.senderPubKey = sender
}
return sender
} catch (e: any) {
const msg = this._errorMsg('Invalid Signature')
throw new Error(msg)
}
return Generic.getSenderPublicKey.bind(this)()
}

protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array) {
Expand Down Expand Up @@ -391,6 +351,6 @@ export class AccessListEIP2930Transaction extends BaseTransaction<TransactionTyp
* @hidden
*/
protected _errorMsg(msg: string) {
return `${msg} (${this.errorStr()})`
return Generic.errorMsg.bind(this)(msg)
}
}
48 changes: 4 additions & 44 deletions packages/tx/src/eip4844Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
commitmentsToVersionedHashes,
computeVersionedHash,
concatBytes,
ecrecover,
equalsBytes,
getBlobs,
hexToBytes,
Expand All @@ -21,6 +20,7 @@ import {
import { keccak256 } from 'ethereum-cryptography/keccak.js'

import { BaseTransaction } from './baseTransaction.js'
import * as Generic from './capabilities/generic.js'
import { LIMIT_BLOBS_PER_TX } from './constants.js'
import { TransactionType } from './types.js'
import { AccessLists } from './util.js'
Expand Down Expand Up @@ -511,19 +511,7 @@ export class BlobEIP4844Transaction extends BaseTransaction<TransactionType.Blob
* Use {@link BlobEIP4844Transaction.getMessageToSign} to get a tx hash for the purpose of signing.
*/
public hash(): Uint8Array {
if (!this.isSigned()) {
const msg = this._errorMsg('Cannot call hash method if transaction is not signed')
throw new Error(msg)
}

if (Object.isFrozen(this)) {
if (!this.cache.hash) {
this.cache.hash = keccak256(this.serialize())
}
return this.cache.hash
}

return keccak256(this.serialize())
return Generic.hash.bind(this)()
}

getMessageToVerifySignature(): Uint8Array {
Expand All @@ -534,35 +522,7 @@ export class BlobEIP4844Transaction extends BaseTransaction<TransactionType.Blob
* Returns the public key of the sender
*/
public getSenderPublicKey(): Uint8Array {
if (this.cache.senderPubKey !== undefined) {
return this.cache.senderPubKey
}

if (!this.isSigned()) {
const msg = this._errorMsg('Cannot call this method if transaction is not signed')
throw new Error(msg)
}

const msgHash = this.getMessageToVerifySignature()
const { v, r, s } = this

this._validateHighS()

try {
const sender = ecrecover(
msgHash,
v! + BigInt(27), // Recover the 27 which was stripped from ecsign
bigIntToUnpaddedBytes(r!),
bigIntToUnpaddedBytes(s!)
)
if (Object.isFrozen(this)) {
this.cache.senderPubKey = sender
}
return sender
} catch (e: any) {
const msg = this._errorMsg('Invalid Signature')
throw new Error(msg)
}
return Generic.getSenderPublicKey.bind(this)()
}

toJSON(): JsonTx {
Expand Down Expand Up @@ -622,7 +582,7 @@ export class BlobEIP4844Transaction extends BaseTransaction<TransactionType.Blob
* @hidden
*/
protected _errorMsg(msg: string) {
return `${msg} (${this.errorStr()})`
return Generic.errorMsg.bind(this)(msg)
}

/**
Expand Down
45 changes: 4 additions & 41 deletions packages/tx/src/legacyTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import {
bigIntToHex,
bigIntToUnpaddedBytes,
bytesToBigInt,
ecrecover,
toBytes,
unpadBytes,
validateNoLeadingZeroes,
} from '@ethereumjs/util'
import { keccak256 } from 'ethereum-cryptography/keccak.js'

import { BaseTransaction } from './baseTransaction.js'
import * as Generic from './capabilities/generic.js'
import { Capability, TransactionType } from './types.js'

import type {
Expand Down Expand Up @@ -256,19 +256,7 @@ export class LegacyTransaction extends BaseTransaction<TransactionType.Legacy> {
* Use {@link Transaction.getMessageToSign} to get a tx hash for the purpose of signing.
*/
hash(): Uint8Array {
if (!this.isSigned()) {
const msg = this._errorMsg('Cannot call hash method if transaction is not signed')
throw new Error(msg)
}

if (Object.isFrozen(this)) {
if (!this.cache.hash) {
this.cache.hash = keccak256(RLP.encode(this.raw()))
}
return this.cache.hash
}

return keccak256(RLP.encode(this.raw()))
return Generic.hash.bind(this)()
}

/**
Expand All @@ -286,32 +274,7 @@ export class LegacyTransaction extends BaseTransaction<TransactionType.Legacy> {
* Returns the public key of the sender
*/
getSenderPublicKey(): Uint8Array {
if (this.cache.senderPubKey !== undefined) {
return this.cache.senderPubKey
}

const msgHash = this.getMessageToVerifySignature()

const { v, r, s } = this

this._validateHighS()

try {
const sender = ecrecover(
msgHash,
v!,
bigIntToUnpaddedBytes(r!),
bigIntToUnpaddedBytes(s!),
this.supports(Capability.EIP155ReplayProtection) ? this.common.chainId() : undefined
)
if (Object.isFrozen(this)) {
this.cache.senderPubKey = sender
}
return sender
} catch (e: any) {
const msg = this._errorMsg('Invalid Signature')
throw new Error(msg)
}
return Generic.getSenderPublicKey.bind(this)()
}

/**
Expand Down Expand Up @@ -413,6 +376,6 @@ export class LegacyTransaction extends BaseTransaction<TransactionType.Legacy> {
* @hidden
*/
protected _errorMsg(msg: string) {
return `${msg} (${this.errorStr()})`
return Generic.errorMsg.bind(this)(msg)
}
}

0 comments on commit 414afdc

Please sign in to comment.