Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

[added temporal snapshot/revert, added evm_decreaseTime, added tests for both] #81

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/blockchain_double.js
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,12 @@ BlockchainDouble.prototype.increaseTime = function(seconds) {
return this.timeAdjustment;
};

BlockchainDouble.prototype.decreaseTime = function(seconds) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to let increaseTime accept negative values? That'd be one fewer public method.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mainly because "increaseTime" as read by a developer would indicate time is going up, and a negative value on the variable is easy to mistake on a glance, while reading right to left of a function is pretty solid.

increaseTime(forwardValue)
increaseTime(-forwardValue)

vs

increaseTime(forwardValue)
decreaseTime(backwardsValue)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plus reading pure function definitions in the readme (which I didn't update in this PR) would be immediately visible, while you'd have to create creating an extra note surrounding a negative value being acceptable in the alternative.

if (seconds < 0) seconds = 0;
this.timeAdjustment -= seconds;
return this.timeAdjustment;
};

BlockchainDouble.prototype.setTime = function(date) {
var now = new Date().getTime() / 1000 | 0;
var start = date.getTime() / 1000 | 0;
Expand Down
20 changes: 16 additions & 4 deletions lib/statemanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -717,10 +717,13 @@ StateManager.prototype.snapshot = function(callback) {
if (err) return callback(err);

self.snapshots.push({
blockNumber: blockNumber
blockNumber: blockNumber,
//@note: also tag the current time in this block, to restore afterwards.
currentTime: self.blockchain.currentTime()
});

self.logger.log("Saved snapshot #" + self.snapshots.length);
self.logger.log("[Save] Snapshot time :: " + self.blockchain.currentTime());

callback(null, to.hex(self.snapshots.length));
});
Expand All @@ -732,13 +735,13 @@ StateManager.prototype.revert = function(snapshot_id, callback) {
// Convert from hex.
snapshot_id = utils.bufferToInt(snapshot_id);

this.logger.log("Reverting to snapshot #" + snapshot_id);

if (snapshot_id > this.snapshots.length) {
return false;
}

// Convert to zero based.
this.logger.log("Reverting to snapshot #" + snapshot_id);

// Convert to zero based.
snapshot_id = snapshot_id - 1;

// Loop through each snapshot with a higher id than the current one.
Expand All @@ -747,6 +750,15 @@ StateManager.prototype.revert = function(snapshot_id, callback) {
}, function(nextSnapshot) {
var snapshot = self.snapshots.pop();

self.logger.log("[Revert] Snapshot time :: " + snapshot.currentTime);

if (typeof snapshot.currentTime !== "undefined" && snapshot.currentTime !== null) {

//@note: to avoid changing the definition of "setTime", we multiply the snapshot time by 1000, and pass it in
// as a "Date" object.
self.blockchain.setTime(new Date(snapshot.currentTime * 1000));
}

// For each snapshot, asynchronously pop off the blocks it represents.
async.during(function(doneWithTest) {
self.blockchain.getHeight(function(err, blockNumber) {
Expand Down
4 changes: 4 additions & 0 deletions lib/subproviders/geth_api_double.js
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,10 @@ GethApiDouble.prototype.evm_increaseTime = function(seconds, callback) {
callback(null, this.state.blockchain.increaseTime(seconds));
};

GethApiDouble.prototype.evm_decreaseTime = function(seconds, callback) {
callback(null, this.state.blockchain.decreaseTime(seconds));
};

GethApiDouble.prototype.evm_mine = function(callback) {
this.state.processBlocks(1, function(err) {
callback(err, '0x0');
Expand Down
82 changes: 71 additions & 11 deletions test/snapshotting.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,28 @@ describe("Checkpointing / Reverting", function() {
var provider;
var accounts;
var web3 = new Web3();
var secondsToJump = 24 * 60 * 60;
var startingBalance;
var startingTime;

var timestampBeforeJump;

var snapshotId;

function send(method, params, callback) {
if (typeof params == "function") {
callback = params;
params = [];
}

provider.send({
jsonrpc: "2.0",
method: method,
params: params || [],
id: new Date().getTime()
}, callback);
}

before("create provider", function() {
provider = Ganache.provider();
web3.setProvider(provider);
Expand Down Expand Up @@ -42,18 +61,52 @@ describe("Checkpointing / Reverting", function() {

startingBalance = balance;

// Now checkpoint.
provider.send({
jsonrpc: "2.0",
method: "evm_snapshot",
params: [],
id: new Date().getTime()
}, function(err, result) {
if (err) return done(err);
snapshotId = result.result;
web3.eth.getBlock('latest', function(err, block){
if(err) return done(err)
startingTime = block.timestamp

// Now checkpoint.
provider.send({
jsonrpc: "2.0",
method: "evm_snapshot",
params: [],
id: new Date().getTime()
}, function(err, result) {
if (err) return done(err);
snapshotId = result.result;
done();
});
})
})
})
});

it('get current time', function(done) {
web3.eth.getBlock('latest', function(err, block){
if(err) return done(err);
timestampBeforeJump = block.timestamp;
done();
});
});

it('increments time by 24 hours', function(done) {
this.timeout(5000) // this is timing out on travis for some reason :-(
// Adjust time
send("evm_increaseTime", [secondsToJump], function(err, result) {
if (err) return done(err);

// Mine a block so new time is recorded.
send("evm_mine", function(err, result) {
if (err) return done(err);

web3.eth.getBlock('latest', function(err, block){
if(err) return done(err);
var secondsJumped = block.timestamp - timestampBeforeJump;

assert(secondsJumped >= secondsToJump);
done();
});
})
});
});
});

Expand Down Expand Up @@ -100,7 +153,14 @@ describe("Checkpointing / Reverting", function() {

assert.equal(receipt, null, "Receipt should be null as it should have been removed");

done();
web3.eth.getBlock('latest', function(err, block) {
if (err) return done(err)

var curTime = block.timestamp
assert.equal(startingTime, curTime, "timestamps of reversion not equal to initial snapshot time");

done();
});
});
});
});
Expand Down
41 changes: 39 additions & 2 deletions test/time_adjust.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ describe('Time adjustment', function() {
var secondsToJump = 5 * 60 * 60;

var timestampBeforeJump;
var timestampBeforeJumpBack;

function send(method, params, callback) {
if (typeof params == "function") {
Expand All @@ -27,9 +28,9 @@ describe('Time adjustment', function() {
params: params || [],
id: new Date().getTime()
}, callback);
};
}

before('get current time', function(done) {
it('get current time', function(done) {
web3.eth.getBlock('latest', function(err, block){
if(err) return done(err)
timestampBeforeJump = block.timestamp
Expand Down Expand Up @@ -66,6 +67,42 @@ describe('Time adjustment', function() {
// test suite. It might have something to do with when the before block
// runs and when the test runs. Likely the last block didn't occur for
// awhile.

//@note: I think the previous comment should be fixed now, changed to an 'it' instead of a 'before'
assert(secondsJumped >= secondsToJump)
done()
})
})
})
})

it('get current time', function(done) {
send("evm_mine", function(err, result) {
if (err) return done(err);

web3.eth.getBlock('latest', function (err, block) {
if (err) return done(err)
timestampBeforeJumpBack = block.timestamp;
done()
})
});
})

it('should jump back 5 hours', function(done) {
// Adjust time
send("evm_decreaseTime", [secondsToJump], function(err, result) {
if (err) return done(err);

// Mine a block so new time is recorded.
send("evm_mine", function(err, result) {
if (err) return done(err);

web3.eth.getBlock('latest', function(err, block){
if(err) return done(err)
var secondsJumped = timestampBeforeJumpBack - block.timestamp;

//@note: fixed the 18 second thing by mining right before this call.
// inverted the "secondsJumped" since we're going backwards.
assert(secondsJumped >= secondsToJump)
done()
})
Expand Down