Update example

This commit is contained in:
Miguel Mota 2021-07-03 23:14:20 -07:00
parent 322a00f9de
commit 39fd0d9e1d
No known key found for this signature in database
GPG Key ID: 67EC1161588A00F9
3 changed files with 334 additions and 108 deletions

View File

@ -8,12 +8,21 @@
body {
padding-bottom: 4rem;
}
form {
display: block;
border: 1px dashed black;
padding: 0.2rem;
margin-bottom: 2rem;
}
label {
display: inline-block;
}
textarea {
width: 100%;
}
input[type="text"] {
width: 100%;
}
#output {
margin-top: 2rem;
}
@ -21,73 +30,112 @@
</head>
<body>
<h1>MerleTree.js example</h1>
<form id="form">
<div>
<label>Leaves <small>(input json array or newline separated)</small></label>
<textarea id="input" rows="10">
<div>
<form id="form">
<div>
<label>Leaves <small>(input json array or newline separated)</small></label>
<textarea id="input" rows="10">
0xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb
0x3e23e8160039594a33894f6564e1b1348bbd7a0088d42c4acb73eeaed59c009d
0x2e7d2c03a9507ae265ecf5b5356885a53393a2029d241394997265a1a25aefc6
</textarea>
</div>
<div>
<label>Hash function</label>
<div>
<input type="radio" name="hash" value="sha256" id="sha256" checked>
<label for="sha256">SHA-256</label>
<input type="radio" name="hash" value="keccak256" id="keccak256">
<label for="keccak256">Keccak-256</label>
<div>
</div>
<div>
<label>Options</label>
<div>
<input type="checkbox" name="option" value="hashLeaves" id="hashLeaves">
<label for="hashLeaves">hashLeaves</label>
<input type="checkbox" name="option" value="sortLeaves" id="sortLeaves">
<label for="sortLeaves">sortLeaves</label>
<input type="checkbox" name="option" value="sortPairs" id="sortPairs">
<label for="sortPairs">sortPairs</label>
<input type="checkbox" name="option" value="duplicateOdd" id="duplicateOdd">
<label for="duplicateOdd">duplicateOdd</label>
<input type="checkbox" name="option" value="isBitcoinTree" id="isBitcoinTree">
<label for="isBitcoinTree">isBitcoinTree</label>
<input type="checkbox" name="option" value="fillDefaultHash" id="fillDefaultHash">
<label for="fillDefaultHash">fillDefaultHash</label>
</textarea>
</div>
</div>
<div id="fillDefaultHashView" style="display:none">
<label>Fill default hash</label>
<small>
<a href='#' id="addressZero">addressZero</a>
<a href='#' id="hashAddressZero">hash(addressZero)</a>
</small>
<textarea id="fillDefaultHashValue" rows="1"></textarea>
</div>
<div>
<div>
<button type="submit" id="submit">Compute</button>
</div>
<div>
<label>Hash function</label>
<div>
<input type="radio" name="hash" value="sha256" id="sha256" checked>
<label for="sha256">SHA-256</label>
<input type="radio" name="hash" value="keccak256" id="keccak256">
<label for="keccak256">Keccak-256</label>
</div>
</div>
<div>
<label>Options</label>
<div>
<input type="checkbox" name="option" value="hashLeaves" id="hashLeaves">
<label for="hashLeaves">hashLeaves</label>
<input type="checkbox" name="option" value="sortLeaves" id="sortLeaves">
<label for="sortLeaves">sortLeaves</label>
<input type="checkbox" name="option" value="sortPairs" id="sortPairs">
<label for="sortPairs">sortPairs</label>
<input type="checkbox" name="option" value="duplicateOdd" id="duplicateOdd">
<label for="duplicateOdd">duplicateOdd</label>
<input type="checkbox" name="option" value="isBitcoinTree" id="isBitcoinTree">
<label for="isBitcoinTree">isBitcoinTree</label>
<input type="checkbox" name="option" value="fillDefaultHash" id="fillDefaultHash">
<label for="fillDefaultHash">fillDefaultHash</label>
</div>
</div>
<div id="fillDefaultHashView" style="display:none">
<label>Fill default hash</label>
<small>
<a href='#' id="addressZero">addressZero</a>
<a href='#' id="hashAddressZero">hash(addressZero)</a>
</small>
<input type="text" id="fillDefaultHashValue" />
</div>
<div>
<button type="submit">Compute</button>
</div>
</form>
</div>
<div>
<form id="verifyForm">
<label>Proof</label>
<div>
<textarea id="verifyProof" rows="3"></textarea>
</div>
<label>Leaf</label>
<div>
<input type="text" id="verifyLeaf" />
</div>
<label>Root</label>
<div>
<input type="text" id="verifyRoot" />
</div>
<div>
<button type="submit">Verify</button>
</div>
<label>Verified</label>
<div>
<pre id="verified"></pre>
</div>
</form>
</div>
<div>
<form id="proofForm">
<div>
<label>Proof</label>
<div>
<select id="leaveSelect"></select>
</div>
</div>
<div>
<pre id="proof"></pre>
</div>
</form>
</div>
<div id="output">
<label>Root</label>
<textarea id="root" rows="1"></textarea>
</div>
<div>
<label>Leaves</label>
<textarea id="leaves" rows="10"></textarea>
</div>
<div>
<label>Layers</label>
<textarea id="layers" rows="10"></textarea>
</div>
<div>
<label>Flat Layers</label>
<textarea id="flatLayers" rows="10"></textarea>
</div>
<div>
<label>Tree</label>
<pre id="tree"></pre>
<div>
<label>Root</label>
<pre id="root"></pre>
</div>
<div>
<label>Leaves</label>
<pre id="leaves"></pre>
</div>
<div>
<label>Layers</label>
<pre id="layers"></pre>
</div>
<div>
<label>Flat Layers</label>
<pre id="flatLayers"></pre>
</div>
<div>
<label>Tree</label>
<pre id="tree"></pre>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/keccak256@latest/keccak256.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-sha256/0.9.0/sha256.min.js"></script>

View File

@ -1,5 +1,7 @@
// elements
var $form = document.getElementById('form')
var $input = document.getElementById('input')
var $options = document.querySelectorAll('input[name="option"]')
var $fillDefaultHashView = document.getElementById('fillDefaultHashView')
var $fillDefaultHash = document.getElementById('fillDefaultHashValue')
var $addressZero = document.getElementById('addressZero')
@ -9,6 +11,15 @@ var $leaves = document.getElementById('leaves')
var $layers = document.getElementById('layers')
var $flatLayers = document.getElementById('flatLayers')
var $tree = document.getElementById('tree')
var $leaveSelect = document.getElementById('leaveSelect')
var $proof = document.getElementById('proof')
var $verifyForm = document.getElementById('verifyForm')
var $verifyProof = document.getElementById('verifyProof')
var $verifyLeaf = document.getElementById('verifyLeaf')
var $verifyRoot = document.getElementById('verifyRoot')
var $verified = document.getElementById('verified')
// variables
const addressZero = '0x0000000000000000000000000000000000000000000000000000000000000000'
var hashFns = {
@ -16,16 +27,6 @@ var hashFns = {
keccak256: window.keccak256
}
function parseInput (value) {
value = $input.value.trim()
value = value.replace(/'/gi, '"')
try {
return JSON.parse(value)
} catch (err) {
return value.split('\n').filter(function (x) { return x })
}
}
var options = {
hashLeaves: false,
sortLeaves: false,
@ -34,18 +35,22 @@ var options = {
isBitcoinTree: false
}
var tree
// functions
function compute () {
const value = getInputValue()
const leaves = parseInput(value)
const hash = getHashFn()
const fillDefaultHash = getDefaultFillHashValue()
const fillDefaultHash = getDefaultFillHashInput()
const _options = Object.assign({}, options, {
fillDefaultHash: options.fillDefaultHash ? fillDefaultHash : undefined
})
console.log('input leaves:', leaves)
console.log('hash:', getHashType())
console.log('options:', _options)
const tree = new window.MerkleTree(leaves, hash, _options)
tree = new window.MerkleTree(leaves, hash, _options)
const hexRoot = tree.getHexRoot()
const hexLeaves = tree.getHexLeaves()
const hexLayers = tree.getHexLayers()
@ -59,13 +64,97 @@ function compute () {
setLayersValue(JSON.stringify(hexLayers, null, 2))
setFlatLayersValue(JSON.stringify(hexFlatLayers, null, 2))
setTreeValue(tree.toString())
updateLeaveOptions(hexLeaves)
updateProof(0)
setVerified('')
}
function parseInput (value) {
value = value.trim().replace(/'/gi, '"')
try {
return JSON.parse(value)
} catch (err) {
return value.split('\n')
.map(function (line) { return line.trim() })
.filter(function (line) { return line })
}
}
function updateLeaveOptions (leaves) {
$leaveSelect.innerHTML = ''
leaves.forEach(function (leaf, i) {
const el = document.createElement('option')
el.value = `${i}`
el.text = `#${i} - ${leaf}`
$leaveSelect.appendChild(el)
})
}
function updateProof (index) {
setProof('')
if (!tree) {
return
}
const leaves = tree.getHexLeaves()
if (!leaves.length) {
return
}
const leaf = leaves[index]
const proof = tree.getHexProof(leaf)
console.log('proof:', proof)
setProof(JSON.stringify(proof, null, 2))
}
function setVerified (verified) {
$verified.textContent = verified
}
function verify () {
setVerified('')
if (!tree) {
return
}
const proof = getVerifyProof()
const leaf = getVerifyLeaf()
const root = getVerifyRoot()
const verified = tree.verify(proof, leaf, root)
setVerified(`${verified}`)
}
// getters
function getHashType () {
const $hash = document.querySelector('input[name="hash"]:checked')
return $hash.value
return $hash.value.trim()
}
function getHashFn () {
const key = getHashType()
return hashFns[key]
}
function getDefaultFillHashInput () {
return $fillDefaultHash.value.trim()
}
function getInputValue (value) {
return $input.value.trim()
}
function getVerifyProof () {
return parseInput($verifyProof.value.trim())
}
function getVerifyLeaf () {
return $verifyLeaf.value.trim()
}
function getVerifyRoot () {
return $verifyRoot.value.trim()
}
// setters
function setHashType (value) {
if (!value) {
return
@ -77,21 +166,10 @@ function setHashType (value) {
$hash.checked = true
}
function getHashFn () {
const key = getHashType()
return hashFns[key]
}
function getDefaultFillHashValue () {
return $fillDefaultHash.value
}
function getInputValue (value) {
return $input.value
}
function setInputValue (value) {
$input.value = value
function setInputValue (value, onlySave) {
if (!onlySave) {
$input.value = value
}
try {
localStorage.setItem('input', value)
} catch (err) {
@ -100,19 +178,19 @@ function setInputValue (value) {
}
function setRootValue (value) {
$root.value = value
$root.textContent = value
}
function setLeavesValue (value) {
$leaves.value = value
$leaves.textContent = value
}
function setLayersValue (value) {
$layers.value = value
$layers.textContent = value
}
function setFlatLayersValue (value) {
$flatLayers.value = value
$flatLayers.textContent = value
}
function setTreeValue (value) {
@ -127,8 +205,14 @@ function setHashValue (value) {
}
}
function setOptionValue (key, enabled) {
function setOptionValue (key, enabled, onlySave) {
try {
if (!onlySave) {
var $option = document.querySelector(`input[name="option"][id="${key}"]`)
if ($option) {
$option.checked = enabled
}
}
options[key] = enabled
localStorage.setItem('options', JSON.stringify(options))
toggleFillDefaultHashView()
@ -137,11 +221,10 @@ function setOptionValue (key, enabled) {
}
}
function setFillDefaultHash (value) {
$fillDefaultHash.value = value
}
function setDefaultFillHashValue (value) {
function setFillDefaultHash (value, onlySave) {
if (!onlySave) {
$fillDefaultHash.value = value
}
try {
localStorage.setItem('fillDefaultHash', value)
} catch (err) {
@ -149,6 +232,43 @@ function setDefaultFillHashValue (value) {
}
}
function setProof (value) {
$proof.textContent = value
}
function setVerifyProof (value, onlySave) {
if (!onlySave) {
$verifyProof.value = value
}
try {
localStorage.setItem('verifyProof', value)
} catch (err) {
console.error(err)
}
}
function setVerifyLeaf (value, onlySave) {
if (!onlySave) {
$verifyLeaf.value = value
}
try {
localStorage.setItem('verifyLeaf', value)
} catch (err) {
console.error(err)
}
}
function setVerifyRoot (value, onlySave) {
if (!onlySave) {
$verifyRoot.value = value
}
try {
localStorage.setItem('verifyRoot', value)
} catch (err) {
console.error(err)
}
}
function toggleFillDefaultHashView () {
if (options.fillDefaultHash) {
$fillDefaultHashView.style.display = 'block'
@ -157,35 +277,41 @@ function toggleFillDefaultHashView () {
}
}
// event listeners
$form.addEventListener('submit', function (event) {
event.preventDefault()
compute()
})
$verifyForm.addEventListener('submit', function (event) {
event.preventDefault()
verify()
})
$input.addEventListener('input', function (event) {
const value = event.target.value
setInputValue(value)
const value = event.target.value.trim()
setInputValue(value, true)
})
var $hashes = document.querySelectorAll('input[name="hash"]')
$hashes.forEach(function ($hash) {
$hash.addEventListener('change', function (event) {
const value = event.target.value
const value = event.target.value.trim()
setHashValue(value)
})
})
var $options = document.querySelectorAll('input[name="option"]')
$options.forEach(function ($option) {
$option.addEventListener('change', function (event) {
const value = event.target.value
const value = event.target.value.trim()
const checked = event.target.checked
setOptionValue(value, checked)
setOptionValue(value, checked, true)
})
})
$fillDefaultHash.addEventListener('input', function (event) {
const value = event.target.value
const value = event.target.value.trim()
setFillDefaultHash(value)
})
@ -200,6 +326,27 @@ $hashAddressZero.addEventListener('click', function (event) {
setFillDefaultHash(result)
})
$leaveSelect.addEventListener('change', function (event) {
updateProof(Number(event.target.value.trim()))
})
$verifyProof.addEventListener('input', function (event) {
const value = event.target.value.trim()
setVerifyProof(value, true)
})
$verifyLeaf.addEventListener('input', function (event) {
const value = event.target.value.trim()
setVerifyLeaf(value, true)
})
$verifyRoot.addEventListener('input', function (event) {
const value = event.target.value.trim()
setVerifyRoot(value, true)
})
// init
function load () {
try {
const value = localStorage.getItem('input')
@ -221,6 +368,9 @@ function load () {
const value = JSON.parse(localStorage.getItem('options'))
if (value) {
options = value
for (const option in options) {
setOptionValue(option, options[option])
}
}
} catch (err) {
console.error(err)
@ -228,14 +378,41 @@ function load () {
try {
const value = localStorage.getItem('fillDefaultHash')
if (value) {
setDefaultFillHashValue(value)
setFillDefaultHash(value)
}
} catch (err) {
console.error(err)
}
try {
const value = localStorage.getItem('verifyProof')
if (value) {
setVerifyProof(value)
}
} catch (err) {
console.error(err)
}
try {
const value = localStorage.getItem('verifyLeaf')
if (value) {
setVerifyLeaf(value)
}
} catch (err) {
console.error(err)
}
try {
const value = localStorage.getItem('verifyRoot')
if (value) {
setVerifyRoot(value)
}
} catch (err) {
console.error(err)
}
}
function main () {
load()
toggleFillDefaultHashView()
compute()
}
load()
main()

View File

@ -14,6 +14,7 @@
"build": "npm run clean && tsc && npm run build:browser",
"build:browser": "browserify -t [ babelify --presets [ @babel/preset-env ] ] dist/index.js | uglifyjs > merkletree.js",
"lint": "standardx --fix src/*.ts test/*.js",
"lint:example": "standardx --fix example/*.js",
"docs": "rimraf docs/ && typedoc --plugin typedoc-plugin-markdown --hideSources --theme markdown --hideGenerator --excludeExternals --excludePrivate --out docs index.ts",
"prepare": "npm run lint && npm run build"
},