NormalOperation tests completed

This commit is contained in:
Jordi Baylina 2017-06-27 13:08:23 +02:00
parent feda565745
commit cec39ea18e
6 changed files with 354 additions and 41 deletions

View File

@ -142,7 +142,8 @@ contract LiquidPledging is LiquidPledgingBase {
if (n.paymentState != PaymentState.Paying) throw;
if (isProjectCanceled(n.owner)) throw;
// Check the project is not canceled in the while.
if (getOldestNoteNotCanceled(idNote) != idNote) throw;
uint64 idNewNote = findNote(
n.owner,
@ -178,9 +179,7 @@ contract LiquidPledging is LiquidPledgingBase {
function cancelProject(uint64 idProject) {
NoteManager project = findManager(idProject);
if ( (project.reviewer != msg.sender)
&&(project.addr != msg.sender))
throw;
require((project.reviewer == msg.sender) || (project.addr == msg.sender));
project.canceled = true;
}
@ -317,7 +316,7 @@ contract LiquidPledging is LiquidPledgingBase {
if (n.paymentState != PaymentState.NotPaid) return idNote;
// First send to a project if it's proposed and commited
if ((n.proposedProject > 0) && ( getTime() > n.commmitTime)) {
if ((n.proposedProject > 0) && ( getTime() > n.commitTime)) {
uint64 oldNote = findNote(
n.owner,
n.delegationChain,
@ -334,6 +333,7 @@ contract LiquidPledging is LiquidPledgingBase {
PaymentState.NotPaid);
doTransfer(idNote, toNote, n.amount);
idNote = toNote;
n = findNote(idNote);
}
toNote = getOldestNoteNotCanceled(idNote);
@ -343,7 +343,6 @@ contract LiquidPledging is LiquidPledgingBase {
return toNote;
}
/////////////
// Test functions
/////////////

View File

@ -21,7 +21,7 @@ contract LiquidPledgingBase {
uint64 owner;
uint64[] delegationChain;
uint64 proposedProject;
uint64 commmitTime; // At what time the upcoming time will become an owner.
uint64 commitTime; // At what time the upcoming time will become an owner.
uint64 oldNote;
PaymentState paymentState;
}
@ -164,7 +164,7 @@ contract LiquidPledgingBase {
uint64 owner,
uint64 nDelegates,
uint64 proposedProject,
uint64 commmitTime,
uint64 commitTime,
uint64 oldNote,
PaymentState paymentState
) {
@ -173,7 +173,7 @@ contract LiquidPledgingBase {
owner = n.owner;
nDelegates = uint64(n.delegationChain.length);
proposedProject = n.proposedProject;
commmitTime = n.commmitTime;
commitTime = n.commitTime;
oldNote = n.oldNote;
paymentState = n.paymentState;
}
@ -219,17 +219,17 @@ contract LiquidPledgingBase {
uint64 owner,
uint64[] delegationChain,
uint64 proposedProject,
uint64 commmitTime,
uint64 commitTime,
uint64 oldNote,
PaymentState paid
) internal returns (uint64)
{
bytes32 hNote = sha3(owner, delegationChain, proposedProject, commmitTime, oldNote, paid);
bytes32 hNote = sha3(owner, delegationChain, proposedProject, commitTime, oldNote, paid);
uint64 idx = hNote2ddx[hNote];
if (idx > 0) return idx;
idx = uint64(notes.length);
hNote2ddx[hNote] = idx;
notes.push(Note(0, owner, delegationChain, proposedProject, commmitTime, oldNote, paid));
notes.push(Note(0, owner, delegationChain, proposedProject, commitTime, oldNote, paid));
return idx;
}
@ -243,25 +243,23 @@ contract LiquidPledgingBase {
return notes[idNote];
}
function getOldestNoteNotCanceled(uint64 idProject) internal constant returns(uint64) {
if (idProject == 0) return 0;
Note n = findNote(idProject);
function getOldestNoteNotCanceled(uint64 idNote) internal constant returns(uint64) {
if (idNote == 0) return 0;
Note n = findNote(idNote);
NoteManager owner = findManager(n.owner);
if (owner.managerType == NoteManagerType.Donor) return idProject;
if (owner.managerType == NoteManagerType.Donor) return idNote;
uint64 parentProject = getOldestNoteNotCanceled(n.oldNote);
if (parentProject == n.oldNote) {
return idProject;
} else {
if (owner.canceled) { // Current project is canceled.
return parentProject;
} else if (parentProject == n.oldNote) { // None of the top projects is canceled
return idNote;
} else { // Current is not canceled but some ont the top yes
return parentProject;
}
}
function isProjectCanceled(uint64 idProject) internal constant returns(bool){
uint parentProject = getOldestNoteNotCanceled(idProject);
return (parentProject != idProject);
}
uint64 constant NOTFOUND = 0xFFFFFFFFFFFFFFFF;
function getDelegateIdx(Note n, uint64 idDelegate) internal returns(uint64) {
for (uint i=0; i<n.delegationChain.length; i++) {

140
package-lock.json generated
View File

@ -310,6 +310,12 @@
"integrity": "sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas=",
"dev": true
},
"aria-query": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-0.7.0.tgz",
"integrity": "sha512-/r2lHl09V3o74+2MLKEdewoj37YZqiQZnfen1O4iNlrOjUgeKuu1U2yF3iKh6HJxqF+OXkLMfQv65Z/cvxD6vA==",
"dev": true
},
"arr-diff": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
@ -358,6 +364,12 @@
"integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=",
"dev": true
},
"array-includes": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz",
"integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=",
"dev": true
},
"array-iterate": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-1.1.1.tgz",
@ -436,6 +448,12 @@
"integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=",
"dev": true
},
"ast-types-flow": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
"integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
"dev": true
},
"async": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz",
@ -472,6 +490,12 @@
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
"dev": true
},
"axobject-query": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-0.1.0.tgz",
"integrity": "sha1-YvWdvFnJ+SQnWco0mWDnov48NsA=",
"dev": true
},
"b64": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/b64/-/b64-3.0.2.tgz",
@ -1857,6 +1881,12 @@
"integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
"dev": true
},
"contains-path": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
"integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=",
"dev": true
},
"content": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/content/-/content-3.0.4.tgz",
@ -2170,6 +2200,12 @@
"integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
"dev": true
},
"damerau-levenshtein": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz",
"integrity": "sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ=",
"dev": true
},
"dargs": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz",
@ -3074,18 +3110,104 @@
}
}
},
"eslint-config-airbnb": {
"version": "15.0.1",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-15.0.1.tgz",
"integrity": "sha1-e1GI5bfHS5ss5jn9Xh2rqP12Gu0=",
"dev": true
},
"eslint-config-airbnb-base": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-11.2.0.tgz",
"integrity": "sha1-GancRIGib3CQRUXsBAEWh2AY+FM=",
"dev": true
},
"eslint-config-standard": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-6.2.1.tgz",
"integrity": "sha1-06aKr8cZFjnn7kQec0hzkCY1QpI=",
"dev": true
},
"eslint-import-resolver-node": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz",
"integrity": "sha1-Wt2BBujJKNssuiMrzZ76hG49oWw=",
"dev": true
},
"eslint-module-utils": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz",
"integrity": "sha512-jDI/X5l/6D1rRD/3T43q8Qgbls2nq5km5KSqiwlyUbGo5+04fXhMKdCPhjwbqAa6HXWaMxj8Q4hQDIh7IadJQw==",
"dev": true
},
"eslint-plugin-import": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.6.0.tgz",
"integrity": "sha512-JdkYDmMMjhxW6X/IVclD+vQXO6e2nJJT4cKcyTw95mvBCWkr8THXKFhc+WCvGvOscjGuLQzUB7tBeJddrg2jig==",
"dev": true,
"dependencies": {
"doctrine": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
"integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
"dev": true
},
"find-up": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
"integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
"dev": true
},
"load-json-file": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"dev": true
},
"path-type": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
"integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",
"dev": true
},
"read-pkg": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
"integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",
"dev": true
},
"read-pkg-up": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",
"integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=",
"dev": true
},
"strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
"dev": true
}
}
},
"eslint-plugin-jsx-a11y": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.0.0.tgz",
"integrity": "sha1-1c3Wj2ZaiVQKVd3A2JjK+AypSsU=",
"dev": true
},
"eslint-plugin-promise": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz",
"integrity": "sha1-ePu2/+BHIBYnVp6FpsU3OvKmj8o=",
"dev": true
},
"eslint-plugin-react": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.1.0.tgz",
"integrity": "sha1-J3cKzzn1/UnNCvQIPOWBBOs5DUw=",
"dev": true
},
"eslint-plugin-standard": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-2.3.1.tgz",
@ -7241,6 +7363,12 @@
}
}
},
"jsx-ast-utils": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz",
"integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=",
"dev": true
},
"karma": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/karma/-/karma-1.7.0.tgz",
@ -7820,6 +7948,12 @@
"integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=",
"dev": true
},
"lodash.cond": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz",
"integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=",
"dev": true
},
"lodash.create": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz",
@ -9288,6 +9422,12 @@
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
"dev": true
},
"pkg-dir": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz",
"integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=",
"dev": true
},
"plugin-error": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz",

View File

@ -30,6 +30,10 @@
"devDependencies": {
"async": "^2.4.0",
"bignumber.js": "^4.0.2",
"eslint-config-airbnb": "^15.0.1",
"eslint-plugin-import": "^2.6.0",
"eslint-plugin-jsx-a11y": "^6.0.0",
"eslint-plugin-react": "^7.1.0",
"ethereumjs-testrpc": "^3.0.5",
"random-bytes": "^1.0.0",
"truffle": "3.2.4",

View File

@ -1,14 +1,106 @@
const LiquidPledging = artifacts.require("LiquidPledgingMock");
const Vault = artifacts.require("Vault");
const assertFail = require("./helpers/assertFail");
const getNote = async (liquidPledging, idNote) => {
const note = {
delegates: [],
};
const res = await liquidPledging.getNote(idNote);
note.amount = res[0];
note.owner = res[1];
for (let i=1; i <= res[2].toNumber(); i += 1) {
const delegate = {};
const resd = await liquidPledging.getNoteDelegate(idNote, i);
delegate.id = resd[0].toNumber();
delegate.addr = resd[1];
delegate.name = resd[2];
note.delegates.push(delegate);
}
if (res[3].toNumber()) {
note.proposedProject = res[3].toNumber();
note.commmitTime = res[4].toNumber();
}
if (res[5].toNumber()) {
note.oldProject = res[5].toNumber();
}
if (res[6].toNumber() == 0) {
note.paymentState = "NotPaid";
} else if (res[6].toNumber() == 1) {
note.paymentState = "Paying";
} else if (res[6].toNumber() == 2) {
note.paymentState = "Paid";
} else {
note.paymentState = "Unknown";
}
return note;
};
const getManager = async (liquidPledging, idManager) => {
const manager = {};
const res = await liquidPledging.getNoteManager(idManager);
if (res[0].toNumber() == 0) {
manager.paymentState = "Donor";
} else if (res[0].toNumber() === 1) {
manager.paymentState = "Delegate";
} else if (res[0].toNumber() === 2) {
manager.paymentState = "Project";
} else {
manager.paymentState = "Unknown";
}
manager.addr = res[1];
manager.name = res[2];
manager.commitTime = res[3].toNumber();
if (manager.paymentState == "Project") {
manager.reviewer = res[4];
manager.canceled = res[5];
}
return manager;
};
const getState = async (liquidPledging) => {
const st = {
notes: [null],
managers: [null],
};
const nNotes = await liquidPledging.numberOfNotes();
for (let i=1; i <= nNotes; i += 1) {
const note = await getNote(liquidPledging, i);
st.notes.push(note);
}
const nManagers = await liquidPledging.numberOfNoteManagers();
for (let i=1; i <= nManagers; i += 1) {
const manager = await getManager(liquidPledging, i);
st.managers.push(manager);
}
return st;
};
const printState = async(liquidPledging) => {
const st = await getState(liquidPledging);
console.log(JSON.stringify(st, null, 2));
};
const printBalances = async(liquidPledging) => {
const st = await getState(liquidPledging);
assert.equal(st.notes.length, 13);
for (let i=1; i<=12; i++) {
console.log(i, web3.fromWei(st.notes[ i ].amount).toNumber() )
}
};
contract("LiquidPledging", (accounts) => {
let liquidPledging;
let vault;
let donor1 = accounts[0];
let delegate1 = accounts[1];
let adminProject1 = accounts[2];
let adminProject2 = accounts[3];
let reviewer = accounts[4];
let donor1 = accounts[1];
let delegate1 = accounts[2];
let adminProject1 = accounts[3];
let adminProject2 = accounts[4];
let adminProject2a = accounts[5];
let delegate2 = accounts[6];
let reviewer = accounts[7];
it("Should deploy LiquidPledgin contract", async () => {
vault = await Vault.new();
liquidPledging = await LiquidPledging.new(vault.address);
@ -40,7 +132,7 @@ contract("LiquidPledging", (accounts) => {
assert.equal(res[2], "Delegate1");
});
it("Donor should delegate on the delegate ", async () => {
await liquidPledging.transfer(1, 1, web3.toWei(0.5), 2);
await liquidPledging.transfer(1, 1, web3.toWei(0.5), 2, {from: donor1});
const nNotes = await liquidPledging.numberOfNotes();
assert.equal(nNotes.toNumber(), 2);
const res1 = await liquidPledging.getNote(1);
@ -151,34 +243,105 @@ contract("LiquidPledging", (accounts) => {
assert.equal(res7[4], 0); // commit time
assert.equal(res7[5].toNumber(), 2); // Old Node
assert.equal(res7[6].toNumber(), 2); // Peinding paid Paid
});
it("Reviewer should be able to cancel project1", async () => {
await liquidPledging.cancelProject(3, {from: reviewer});
const st = await getState(liquidPledging);
assert.equal(st.managers[3].canceled , true);
});
it("Should not allow to withdraw from a canceled project", async () => {
const st = await getState(liquidPledging);
assert.equal(web3.fromWei(st.notes[5].amount).toNumber(), 0.05);
await assertFail(async function() {
await liquidPledging.withdraw(5, web3.toWei(0.01), {from: adminProject1});
});
});
it("Delegate should send part of this ETH to project2", async () => {
await liquidPledging.transfer(2, 5, web3.toWei(0.03), 4, {from: delegate1});
const st = await getState(liquidPledging);
assert.equal(st.notes.length, 9);
assert.equal(web3.fromWei(st.notes[ 8 ].amount).toNumber(), 0.03);
assert.equal(st.notes[8].owner, 1);
assert.equal(st.notes[8].delegates.length, 1);
assert.equal(st.notes[8].delegates[0].id, 2);
assert.equal(st.notes[8].proposedProject, 4);
});
it("Owner should be able to send the remaining to project2", async () => {
it("Donor should be able to send the remaining to project2", async () => {
await liquidPledging.transfer(1, 5, web3.toWei(0.02), 4, {from: donor1});
const st = await getState(liquidPledging);
assert.equal(st.notes.length, 9);
assert.equal(web3.fromWei(st.notes[ 5 ].amount).toNumber(), 0);
assert.equal(web3.fromWei(st.notes[ 4 ].amount).toNumber(), 0.12);
});
it("A subproject 2a and a delegate2 is created", async () => {
await liquidPledging.addProject("Project2a", reviewer, 86400, {from: adminProject2a});
await liquidPledging.addDelegate("Delegate2", {from: delegate2});
const nManagers = await liquidPledging.numberOfNoteManagers();
assert.equal(nManagers, 6);
});
it("Project 2 delegate in delegate2", async () => {
await liquidPledging.transfer(4, 4, web3.toWei(0.02), 6, {from: adminProject2});
const st = await getState(liquidPledging);
assert.equal(st.notes.length, 10);
assert.equal(web3.fromWei(st.notes[ 9 ].amount).toNumber(), 0.02);
assert.equal(web3.fromWei(st.notes[ 4 ].amount).toNumber(), 0.1);
});
it("delegate2 assigns to projec2a", async () => {
await liquidPledging.transfer(6, 9, web3.toWei(0.01), 5, {from: delegate2});
const st = await getState(liquidPledging);
assert.equal(st.notes.length, 11);
assert.equal(web3.fromWei(st.notes[ 9 ].amount).toNumber(), 0.01);
assert.equal(web3.fromWei(st.notes[ 10 ].amount).toNumber(), 0.01);
});
it("project2a spends on a while", async () => {
it("project2a authorize to spend a little", async () => {
const n = Math.floor(new Date().getTime() / 1000);
await liquidPledging.setMockedTime(n + 86401*3);
await liquidPledging.withdraw(10, web3.toWei(0.005), {from: adminProject2a});
const st = await getState(liquidPledging);
assert.equal(st.notes.length, 13);
assert.equal(web3.fromWei(st.notes[ 10 ].amount).toNumber(), 0);
assert.equal(web3.fromWei(st.notes[ 11 ].amount).toNumber(), 0.005);
assert.equal(web3.fromWei(st.notes[ 12 ].amount).toNumber(), 0.005);
});
it("project2 is canceled", async () => {
await liquidPledging.cancelProject(4, {from: reviewer});
});
it("project2 should not be able to confirm payment", async () => {
await assertFail(async function() {
await vault.confirmPayment(1);
});
});
it("Should not be able to withdraw it", async() => {
await assertFail(async function() {
await liquidPledging.withdraw(12, web3.toWei(0.005), {from: donor1});
});
});
it("Should not be able to cancel payment", async() => {
await vault.cancelPayment(1);
const st = await getState(liquidPledging);
assert.equal(st.notes.length, 13);
assert.equal(web3.fromWei(st.notes[ 2 ].amount).toNumber(), 0.31);
assert.equal(web3.fromWei(st.notes[ 11 ].amount).toNumber(), 0);
assert.equal(web3.fromWei(st.notes[ 12 ].amount).toNumber(), 0);
});
it("original owner should recover the remaining funds", async () => {
const st = await getState(liquidPledging);
await liquidPledging.withdraw(1, web3.toWei(0.5), {from: donor1});
await liquidPledging.withdraw(2, web3.toWei(0.31), {from: donor1});
await liquidPledging.withdraw(4, web3.toWei(0.1), {from: donor1});
await liquidPledging.withdraw(8, web3.toWei(0.03), {from: donor1});
const test = await liquidPledging.test();
await liquidPledging.withdraw(9, web3.toWei(0.01), {from: donor1});
const initialBalance = await web3.eth.getBalance(donor1);
await vault.multiConfirm([2,3,4,5,6]);
const finalBalance = await web3.eth.getBalance(donor1);
const collected = web3.fromWei(finalBalance.sub(initialBalance)).toNumber();
assert.equal(collected, 0.95);
});
});

View File

@ -0,0 +1,9 @@
module.exports = async function(callback) {
let web3_error_thrown = false;
try {
await callback();
} catch (error) {
if (error.message.search("invalid opcode")) web3_error_thrown = true;
}
assert.ok(web3_error_thrown, "Transaction should fail");
};