Commit a0a00525 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

fix: backport value fixes (#766)

* dtl: index the value field (#686)

* chore: add changeset

* chore: add changeset

* dtl: pass through value field

* core-utils: update and test toRpcString

* lint: fix

* l2geth: parse value fields

* chore: add changeset

* dtl: prevent null reference in L1 handler (#757)

* dtl: prevent reference of null value

* chore: add changeset

* dtl: propagate value

* lint: fix
parent d2091d43
---
"@eth-optimism/data-transport-layer": patch
---
Parse and index the value field in the data transport layer
---
"@eth-optimism/l2geth": patch
---
Add value parsing to the rollup client
---
"@eth-optimism/core-utils": patch
---
Update toRpcHexString to accept ethers.BigNumber and add tests
---
'@eth-optimism/data-transport-layer': patch
---
Prevent access of null value in L1 transaction deserialization
...@@ -70,6 +70,7 @@ type transaction struct { ...@@ -70,6 +70,7 @@ type transaction struct {
BatchIndex uint64 `json:"batchIndex"` BatchIndex uint64 `json:"batchIndex"`
BlockNumber uint64 `json:"blockNumber"` BlockNumber uint64 `json:"blockNumber"`
Timestamp uint64 `json:"timestamp"` Timestamp uint64 `json:"timestamp"`
Value hexutil.Uint64 `json:"value"`
GasLimit uint64 `json:"gasLimit"` GasLimit uint64 `json:"gasLimit"`
Target common.Address `json:"target"` Target common.Address `json:"target"`
Origin *common.Address `json:"origin"` Origin *common.Address `json:"origin"`
...@@ -104,6 +105,7 @@ type signature struct { ...@@ -104,6 +105,7 @@ type signature struct {
// it means that the decoding failed. // it means that the decoding failed.
type decoded struct { type decoded struct {
Signature signature `json:"sig"` Signature signature `json:"sig"`
Value hexutil.Uint64 `json:"value"`
GasLimit uint64 `json:"gasLimit"` GasLimit uint64 `json:"gasLimit"`
GasPrice uint64 `json:"gasPrice"` GasPrice uint64 `json:"gasPrice"`
Nonce uint64 `json:"nonce"` Nonce uint64 `json:"nonce"`
...@@ -228,6 +230,7 @@ func enqueueToTransaction(enqueue *Enqueue) (*types.Transaction, error) { ...@@ -228,6 +230,7 @@ func enqueueToTransaction(enqueue *Enqueue) (*types.Transaction, error) {
} }
data := *enqueue.Data data := *enqueue.Data
// enqueue transactions have no value
value := big.NewInt(0) value := big.NewInt(0)
tx := types.NewTransaction(nonce, target, value, gasLimit, big.NewInt(0), data) tx := types.NewTransaction(nonce, target, value, gasLimit, big.NewInt(0), data)
...@@ -303,7 +306,7 @@ func batchedTransactionToTransaction(res *transaction, signer *types.OVMSigner) ...@@ -303,7 +306,7 @@ func batchedTransactionToTransaction(res *transaction, signer *types.OVMSigner)
if res.Decoded != nil { if res.Decoded != nil {
nonce := res.Decoded.Nonce nonce := res.Decoded.Nonce
to := res.Decoded.Target to := res.Decoded.Target
value := new(big.Int) value := new(big.Int).SetUint64(uint64(res.Decoded.Value))
// Note: there are two gas limits, one top level and // Note: there are two gas limits, one top level and
// another on the raw transaction itself. Maybe maxGasLimit // another on the raw transaction itself. Maybe maxGasLimit
// for the top level? // for the top level?
...@@ -357,7 +360,8 @@ func batchedTransactionToTransaction(res *transaction, signer *types.OVMSigner) ...@@ -357,7 +360,8 @@ func batchedTransactionToTransaction(res *transaction, signer *types.OVMSigner)
gasLimit := res.GasLimit gasLimit := res.GasLimit
data := res.Data data := res.Data
origin := res.Origin origin := res.Origin
tx := types.NewTransaction(nonce, target, big.NewInt(0), gasLimit, big.NewInt(0), data) value := new(big.Int).SetUint64(uint64(res.Value))
tx := types.NewTransaction(nonce, target, value, gasLimit, big.NewInt(0), data)
txMeta := types.NewTransactionMeta( txMeta := types.NewTransactionMeta(
new(big.Int).SetUint64(res.BlockNumber), new(big.Int).SetUint64(res.BlockNumber),
res.Timestamp, res.Timestamp,
......
...@@ -60,11 +60,18 @@ export const toHexString = (inp: Buffer | string | number | null): string => { ...@@ -60,11 +60,18 @@ export const toHexString = (inp: Buffer | string | number | null): string => {
} }
} }
export const toRpcHexString = (n: number): string => { export const toRpcHexString = (n: number | BigNumber): string => {
if (n === 0) { let num
return '0x0' if (typeof n === 'number') {
num = '0x' + n.toString(16)
} else { } else {
return '0x' + toHexString(n).slice(2).replace(/^0+/, '') num = n.toHexString()
}
if (num === '0x0') {
return num
} else {
return num.replace(/^0x0/, '0x')
} }
} }
......
import { expect } from '../setup' import { expect } from '../setup'
import { BigNumber } from 'ethers'
/* Imports: Internal */ /* Imports: Internal */
import { getRandomHexString } from '../../src' import { getRandomHexString, toRpcHexString } from '../../src'
describe('getRandomHexString', () => { describe('getRandomHexString', () => {
const random = global.Math.random const random = global.Math.random
...@@ -18,3 +19,24 @@ describe('getRandomHexString', () => { ...@@ -18,3 +19,24 @@ describe('getRandomHexString', () => {
expect(getRandomHexString(8)).to.equal('0x' + '88'.repeat(8)) expect(getRandomHexString(8)).to.equal('0x' + '88'.repeat(8))
}) })
}) })
describe('toRpcHexString', () => {
it('should parse 0', () => {
expect(toRpcHexString(0)).to.deep.equal('0x0')
expect(toRpcHexString(BigNumber.from(0))).to.deep.equal('0x0')
})
it('should parse non 0', () => {
const cases = [
{ input: 2, output: '0x2' },
{ input: BigNumber.from(2), output: '0x2' },
{ input: 100, output: '0x64' },
{ input: BigNumber.from(100), output: '0x64' },
{ input: 300, output: '0x12c' },
{ input: BigNumber.from(300), output: '0x12c' },
]
for (const test of cases) {
expect(toRpcHexString(test.input)).to.deep.equal(test.output)
}
})
})
...@@ -5,6 +5,7 @@ import { ...@@ -5,6 +5,7 @@ import {
ctcCoder, ctcCoder,
fromHexString, fromHexString,
toHexString, toHexString,
toRpcHexString,
TxType, TxType,
EventArgsSequencerBatchAppended, EventArgsSequencerBatchAppended,
} from '@eth-optimism/core-utils' } from '@eth-optimism/core-utils'
...@@ -120,6 +121,7 @@ export const handleEventsSequencerBatchAppended: EventHandlerSet< ...@@ -120,6 +121,7 @@ export const handleEventsSequencerBatchAppended: EventHandlerSet<
data: toHexString(sequencerTransaction), data: toHexString(sequencerTransaction),
queueOrigin: 'sequencer', queueOrigin: 'sequencer',
type, type,
value: decoded ? decoded.value : '0x0',
queueIndex: null, queueIndex: null,
decoded, decoded,
confirmed: true, confirmed: true,
...@@ -152,6 +154,7 @@ export const handleEventsSequencerBatchAppended: EventHandlerSet< ...@@ -152,6 +154,7 @@ export const handleEventsSequencerBatchAppended: EventHandlerSet<
data: '0x', data: '0x',
queueOrigin: 'l1', queueOrigin: 'l1',
type: 'EIP155', type: 'EIP155',
value: '0x0',
queueIndex: queueIndex.toNumber(), queueIndex: queueIndex.toNumber(),
decoded: null, decoded: null,
confirmed: true, confirmed: true,
...@@ -254,6 +257,8 @@ const maybeDecodeSequencerBatchTransaction = ( ...@@ -254,6 +257,8 @@ const maybeDecodeSequencerBatchTransaction = (
} else { } else {
throw new Error(`Unknown sequencer transaction type.`) throw new Error(`Unknown sequencer transaction type.`)
} }
// Temporary fix to propagate the value
decoded.value = '0x0'
// Validate the transaction // Validate the transaction
if (!validateBatchTransaction(type, decoded)) { if (!validateBatchTransaction(type, decoded)) {
decoded = null decoded = null
......
...@@ -32,6 +32,7 @@ export const handleSequencerBlock = { ...@@ -32,6 +32,7 @@ export const handleSequencerBlock = {
let transactionEntry: Partial<TransactionEntry> = { let transactionEntry: Partial<TransactionEntry> = {
// Legacy support. // Legacy support.
index: transactionIndex, index: transactionIndex,
value: transaction.value,
batchIndex: null, batchIndex: null,
blockNumber: BigNumber.from(transaction.l1BlockNumber).toNumber(), blockNumber: BigNumber.from(transaction.l1BlockNumber).toNumber(),
timestamp: BigNumber.from(transaction.l1Timestamp).toNumber(), timestamp: BigNumber.from(transaction.l1Timestamp).toNumber(),
...@@ -47,6 +48,7 @@ export const handleSequencerBlock = { ...@@ -47,6 +48,7 @@ export const handleSequencerBlock = {
r: padHexString(transaction.r, 32), r: padHexString(transaction.r, 32),
s: padHexString(transaction.s, 32), s: padHexString(transaction.s, 32),
}, },
value: transaction.value,
gasLimit: BigNumber.from(transaction.gas).toNumber(), gasLimit: BigNumber.from(transaction.gas).toNumber(),
gasPrice: BigNumber.from(transaction.gasPrice).toNumber(), // ? gasPrice: BigNumber.from(transaction.gasPrice).toNumber(), // ?
nonce: BigNumber.from(transaction.nonce).toNumber(), nonce: BigNumber.from(transaction.nonce).toNumber(),
......
...@@ -4,6 +4,7 @@ export interface DecodedSequencerBatchTransaction { ...@@ -4,6 +4,7 @@ export interface DecodedSequencerBatchTransaction {
s: string s: string
v: number v: number
} }
value: string
gasLimit: number gasLimit: number
gasPrice: number gasPrice: number
nonce: number nonce: number
...@@ -31,6 +32,7 @@ export interface TransactionEntry { ...@@ -31,6 +32,7 @@ export interface TransactionEntry {
gasLimit: number gasLimit: number
target: string target: string
origin: string origin: string
value: string
queueOrigin: 'sequencer' | 'l1' queueOrigin: 'sequencer' | 'l1'
queueIndex: number | null queueIndex: number | null
type: 'EIP155' | 'ETH_SIGN' | null type: 'EIP155' | 'ETH_SIGN' | null
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment