Commit 27d8942e authored by Mark Tyneway's avatar Mark Tyneway

core-utils: update batch serialization

Update the batch serialization to allow for typed batches.
Also include logic for type 0 batches, which are compressed
with zlib.
parent 8ef006f7
---
'@eth-optimism/core-utils': patch
---
Update batch serialization with typed batches and zlib compression
...@@ -35,7 +35,9 @@ ...@@ -35,7 +35,9 @@
"@ethersproject/abstract-provider": "^5.5.1", "@ethersproject/abstract-provider": "^5.5.1",
"@ethersproject/bytes": "^5.5.0", "@ethersproject/bytes": "^5.5.0",
"@ethersproject/providers": "^5.5.3", "@ethersproject/providers": "^5.5.3",
"@ethersproject/transactions": "^5.5.0",
"@ethersproject/web": "^5.5.1", "@ethersproject/web": "^5.5.1",
"bufio": "^1.0.7",
"chai": "^4.3.4", "chai": "^4.3.4",
"ethers": "^5.5.4" "ethers": "^5.5.4"
}, },
......
declare module 'bufio' {
class BufferWriter {
public offset: number
constructor()
render(): Buffer
getSize(): number
seek(offset: number): this
destroy(): this
writeU8(n: number): this
writeU16(n: number): this
writeU16BE(n: number): this
writeU24(n: number): this
writeU24BE(n: number): this
writeU32(n: number): this
writeU32BE(n: number): this
writeU40(n: number): this
writeU40BE(n: number): this
writeU48(n: number): this
writeU48BE(n: number): this
writeU56(n: number): this
writeU56BE(n: number): this
writeU64(n: number): this
writeU64BE(n: number): this
writeBytes(b: Buffer): this
copy(value: number, start: number, end: number): this
}
class BufferReader {
constructor(data: Buffer, copy?: boolean)
getSize(): number
check(n: number): void
left(): number
seek(offset: number): this
start(): number
end(): number
destroy(): this
readU8(): number
readU16(): number
readU16BE(): number
readU24(): number
readU24BE(): number
readU32(): number
readU32BE(): number
readU40(): number
readU40BE(): number
readU48(): number
readU48BE(): number
readU56(): number
readU56BE(): number
readU64(): number
readU64BE(): number
readBytes(size: number, copy?: boolean): Buffer
}
class Struct {
constructor()
encode(extra?: object): Buffer
decode<T extends Struct>(data: Buffer, extra?: object): T
getSize(extra?: object): number
fromHex(s: string, extra?: object): this
toHex(): string
write(bw: BufferWriter, extra?: object): BufferWriter
read(br: BufferReader, extra?: object): this
static read<T extends Struct>(br: BufferReader, extra?: object): T
static decode<T extends Struct>(data: Buffer, extra?: object): T
static fromHex<T extends Struct>(s: string, extra?: object): T
}
}
...@@ -7,23 +7,31 @@ import { ...@@ -7,23 +7,31 @@ import {
encodeAppendSequencerBatch, encodeAppendSequencerBatch,
decodeAppendSequencerBatch, decodeAppendSequencerBatch,
sequencerBatch, sequencerBatch,
BatchType,
SequencerBatch,
} from '../src' } from '../src'
describe('BatchEncoder', () => { describe('BatchEncoder', function () {
this.timeout(10_000)
// eslint-disable-next-line @typescript-eslint/no-var-requires
const data = require('./fixtures/calldata.json')
describe('appendSequencerBatch', () => { describe('appendSequencerBatch', () => {
it('should work with the simple case', () => { it('legacy: should work with the simple case', () => {
const batch = { const batch = {
shouldStartAtElement: 0, shouldStartAtElement: 0,
totalElementsToAppend: 0, totalElementsToAppend: 0,
contexts: [], contexts: [],
transactions: [], transactions: [],
type: BatchType.LEGACY,
} }
const encoded = encodeAppendSequencerBatch(batch) const encoded = encodeAppendSequencerBatch(batch)
const decoded = decodeAppendSequencerBatch(encoded) const decoded = decodeAppendSequencerBatch(encoded)
expect(decoded).to.deep.equal(batch) expect(decoded).to.deep.equal(batch)
}) })
it('should work with more complex case', () => { it('legacy: should work with more complex case', () => {
const batch = { const batch = {
shouldStartAtElement: 10, shouldStartAtElement: 10,
totalElementsToAppend: 1, totalElementsToAppend: 1,
...@@ -36,19 +44,57 @@ describe('BatchEncoder', () => { ...@@ -36,19 +44,57 @@ describe('BatchEncoder', () => {
}, },
], ],
transactions: ['0x45423400000011', '0x45423400000012'], transactions: ['0x45423400000011', '0x45423400000012'],
type: BatchType.LEGACY,
} }
const encoded = encodeAppendSequencerBatch(batch) const encoded = encodeAppendSequencerBatch(batch)
const decoded = decodeAppendSequencerBatch(encoded) const decoded = decodeAppendSequencerBatch(encoded)
expect(decoded).to.deep.equal(batch) expect(decoded).to.deep.equal(batch)
}) })
it('should work with mainnet calldata', () => { describe('mainnet data', () => {
// eslint-disable-next-line @typescript-eslint/no-var-requires for (const [hash, calldata] of Object.entries(data)) {
const data = require('./fixtures/appendSequencerBatch.json') // Deserialize the raw calldata
for (const calldata of data.calldata) { const decoded = SequencerBatch.fromHex<SequencerBatch>(
const decoded = sequencerBatch.decode(calldata) calldata as string
const encoded = sequencerBatch.encode(decoded) )
expect(encoded).to.equal(calldata)
it(`${hash}`, () => {
const encoded = decoded.toHex()
expect(encoded).to.deep.equal(calldata)
const batch = SequencerBatch.decode(decoded.encode())
expect(decoded).to.deep.eq(batch)
})
it(`${hash} (compressed)`, () => {
// Set the batch type to be zlib so that the batch
// is compressed
decoded.type = BatchType.ZLIB
// Encode a compressed batch
const encodedCompressed = decoded.encode()
// Decode a compressed batch
const decodedPostCompressed =
SequencerBatch.decode<SequencerBatch>(encodedCompressed)
// Expect that the batch type is detected
expect(decodedPostCompressed.type).to.eq(BatchType.ZLIB)
// Expect that the contexts match
expect(decoded.contexts).to.deep.equal(decodedPostCompressed.contexts)
for (const [i, tx] of decoded.transactions.entries()) {
const got = decodedPostCompressed.transactions[i]
expect(got).to.deep.eq(tx)
}
// Reserialize the batch as legacy
decodedPostCompressed.type = BatchType.LEGACY
// Ensure that the original data can be recovered
const encoded = decodedPostCompressed.toHex()
expect(encoded).to.deep.equal(calldata)
})
it(`${hash}: serialize txs`, () => {
for (const tx of decoded.transactions) {
tx.toTransaction()
}
})
} }
}) })
......
This diff is collapsed.
{ {
"extends": "../../tsconfig.json" "extends": "../../tsconfig.json",
"typeRoots": ["node_modules/@types", "src/@types"]
} }
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