Comparing version
@@ -1,5 +0,5 @@ | ||
var Migrations = artifacts.require("./Migrations.sol"); | ||
var Migrations = artifacts.require('./Migrations.sol') | ||
module.exports = function(deployer) { | ||
deployer.deploy(Migrations); | ||
}; | ||
module.exports = function (deployer) { | ||
deployer.deploy(Migrations) | ||
} |
@@ -1,5 +0,5 @@ | ||
const PatriciaTree = artifacts.require("PatriciaTree"); | ||
const PatriciaTree = artifacts.require('PatriciaTree') | ||
module.exports = function(deployer) { | ||
deployer.deploy(PatriciaTree); | ||
}; | ||
module.exports = function (deployer) { | ||
deployer.deploy(PatriciaTree) | ||
} |
{ | ||
"name": "merklux", | ||
"version": "0.0.0", | ||
"description": "A merkleized unidirectional data flow for state verification across multiple chains", | ||
"version": "0.0.1", | ||
"description": "A state machine for child chain to manage the state transition with a merkleized unidirectional data flow", | ||
"directories": { | ||
@@ -11,12 +11,17 @@ "test": "test" | ||
"chai-bignumber": "^2.0.2", | ||
"ganache-cli": "^6.1.6", | ||
"openzeppelin-solidity": "^2.0.0-rc.2", | ||
"truffle": "^4.1.13", | ||
"ganache-cli": "^6.1.8", | ||
"solidity-coverage": "^0.5.11", | ||
"standard": "^12.0.1", | ||
"truffle": "^4.1.14", | ||
"truffle-hdwallet-provider": "^0.0.5" | ||
}, | ||
"dependencies": {}, | ||
"dependencies": { | ||
"openzeppelin-solidity": "^2.0.0-rc.2" | ||
}, | ||
"scripts": { | ||
"sequenceTest": "scripts/sequenceTest.sh", | ||
"coverage": "./node_modules/.bin/solidity-coverage", | ||
"build": "truffle compile", | ||
"migrate": "truffle migrate" | ||
"migrate": "truffle migrate", | ||
"test": "scripts/test.sh" | ||
}, | ||
@@ -23,0 +28,0 @@ "repository": { |
@@ -1,3 +0,19 @@ | ||
# merklux | ||
# Merklux | ||
[](https://gitter.im/commitground/merklux?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||
##### latest released version | ||
[](https://www.npmjs.com/package/merklux) | ||
[](https://travis-ci.org/commitground/merklux) | ||
[](https://coveralls.io/github/commitground/merklux?branch=develop) | ||
##### in progress | ||
[](https://www.npmjs.com/package/merklux) | ||
[](https://travis-ci.org/commitground/merklux) | ||
[](https://coveralls.io/github/commitground/merklux?branch=develop) | ||
[](https://github.com/standard/standard) | ||
## What is Merklux | ||
@@ -4,0 +20,0 @@ |
@@ -1,217 +0,215 @@ | ||
const chai = require('chai'); | ||
const assert = chai.assert; | ||
const BigNumber = web3.BigNumber; | ||
const should = chai.use(require('chai-bignumber')(BigNumber)).should(); | ||
const chai = require('chai') | ||
const assert = chai.assert | ||
const BigNumber = web3.BigNumber | ||
const should = chai.use(require('chai-bignumber')(BigNumber)).should() | ||
const MerkluxTree = artifacts.require('MerkluxTree'); | ||
const {toNodeObject, progress} = require('./utils'); | ||
const MerkluxTree = artifacts.require('MerkluxTree') | ||
const { toNodeObject, progress } = require('./utils') | ||
const ZERO = '0x0000000000000000000000000000000000000000000000000000000000000000'; | ||
const ZERO = '0x0000000000000000000000000000000000000000000000000000000000000000' | ||
contract('MerkluxTree', async ([_, primary, nonPrimary]) => { | ||
context('inherits the patricia tree smart contract', async () => { | ||
let tree; | ||
beforeEach('deploy MerkluxTree', async () => { | ||
tree = await MerkluxTree.new({from: primary}); | ||
}); | ||
describe('insert()', async () => { | ||
it('should not use gas more than 1 million', async () => { | ||
let itemCount = 10; | ||
let items = {}; | ||
for (let i = 0; i < itemCount; i++) { | ||
items[web3.sha3('key' + Math.random())] = web3.sha3('val' + Math.random()); | ||
} | ||
let count = 1; | ||
for (const key of Object.keys(items)) { | ||
await tree.insert(key, items[key], {from: primary}); | ||
let estimatedGasToAddNewValue = await tree.insert.estimateGas(web3.sha3('key' + Math.random()), web3.sha3('val' + Math.random()), {from: primary}); | ||
progress.log(`(${count++}/${itemCount}) Required gas for a transaction: ${estimatedGasToAddNewValue}`); | ||
assert.isTrue(estimatedGasToAddNewValue < 1000000); | ||
} | ||
progress.close(); | ||
}); | ||
it('should allow only primary address to put items', async () => { | ||
await tree.insert('foo', 'bar', {from: primary}); | ||
}); | ||
it('should allow overwriting', async () => { | ||
await tree.insert('foo', 'bar', {from: primary}); | ||
await tree.insert('foo', 'baz', {from: primary}); | ||
assert.equal(web3.toUtf8(await tree.get('foo')), 'baz'); | ||
}); | ||
it('should revert when a non-primary address tries to insert a new item', async () => { | ||
try { | ||
await tree.insert('foo', 'bar', {from: nonPrimary}); | ||
assert.fail('it should throw an error') | ||
} catch (e) { | ||
assert.ok('it is successfully reverted'); | ||
} | ||
}); | ||
}); | ||
context('inherits the patricia tree smart contract', async () => { | ||
let tree | ||
beforeEach('deploy MerkluxTree', async () => { | ||
tree = await MerkluxTree.new({ from: primary }) | ||
}) | ||
describe('insert()', async () => { | ||
it('should not use gas more than 1 million', async () => { | ||
let itemCount = 10 | ||
let items = {} | ||
for (let i = 0; i < itemCount; i++) { | ||
items[web3.sha3('key' + Math.random())] = web3.sha3('val' + Math.random()) | ||
} | ||
let count = 1 | ||
for (const key of Object.keys(items)) { | ||
await tree.insert(key, items[key], { from: primary }) | ||
let estimatedGasToAddNewValue = await tree.insert.estimateGas(web3.sha3('key' + Math.random()), web3.sha3('val' + Math.random()), { from: primary }) | ||
progress.log(`(${count++}/${itemCount}) Required gas for a transaction: ${estimatedGasToAddNewValue}`) | ||
assert.isTrue(estimatedGasToAddNewValue < 1000000) | ||
} | ||
progress.close() | ||
}) | ||
it('should allow only primary address to put items', async () => { | ||
await tree.insert('foo', 'bar', { from: primary }) | ||
}) | ||
it('should allow overwriting', async () => { | ||
await tree.insert('foo', 'bar', { from: primary }) | ||
await tree.insert('foo', 'baz', { from: primary }) | ||
assert.equal(web3.toUtf8(await tree.get('foo')), 'baz') | ||
}) | ||
it('should revert when a non-primary address tries to insert a new item', async () => { | ||
try { | ||
await tree.insert('foo', 'bar', { from: nonPrimary }) | ||
assert.fail('it should throw an error') | ||
} catch (e) { | ||
assert.ok('it is successfully reverted') | ||
} | ||
}) | ||
}) | ||
describe('getRootHash()', async () => { | ||
it('should return its root hash value as zero when nothing is stored', async () => { | ||
assert.equal(await tree.getRootHash(), ZERO) | ||
}); | ||
it('should update its root hash when every new items are put into', async () => { | ||
// insert an item | ||
await tree.insert('foo', 'bar', {from: primary}); | ||
let firstRootHash = await tree.getRootHash(); | ||
// insert an item again | ||
await tree.insert('baz', 'qux', {from: primary}); | ||
let secondRootHash = await tree.getRootHash(); | ||
assert.notEqual(firstRootHash, secondRootHash); | ||
// insert an item again | ||
await tree.insert('foo', 'baz', {from: primary}); | ||
let thirdRootHash = await tree.getRootHash(); | ||
assert.notEqual(secondRootHash, thirdRootHash); | ||
}); | ||
describe('getRootHash()', async () => { | ||
it('should return its root hash value as zero when nothing is stored', async () => { | ||
assert.equal(await tree.getRootHash(), ZERO) | ||
}) | ||
it('should update its root hash when every new items are put into', async () => { | ||
// insert an item | ||
await tree.insert('foo', 'bar', { from: primary }) | ||
let firstRootHash = await tree.getRootHash() | ||
// insert an item again | ||
await tree.insert('baz', 'qux', { from: primary }) | ||
let secondRootHash = await tree.getRootHash() | ||
assert.notEqual(firstRootHash, secondRootHash) | ||
// insert an item again | ||
await tree.insert('foo', 'baz', { from: primary }) | ||
let thirdRootHash = await tree.getRootHash() | ||
assert.notEqual(secondRootHash, thirdRootHash) | ||
}) | ||
it('should return same root hash for same write history', async () => { | ||
// define items to put | ||
let items = { | ||
key1: 'val1', | ||
key2: 'val2', | ||
key3: 'val3', | ||
}; | ||
it('should return same root hash for same write history', async () => { | ||
// define items to put | ||
let items = { | ||
key1: 'val1', | ||
key2: 'val2', | ||
key3: 'val3' | ||
} | ||
// insert items into the first tree | ||
for (const key of Object.keys(items)) { | ||
progress.log(`Insert items (${key}, ${items[key]})`); | ||
await tree.insert(key, items[key], {from: primary}); | ||
} | ||
progress.close(); | ||
// get root hash of the first tree | ||
let rootEdgeOfTree = await tree.getRootEdge(); | ||
let rootHashOfTree = rootEdgeOfTree[2]; | ||
// insert items into the first tree | ||
for (const key of Object.keys(items)) { | ||
progress.log(`Insert items (${key}, ${items[key]})`) | ||
await tree.insert(key, items[key], { from: primary }) | ||
} | ||
progress.close() | ||
// get root hash of the first tree | ||
let rootEdgeOfTree = await tree.getRootEdge() | ||
let rootHashOfTree = rootEdgeOfTree[2] | ||
// deploy a second tree | ||
let secondTree = await MerkluxTree.new({from: primary}); | ||
// insert same items into the second tree | ||
for (const key of Object.keys(items)) { | ||
await progress.log(`Insert items into the second tree (${key}, ${items[key]})`, 500); | ||
await secondTree.insert(key, items[key], {from: primary}); | ||
} | ||
progress.close(); | ||
// get root hash of the second tree | ||
let rootEdgeOfSecondTree = await secondTree.getRootEdge(); | ||
let rootHashOfSecondTree = rootEdgeOfSecondTree[2]; | ||
// deploy a second tree | ||
let secondTree = await MerkluxTree.new({ from: primary }) | ||
// insert same items into the second tree | ||
for (const key of Object.keys(items)) { | ||
await progress.log(`Insert items into the second tree (${key}, ${items[key]})`, 500) | ||
await secondTree.insert(key, items[key], { from: primary }) | ||
} | ||
progress.close() | ||
// get root hash of the second tree | ||
let rootEdgeOfSecondTree = await secondTree.getRootEdge() | ||
let rootHashOfSecondTree = rootEdgeOfSecondTree[2] | ||
// compare the two root hashes | ||
assert.equal(rootHashOfTree, rootHashOfSecondTree); | ||
}); | ||
}); | ||
// compare the two root hashes | ||
assert.equal(rootHashOfTree, rootHashOfSecondTree) | ||
}) | ||
}) | ||
describe('getNode()', async () => { | ||
it('should able to find all nodes', async () => { | ||
let items = { | ||
'key1': 'value1', | ||
'key2': 'value2', | ||
'key3': 'value3', | ||
'key4': 'value4', | ||
'key5': 'value5', | ||
}; | ||
describe('getNode()', async () => { | ||
it('should able to find all nodes', async () => { | ||
let items = { | ||
'key1': 'value1', | ||
'key2': 'value2', | ||
'key3': 'value3', | ||
'key4': 'value4', | ||
'key5': 'value5' | ||
} | ||
// insert items | ||
for (const key of Object.keys(items)) { | ||
await tree.insert(key, items[key], {from: primary}); | ||
} | ||
// insert items | ||
for (const key of Object.keys(items)) { | ||
await tree.insert(key, items[key], { from: primary }) | ||
} | ||
// find all nodes and check stored value hash | ||
let leafNodes = []; | ||
let nodeObjs = []; | ||
// find all nodes and check stored value hash | ||
let leafNodes = [] | ||
let nodeObjs = [] | ||
const getNodeRecursively = (depth, parent, hash) => new Promise(async res => { | ||
let result = await tree.getNode(hash); | ||
let nodes = [ | ||
[result[0], result[1], result[2]], | ||
[result[3], result[4], result[5]]]; | ||
for (let i = 0; i < nodes.length; i++) { | ||
let nodeObj = toNodeObject(depth, hash, nodes[i]); | ||
nodeObjs.push(nodeObj); | ||
let nodeHashValue = nodeObj.node; | ||
if (nodeHashValue == ZERO) { | ||
// Because an edge should always have two nodes, it duplicates a leaf node when only one exist. | ||
// Therefore, if there already exists a same node, do not push it into the leaf node array. | ||
let leafNode = { | ||
parent, | ||
hash | ||
}; | ||
let leafNodeAlreadyExist = leafNodes.reduce((val, item) => JSON.stringify(item) === JSON.stringify(leafNode), 0); | ||
if (!leafNodeAlreadyExist) { | ||
leafNodes.push(leafNode); | ||
await progress.log(`Found leaf node (${leafNode.hash})`, 500); | ||
} | ||
} else { | ||
await getNodeRecursively(depth + 1, hash, nodeHashValue); | ||
} | ||
} | ||
progress.close(); | ||
res(); | ||
}); | ||
const getNodeRecursively = (depth, parent, hash) => new Promise(async res => { | ||
let result = await tree.getNode(hash) | ||
let nodes = [ | ||
[result[0], result[1], result[2]], | ||
[result[3], result[4], result[5]]] | ||
for (let i = 0; i < nodes.length; i++) { | ||
let nodeObj = toNodeObject(depth, hash, nodes[i]) | ||
nodeObjs.push(nodeObj) | ||
let nodeHashValue = nodeObj.node | ||
if (nodeHashValue == ZERO) { | ||
// Because an edge should always have two nodes, it duplicates a leaf node when only one exist. | ||
// Therefore, if there already exists a same node, do not push it into the leaf node array. | ||
let leafNode = { | ||
parent, | ||
hash | ||
} | ||
let leafNodeAlreadyExist = leafNodes.reduce((val, item) => JSON.stringify(item) === JSON.stringify(leafNode), 0) | ||
if (!leafNodeAlreadyExist) { | ||
leafNodes.push(leafNode) | ||
} | ||
} else { | ||
await getNodeRecursively(depth + 1, hash, nodeHashValue) | ||
} | ||
} | ||
progress.close() | ||
res() | ||
}) | ||
// Get root hash to start to find nodes recursively | ||
let rootNode = toNodeObject(0, 'root', await tree.getRootEdge()); | ||
let rootHash = rootNode.node; | ||
// Find nodes recursively and add leaf nodes to the array | ||
await getNodeRecursively(1, 'root', rootHash); | ||
// Get root hash to start to find nodes recursively | ||
let rootNode = toNodeObject(0, 'root', await tree.getRootEdge()) | ||
let rootValue = rootNode.node | ||
// Find nodes recursively and add leaf nodes to the array | ||
await getNodeRecursively(1, 'root', rootValue) | ||
// Compare the found leaf nodes and initial items | ||
let hashValuesFromLeafNodes = leafNodes.map(leafNode => leafNode.hash); | ||
let hashValuesFromInitialItems = Object.values(items).map(item => web3.sha3(item)); | ||
assert.equal( | ||
JSON.stringify(hashValuesFromLeafNodes.sort()), | ||
JSON.stringify(hashValuesFromInitialItems.sort()) | ||
); | ||
// Compare the found leaf nodes and initial items | ||
let hashValuesFromLeafNodes = leafNodes.map(leafNode => leafNode.hash) | ||
let hashValuesFromInitialItems = Object.values(items).map(item => web3.sha3(item)) | ||
assert.equal( | ||
JSON.stringify(hashValuesFromLeafNodes.sort()), | ||
JSON.stringify(hashValuesFromInitialItems.sort()) | ||
) | ||
// if you want to see more in detail, you can print the leafNodes and nodeObj arrays. | ||
// console.log(nodeObjs); | ||
// console.log(leafNodes); | ||
}); | ||
}); | ||
// if you want to see more in detail, you can print the leafNodes and nodeObj arrays. | ||
// console.log(nodeObjs); | ||
// console.log(leafNodes); | ||
}) | ||
}) | ||
describe('getProof() & verifyProof()', async () => { | ||
it('should be able to verify merkle proof for a given key', async () => { | ||
let items = {key1: 'value1', key2: 'value2', key3: 'value3'}; | ||
for (const key of Object.keys(items)) { | ||
await tree.insert(key, items[key], {from: primary}) | ||
} | ||
let count = 0; | ||
for (const key of Object.keys(items)) { | ||
let [branchMask, siblings] = await tree.getProof(key); | ||
let rootHash = await tree.getRootHash(); | ||
await tree.verifyProof(rootHash, key, items[key], branchMask, siblings); | ||
progress.log(`(${count++}/${Object.keys(items).length}) Merkle proof for ${key}:${items[key]}`); | ||
assert.ok('is not reverted'); | ||
} | ||
progress.close(); | ||
}); | ||
describe('getProof() & verifyProof()', async () => { | ||
it('should be able to verify merkle proof for a given key', async () => { | ||
let items = { key1: 'value1', key2: 'value2', key3: 'value3' } | ||
for (const key of Object.keys(items)) { | ||
await tree.insert(key, items[key], { from: primary }) | ||
} | ||
let count = 0 | ||
for (const key of Object.keys(items)) { | ||
let [branchMask, siblings] = await tree.getProof(key) | ||
let rootHash = await tree.getRootHash() | ||
await tree.verifyProof(rootHash, key, items[key], branchMask, siblings) | ||
progress.log(`(${count++}/${Object.keys(items).length}) Merkle proof for ${key}:${items[key]}`) | ||
assert.ok('is not reverted') | ||
} | ||
progress.close() | ||
}) | ||
it('should throw an error for an invalid merkle proof', async () => { | ||
let items = {key1: 'value1', key2: 'value2', key3: 'value3'}; | ||
for (const key of Object.keys(items)) { | ||
await tree.insert(key, items[key], {from: primary}) | ||
} | ||
let count = 0; | ||
for (const key of Object.keys(items)) { | ||
let [branchMask, siblings] = await tree.getProof(key); | ||
let rootHash = await tree.getRootHash(); | ||
try { | ||
await tree.verifyProof(rootHash, key, `manipulate${items[key]}`, branchMask, siblings); | ||
} catch (e) { | ||
progress.log(`(${count++}/${Object.keys(items).length}) fraud proof for ${key}:${items[key]}`); | ||
assert.ok('reverted'); | ||
} | ||
} | ||
progress.close(); | ||
}); | ||
}); | ||
it('should throw an error for an invalid merkle proof', async () => { | ||
let items = { key1: 'value1', key2: 'value2', key3: 'value3' } | ||
for (const key of Object.keys(items)) { | ||
await tree.insert(key, items[key], { from: primary }) | ||
} | ||
let count = 0 | ||
for (const key of Object.keys(items)) { | ||
let [branchMask, siblings] = await tree.getProof(key) | ||
let rootHash = await tree.getRootHash() | ||
try { | ||
await tree.verifyProof(rootHash, key, `manipulate${items[key]}`, branchMask, siblings) | ||
} catch (e) { | ||
progress.log(`(${count++}/${Object.keys(items).length}) fraud proof for ${key}:${items[key]}`) | ||
assert.ok('reverted') | ||
} | ||
} | ||
progress.close() | ||
}) | ||
}) | ||
describe('get()', async () => { | ||
it('should return stored value for the given key', async () => { | ||
await tree.insert('foo', 'bar', {from: primary}); | ||
assert.equal(web3.toUtf8(await tree.get('foo')), 'bar'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('get()', async () => { | ||
it('should return stored value for the given key', async () => { | ||
await tree.insert('foo', 'bar', { from: primary }) | ||
assert.equal(web3.toUtf8(await tree.get('foo')), 'bar') | ||
}) | ||
}) | ||
}) | ||
}) |
const hexToString = hex => { | ||
const hexCodes = hex.startsWith("0x") ? hex.substr(2) : hex; | ||
let str = ''; | ||
let i; | ||
for (i = 0; (i < hexCodes.length && hexCodes.substr(i, 2) !== '00'); i += 2) | ||
str += String.fromCharCode(parseInt(hexCodes.substr(i, 2), 16)); | ||
return str; | ||
}; | ||
const hexCodes = hex.startsWith('0x') ? hex.substr(2) : hex | ||
let str = '' | ||
let i | ||
for (i = 0; (i < hexCodes.length && hexCodes.substr(i, 2) !== '00'); i += 2) { | ||
str += String.fromCharCode(parseInt(hexCodes.substr(i, 2), 16)) | ||
} | ||
return str | ||
} | ||
const toNodeObject = (depth, label, node) => { | ||
return { | ||
parent: label, | ||
depth, | ||
labelLength: node[0].toNumber(), | ||
labelData: node[1], | ||
node: node[2], | ||
}; | ||
}; | ||
return { | ||
parent: label, | ||
depth, | ||
labelLength: node[0].toNumber(), | ||
labelData: node[1], | ||
node: node[2] | ||
} | ||
} | ||
const logger4 = (on, ...args) => { | ||
if (on) { | ||
console.log(args); | ||
} | ||
}; | ||
const progress = { | ||
log: async (output, ms) => { | ||
process.stdout.clearLine(); | ||
process.stdout.cursorTo(0); | ||
process.stdout.write(`Progress >>\t${output}`); | ||
if (ms) { | ||
let sleep = () => new Promise(resolve => setTimeout(resolve, ms)); | ||
// await sleep(); | ||
} | ||
}, | ||
close: () => { | ||
process.stdout.clearLine(); | ||
process.stdout.cursorTo(0); | ||
process.stdout.write(''); | ||
log: async (output, ms) => { | ||
process.stdout.clearLine() | ||
process.stdout.cursorTo(0) | ||
process.stdout.write(`Progress >>\t${output}`) | ||
if (ms) { | ||
let sleep = () => new Promise(resolve => setTimeout(resolve, ms)) | ||
await sleep() | ||
} | ||
}; | ||
}, | ||
close: () => { | ||
process.stdout.clearLine() | ||
process.stdout.cursorTo(0) | ||
process.stdout.write('') | ||
} | ||
} | ||
module.exports = { | ||
hexToString, | ||
toNodeObject, | ||
progress | ||
}; | ||
hexToString, | ||
toNodeObject, | ||
progress | ||
} |
@@ -16,3 +16,3 @@ /* | ||
module.exports = { | ||
migrations_directory: "./migrations", | ||
migrations_directory: './migrations', | ||
// See <http://truffleframework.com/docs/advanced/configuration> | ||
@@ -22,25 +22,5 @@ // to customize your Truffle configuration! | ||
development: { | ||
host: "localhost", | ||
host: 'localhost', | ||
port: 8545, | ||
network_id: "*" | ||
}, | ||
devRoot: { | ||
host: "localhost", | ||
port: 8546, | ||
network_id: "*" | ||
}, | ||
devSide: { | ||
host: "localhost", | ||
port: 8547, | ||
network_id: "*" | ||
}, | ||
testRoot: { | ||
host: "localhost", | ||
port: 8548, | ||
network_id: "*" | ||
}, | ||
testSide: { | ||
host: "localhost", | ||
port: 8549, | ||
network_id: "*" | ||
network_id: '*' | ||
} | ||
@@ -53,3 +33,3 @@ }, | ||
} | ||
} | ||
}; | ||
} | ||
} |
@@ -16,3 +16,3 @@ /* | ||
module.exports = { | ||
migrations_directory: "./migrations", | ||
migrations_directory: './migrations', | ||
// See <http://truffleframework.com/docs/advanced/configuration> | ||
@@ -22,25 +22,5 @@ // to customize your Truffle configuration! | ||
development: { | ||
host: "localhost", | ||
host: 'localhost', | ||
port: 8545, | ||
network_id: "180902" | ||
}, | ||
devRoot: { | ||
host: "localhost", | ||
port: 8546, | ||
network_id: "180903" | ||
}, | ||
devSide: { | ||
host: "localhost", | ||
port: 8547, | ||
network_id: "180904" | ||
}, | ||
testRoot: { | ||
host: "localhost", | ||
port: 8548, | ||
network_id: "180905" | ||
}, | ||
testSide: { | ||
host: "localhost", | ||
port: 8549, | ||
network_id: "180906" | ||
network_id: '*' | ||
} | ||
@@ -53,3 +33,3 @@ }, | ||
} | ||
} | ||
}; | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
61020
37.15%24
14.29%544
55.43%32
100%1
Infinity%7
16.67%1
Infinity%+ Added