Skip to content

Instantly share code, notes, and snippets.

@barkthins
Last active March 2, 2016 06:24
Show Gist options
  • Save barkthins/c2e527af82056542cd7d to your computer and use it in GitHub Desktop.
Save barkthins/c2e527af82056542cd7d to your computer and use it in GitHub Desktop.
#!/usr/bin/env node
var Promise = require('bluebird');
var fs = require('fs');
var test = require('blue-tape');
require('../web3E.js');
var Web3 = require('web3');
var web3 = new Web3();
var solc = require('solc');
// we shouldn't have to do this after web3E has done it, but can't
// get that working properly...
Promise.promisifyAll(web3.eth);
test("What happens when a contract sends ether it does not have", function(tid) {
web3.setupDefault();
var myContract;
var source = fs.readFileSync("tape/send.sol", 'utf8');
var compiled = solc.compile(source,1);
var code = compiled.contracts.sendit.bytecode;
var abi = JSON.parse(compiled.contracts.sendit.interface);
web3.eth.deployContract(code, abi)
.then(function(contract) {
myContract = contract;
Promise.promisifyAll(myContract);
Promise.promisifyAll(myContract.incrData);
// the contract sends ether it doesn't have. This results in
// the send failing but other side effects still happen.
// i.e. no throw in solidity. Note the contract takes the 5000 Wei that was sent,
// meaning this function would send ether every other time.
sent = 5000;
// this is not a good place to specify gas. Should be on the ABI function, not sprinkled into code.
return myContract.incrData.sendTransactionAsync({value:sent, gas:600000})
}).then(function(result) {
// timeout should never be in application code, it's deployment and ABI function dependent.
// XXX if we run out of gas the tests below may be invalid and give false positive or false negative
return web3.eth.awaitConsensus(result).timeout(30000,"ethereum didn't mine it")
}).then(function() {
// XXX what happens if this times out because of node problem? Should throw from library
return myContract.dataAsync()
}).then(function(res) {
tid.equal(res.toString(10), '1', "Side effect of incrementing occured");
return myContract.resultAsync()
}).then(function(res) {
tid.equal(res, false, "Got a failure to send the ether");
return myContract.sendersBalanceAsync()
}).then(function(res) {
return web3.eth.getBalanceAsync(myContract.address)
}).then(function(bal) {
tid.equal(bal.toNumber(), sent, "Ether balance is what we sent in the incrData call");
tid.end();
});
});
@barkthins
Copy link
Author

here's the solidity contract I'm testing:

contract sendit {
    uint256 public data;
    bool public result;
    uint256 public sendersBalance;

    function test() {
    }

    // if you send 5000 Wei to this function it will
    // successfully send ether every other transaction
    function incrData() {
        data += 1;
        // this should fail if this contract doesn't have enough ether
        // however there's no throw.  data is still incremented,
        // and ether is still added to this contract instance's balance
        // if it was sent in this transaction
        result = msg.sender.send(10000);
        sendersBalance = msg.sender.balance;
    }
}

@barkthins
Copy link
Author

BTW this is the type of test contract and test code I write every time I encounter something non-obvious, to help the next noob and remind me when I forget.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment