change verify proofs to internal calls
MODIFY
src/helpers/proofs.js
src/helpers/proofs.js
@@ -3,51 +3,15 @@ import utils from "ethereumjs-util"
import EthereumTx from "ethereumjs-tx"
import EthereumBlock from "ethereumjs-block/from-rpc"
-const rlp = utils.rlp
-
-// raw header
-function getRawHeader(_block) {
- if (typeof _block.difficulty !== "string") {
- _block.difficulty = "0x" + _block.difficulty.toString(16)
- }
-
- const block = new EthereumBlock(_block)
- return block.header
-}
-
-// squanch transaction
-export function squanchTx(tx) {
- tx.gasPrice = "0x" + parseInt(tx.gasPrice).toString(16)
- tx.value = "0x" + parseInt(tx.value).toString(16) || "0"
- tx.gas = "0x" + parseInt(tx.gas).toString(16)
- tx.data = tx.input
- return tx
-}
-
-function nibblesToTraverse(encodedPartialPath, path, pathPtr) {
- let partialPath
- if (
- String(encodedPartialPath[0]) === "0" ||
- String(encodedPartialPath[0]) === "2"
- ) {
- partialPath = encodedPartialPath.slice(2)
- } else {
- partialPath = encodedPartialPath.slice(1)
- }
+import MerkleTree from "./merkle-tree"
- if (partialPath === path.slice(pathPtr, pathPtr + partialPath.length)) {
- return partialPath.length
- } else {
- throw new Error("path was wrong")
- }
-}
+const rlp = utils.rlp
export function getTxBytes(tx) {
const txObj = new EthereumTx(squanchTx(tx))
return txObj.serialize()
}
-// build
export async function getTxProof(tx, block) {
const txTrie = new Trie()
for (let i = 0; i < block.transactions.length; i++) {
@@ -91,69 +55,6 @@ export async function getTxProof(tx, block) {
})
}
-export function verifyTxProof(proof) {
- const path = proof.path.toString("hex")
- const value = proof.value
- const parentNodes = proof.parentNodes
- const txRoot = proof.root
- try {
- var currentNode
- var len = parentNodes.length
- var nodeKey = txRoot
- var pathPtr = 0
- for (var i = 0; i < len; i++) {
- currentNode = parentNodes[i]
- const encodedNode = Buffer.from(
- utils.sha3(rlp.encode(currentNode)),
- "hex"
- )
- if (!nodeKey.equals(encodedNode)) {
- return false
- }
- if (pathPtr > path.length) {
- return false
- }
- switch (currentNode.length) {
- case 17: // branch node
- if (pathPtr === path.length) {
- if (currentNode[16] === rlp.encode(value)) {
- return true
- } else {
- return false
- }
- }
- nodeKey = currentNode[parseInt(path[pathPtr], 16)] // must === sha3(rlp.encode(currentNode[path[pathptr]]))
- pathPtr += 1
- break
- case 2:
- pathPtr += nibblesToTraverse(
- currentNode[0].toString("hex"),
- path,
- pathPtr
- )
- if (pathPtr === path.length) {
- // leaf node
- if (currentNode[1].equals(rlp.encode(value))) {
- return true
- } else {
- return false
- }
- } else {
- // extension node
- nodeKey = currentNode[1]
- }
- break
- default:
- // all nodes must be length 17 or 2
- return false
- }
- }
- } catch (e) {
- return false
- }
- return false
-}
-
export function getReceiptBytes(receipt) {
let status = receipt.root
if (receipt.status !== undefined && receipt.status !== null) {
@@ -232,6 +133,125 @@ export async function getReceiptProof(receipt, block, web3) {
})
}
+export function verifyHeaderProof({ value, valueIndex, headerRoot, proof }) {
+ const bufferedValue = utils.toBuffer(value)
+ const tree = new MerkleTree([bufferedValue])
+ return tree.verify(
+ bufferedValue,
+ valueIndex,
+ utils.toBuffer(headerRoot),
+ proof.map(p => utils.toBuffer(p))
+ )
+}
+
+export function verifyTxProof(proof) {
+ const path = utils.toBuffer(proof.path).toString("hex")
+ const value = rlp.decode(utils.toBuffer(proof.value))
+ const parentNodes = rlp.decode(utils.toBuffer(proof.parentNodes))
+ const txRoot = utils.toBuffer(proof.root)
+
+ try {
+ var currentNode
+ var len = parentNodes.length
+ var nodeKey = txRoot
+ var pathPtr = 0
+ for (var i = 0; i < len; i++) {
+ currentNode = parentNodes[i]
+ const encodedNode = Buffer.from(
+ utils.sha3(rlp.encode(currentNode)),
+ "hex"
+ )
+ if (!nodeKey.equals(encodedNode)) {
+ return false
+ }
+
+ if (pathPtr > path.length) {
+ return false
+ }
+
+ switch (currentNode.length) {
+ case 17: // branch node
+ if (pathPtr === path.length) {
+ if (currentNode[16] === rlp.encode(value)) {
+ return true
+ } else {
+ return false
+ }
+ }
+ nodeKey = currentNode[parseInt(path[pathPtr], 16)] // must === sha3(rlp.encode(currentNode[path[pathptr]]))
+ pathPtr += 1
+ break
+ case 2:
+ pathPtr += nibblesToTraverse(
+ currentNode[0].toString("hex"),
+ path,
+ pathPtr
+ )
+ if (pathPtr === path.length) {
+ // leaf node
+ if (currentNode[1].equals(rlp.encode(value))) {
+ return true
+ } else {
+ return false
+ }
+ } else {
+ // extension node
+ nodeKey = currentNode[1]
+ }
+ break
+ default:
+ console.log("all nodes must be length 17 or 2")
+ return false
+ }
+ }
+ } catch (e) {
+ console.log(e)
+ return false
+ }
+ return false
+}
+
export function verifyReceiptProof(proof) {
return verifyTxProof(proof, true)
}
+
+//
+// Helper methods
+//
+
+// raw header
+function getRawHeader(_block) {
+ if (typeof _block.difficulty !== "string") {
+ _block.difficulty = "0x" + _block.difficulty.toString(16)
+ }
+
+ const block = new EthereumBlock(_block)
+ return block.header
+}
+
+// squanch transaction
+export function squanchTx(tx) {
+ tx.gasPrice = "0x" + parseInt(tx.gasPrice).toString(16)
+ tx.value = "0x" + parseInt(tx.value).toString(16) || "0"
+ tx.gas = "0x" + parseInt(tx.gas).toString(16)
+ tx.data = tx.input
+ return tx
+}
+
+function nibblesToTraverse(encodedPartialPath, path, pathPtr) {
+ let partialPath
+ if (
+ String(encodedPartialPath[0]) === "0" ||
+ String(encodedPartialPath[0]) === "2"
+ ) {
+ partialPath = encodedPartialPath.slice(2)
+ } else {
+ partialPath = encodedPartialPath.slice(1)
+ }
+
+ if (partialPath === path.slice(pathPtr, pathPtr + partialPath.length)) {
+ return partialPath.length
+ } else {
+ throw new Error("path was wrong")
+ }
+}

MODIFY
src/index.js
src/index.js
@@ -8,7 +8,10 @@ import {
getTxBytes,
getReceiptBytes,
getTxProof,
- getReceiptProof
+ getReceiptProof,
+ verifyTxProof,
+ verifyReceiptProof,
+ verifyHeaderProof
} from "./helpers/proofs"
import { getHeaders, getBlockHeader } from "./helpers/blocks"
import MerkleTree from "./helpers/merkle-tree"
@@ -179,13 +182,8 @@ export default class Matic {
return txProof
}
- async verifyTxProof(txId, txProof) {
- const isTxProofValid = await this._apiCall({
- url: `${this._syncerUrl}/tx/${txId}/verify-proof`,
- body: txProof
- })
-
- return isTxProofValid
+ verifyTxProof(txProof) {
+ return verifyTxProof(txProof)
}
async getReceiptProof(txId) {
@@ -196,13 +194,8 @@ export default class Matic {
return receiptProof
}
- async verifyReceiptProof(txId, receiptProof) {
- const isReceiptProof = await this._apiCall({
- url: `${this._syncerUrl}/tx/${txId}/receipt/verify-proof`,
- body: receiptProof
- })
-
- return isReceiptProof
+ verifyReceiptProof(receiptProof) {
+ return verifyReceiptProof(receiptProof)
}
getHeaderObject(blockNumber) {
@@ -223,13 +216,8 @@ export default class Matic {
return headerProof
}
- async verifyHeaderProof(blockNumber, headerProof) {
- const isHeaderProofValid = await this._apiCall({
- url: `${this._syncerUrl}/block/${blockNumber}/verify-proof`,
- body: headerProof
- })
-
- return isHeaderProofValid
+ verifyHeaderProof(headerProof) {
+ return verifyHeaderProof(headerProof)
}
async withdraw(txId, options = {}) {
@@ -242,6 +230,7 @@ export default class Matic {
// fetch header object & header proof
const header = await this.getHeaderObject(txProof.blockNumber)
const headerProof = await this.getHeaderProof(txProof.blockNumber, header)
+
const withdrawTx = this._rootChainContract.methods.withdraw(
header.number.toString(), // header block
utils.bufferToHex(
@@ -379,7 +368,7 @@ export default class Matic {
return {
from,
gasLimit,
- gasPrice,
+ gasPrice: gasPrice,
nonce,
chainId,
value: options.value || 0

change verify proofs to internal calls