Skip to content
This repository was archived by the owner on Jan 19, 2021. It is now read-only.

Commit cb63d56

Browse files
committed
Add flat encoding for instructions
1 parent 1f2ffea commit cb63d56

File tree

2 files changed

+90
-19
lines changed

2 files changed

+90
-19
lines changed

src/multiproof.ts

+57-7
Original file line numberDiff line numberDiff line change
@@ -306,15 +306,65 @@ export function decodeMultiproof(raw: Buffer): Multiproof {
306306
}
307307
}
308308

309-
export function encodeMultiproof(proof: Multiproof): Buffer {
310-
return encode(rawMultiproof(proof))
309+
export function encodeMultiproof(proof: Multiproof, flatInstructions: boolean = false): Buffer {
310+
return encode(rawMultiproof(proof, flatInstructions))
311311
}
312312

313-
export function rawMultiproof(proof: Multiproof): any {
314-
return [proof.hashes, proof.keyvals, proof.instructions.map(i => {
315-
if (i.value !== undefined) return [i.kind, i.value]
316-
return [i.kind]
317-
})]
313+
export function rawMultiproof(proof: Multiproof, flatInstructions: boolean = false): any {
314+
if (flatInstructions) {
315+
return [proof.hashes, proof.keyvals, flatEncodeInstructions(proof.instructions)]
316+
} else {
317+
return [proof.hashes, proof.keyvals, proof.instructions.map(i => {
318+
if (i.value !== undefined) return [i.kind, i.value]
319+
return [i.kind]
320+
})]
321+
}
322+
}
323+
324+
export function flatEncodeInstructions(instructions: Instruction[]): Buffer {
325+
const res: number[] = []
326+
for (const instr of instructions) {
327+
res.push(instr.kind)
328+
if (instr.kind === Opcode.Branch || instr.kind === Opcode.Add) {
329+
res.push(instr.value as number)
330+
} else if (instr.kind === Opcode.Extension) {
331+
const nibbles = instr.value as number[]
332+
res.push(nibbles.length)
333+
res.push(...nibbles)
334+
}
335+
}
336+
return Buffer.from(new Uint8Array(res))
337+
}
338+
339+
export function flatDecodeInstructions(raw: Buffer): Instruction[] {
340+
const res = []
341+
let i = 0
342+
while (i < raw.length) {
343+
const op = raw[i++]
344+
switch (op) {
345+
case Opcode.Branch:
346+
res.push({ kind: Opcode.Branch, value: raw[i++] })
347+
break
348+
case Opcode.Hasher:
349+
res.push({ kind: Opcode.Hasher })
350+
break
351+
case Opcode.Leaf:
352+
res.push({ kind: Opcode.Leaf })
353+
break
354+
case Opcode.Extension:
355+
const length = raw.readUInt8(i++)
356+
const nibbles = []
357+
for (let j = 0; j < length; j++) {
358+
nibbles.push(raw[i++])
359+
}
360+
res.push({ kind: Opcode.Extension, value: nibbles })
361+
break
362+
case Opcode.Add:
363+
res.push({ kind: Opcode.Add, value: raw[i++] })
364+
break
365+
}
366+
}
367+
return res
318368
}
319369

320370
export function decodeInstructions(instructions: Buffer[][]) {

test/multiproof.js

+33-12
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,44 @@ const tape = require('tape')
22
const promisify = require('util.promisify')
33
const rlp = require('rlp')
44
const { keccak256 } = require('ethereumjs-util')
5-
const { decodeMultiproof, rawMultiproof, encodeMultiproof, decodeInstructions, verifyMultiproof, makeMultiproof, Instruction, Opcode } = require('../dist/multiproof')
65
const { Trie } = require('../dist/baseTrie')
76
const { SecureTrie } = require('../dist/secure')
87
const { LeafNode } = require('../dist/trieNode')
98
const { stringToNibbles } = require('../dist/util/nibbles')
9+
const {
10+
decodeMultiproof, rawMultiproof, encodeMultiproof,
11+
decodeInstructions, flatEncodeInstructions, flatDecodeInstructions,
12+
verifyMultiproof, makeMultiproof, Instruction, Opcode
13+
} = require('../dist/multiproof')
1014

11-
tape('decode instructions', (t) => {
12-
const raw = Buffer.from('d0c20201c20405c603c403030303c28006', 'hex')
13-
const expected = [
14-
{ kind: Opcode.Leaf },
15-
{ kind: Opcode.Add, value: 5 },
16-
{ kind: Opcode.Extension, value: [3, 3, 3, 3] },
17-
{ kind: Opcode.Branch, value: 6 }
18-
]
19-
const res = decodeInstructions(rlp.decode(raw))
20-
t.deepEqual(expected, res)
21-
t.end()
15+
tape('decode and encode instructions', (t) => {
16+
t.test('rlp encoding', (st) => {
17+
const raw = Buffer.from('d0c20201c20405c603c403030303c28006', 'hex')
18+
const expected = [
19+
{ kind: Opcode.Leaf },
20+
{ kind: Opcode.Add, value: 5 },
21+
{ kind: Opcode.Extension, value: [3, 3, 3, 3] },
22+
{ kind: Opcode.Branch, value: 6 }
23+
]
24+
const res = decodeInstructions(rlp.decode(raw))
25+
st.deepEqual(expected, res)
26+
st.end()
27+
})
28+
29+
t.test('flat encoding', (st) => {
30+
const raw = Buffer.from('0204050304030303030006', 'hex')
31+
const instructions = [
32+
{ kind: Opcode.Leaf },
33+
{ kind: Opcode.Add, value: 5 },
34+
{ kind: Opcode.Extension, value: [3, 3, 3, 3] },
35+
{ kind: Opcode.Branch, value: 6 }
36+
]
37+
const encoded = flatEncodeInstructions(instructions)
38+
st.assert(raw.equals(encoded))
39+
const decoded = flatDecodeInstructions(raw)
40+
st.deepEqual(instructions, decoded)
41+
st.end()
42+
})
2243
})
2344

2445
tape('decode and encode multiproof', (t) => {

0 commit comments

Comments
 (0)