Add binary <--> json encoding integration tests

* Add full json ledger dumps of ledgers 38129 and 40000 to test/fixtures
* Use `Ledger` to calculate account and transaction hashes and verify
  against dumps
This commit is contained in:
Nicholas Dudfield
2014-05-18 17:27:47 +07:00
parent 5280d994a2
commit 80bdce970a
7 changed files with 101 additions and 22 deletions

50
scripts/verify_ledger_json.js Normal file → Executable file
View File

@@ -1,25 +1,49 @@
var fs = require('fs');
var Ledger = require('../src/js/ripple/ledger').Ledger;
if (process.argc < 1) {
function parse_options(from, flags) {
var argv = from.slice(2), // remove `node` and `this.js`
opts = {argv:argv};
flags.forEach(function(f) {
// Do we have the flag?
var flag_index = argv.indexOf('--' + f);
// normalize the name of the flag
f = f.replace('-', '_');
// opts has Boolean value for normalized flag key
opts[f] = !!~flag_index;
if (opts[f]) {
// remove the flag from the argv
argv.splice(flag_index, 1);
}
});
return opts;
}
var opts = parse_options(process.argv, ['sanity-test']);
if (opts.argv.length < 1) {
console.error("Usage: scripts/verify_ledger_json path/to/ledger.json");
console.error(" optional: --sanity-test (json>binary>json>binary)");
process.exit(1);
}
var json = fs.readFileSync(process.argv[2], 'utf-8');
var json = fs.readFileSync(opts.argv[0], 'utf-8');
var ledger = Ledger.from_json(JSON.parse(json));
// This will serialize each accountState object to binary and then back to json
// before finally serializing for hashing. This is mostly for verifying that
// ripple-libs binary codecs are working.
// Must obviously go after process.argv[2] used to specify ledger json
var hardcore = ~process.argv.indexOf('--hardcore')
// before finally serializing for hashing. This is mostly to expose any issues
// with ripple-libs binary <--> json codecs.
console.log("Transaction hash in header: "+ledger.ledger_json.transaction_hash);
console.log("Calculated transaction hash: "+ledger.calc_tx_hash().to_hex());
if (opts.sanity_test) {
console.log("All accountState nodes will be processed from " +
"json->binary->json->binary. This may take some time " +
"with large ledgers.");
}
console.log("Account state hash in header: "+ledger.ledger_json.account_hash);
hardcore && console.log("Standby, we are going hardcore!, this may take some time");
console.log("Calculated account state hash: "+ledger.calc_account_hash(hardcore).to_hex());
console.log("Transaction hash in header: " + ledger.ledger_json.transaction_hash);
console.log("Calculated transaction hash: " + ledger.calc_tx_hash().to_hex());
console.log("Account state hash in header: " + ledger.ledger_json.account_hash);
console.log("Calculated account state hash: " + ledger.calc_account_hash(
{sanity_test:opts.sanity_test})
.to_hex());

View File

@@ -37,26 +37,40 @@ Ledger.prototype.calc_tx_hash = function () {
return tx_map.hash();
};
Ledger.prototype.calc_account_hash = function (hardcore) {
/**
* @param options.sanity_test {Boolean}
*
* If `true`, will serialize each accountState item to binary and then back to
* json before finally serializing for hashing. This is mostly to expose any
* issues with ripple-lib's binary <--> json codecs.
*
*/
Ledger.prototype.calc_account_hash = function (options) {
var account_map = new SHAMap();
var erred;
this.ledger_json.accountState.forEach(function (le) {
var data = SerializedObject.from_json(le);
if (hardcore) {
if (options != null && options.sanity_test) {
try {
var json = data.to_json();
data = SerializedObject.from_json(json);
} catch (e) {
console.log("erred on", le);
console.log("to_json() was", json);
console.log("e", e);
console.log("account state item: ", le);
console.log("to_json() ",json);
console.log("exception: ", e);
erred = true;
}
};
account_map.add_item(le.index, data, SHAMapTreeNode.TYPE_ACCOUNT_STATE);
});
if (erred) {
throw new Error("There were errors with sanity_test"); // all logged above
}
return account_map.hash();
};

View File

@@ -53,7 +53,7 @@ SerializedObject.from_json = function (obj) {
}
}
if ("number" === typeof obj.TransactionType) {
if ("number" === typeof obj.LedgerEntryType) {
obj.LedgerEntryType = SerializedObject.lookup_type_le(obj.LedgerEntryType);
if (!obj.LedgerEntryType) {

View File

@@ -60,9 +60,9 @@ function SHAMapTreeNodeInner(depth) {
util.inherits(SHAMapTreeNodeInner, SHAMapTreeNode);
/*
* @param tag {String} (equates to a ledger entries `index`)
*/
/**
* @param tag {String} (equates to a ledger entries `index`)
*/
SHAMapTreeNodeInner.prototype.add_item = function (tag, node) {
var depth = this.depth;
var existing_node = this.get_node(tag[depth]);

1
test/fixtures/ledger-full-38129.json vendored Normal file

File diff suppressed because one or more lines are too long

1
test/fixtures/ledger-full-40000.json vendored Normal file

File diff suppressed because one or more lines are too long

39
test/ledger-test.js Normal file
View File

@@ -0,0 +1,39 @@
var assert = require('assert');
var fs = require('fs');
var utils = require('./testutils');
var Ledger = utils.load_module('ledger').Ledger;
var config = require('./testutils').get_config();
/**
* @param ledger_index {Number}
* Expects a corresponding ledger dump in $repo/test/fixtures/ folder
*/
create_ledger_test = function (ledger_index) {
describe(String(ledger_index), function () {
var path = __dirname + '/fixtures/ledger-full-'+ledger_index+'.json';
var ledger_raw = fs.readFileSync(path),
ledger_json = JSON.parse(ledger_raw),
ledger = Ledger.from_json(ledger_json);
it('has account_hash of '+ ledger_json.account_hash, function() {
assert.equal(ledger_json.account_hash,
ledger.calc_account_hash({sanity_test:true}).to_hex());
})
it('has transaction_hash of '+ ledger_json.transaction_hash, function() {
assert.equal(ledger_json.transaction_hash,
ledger.calc_tx_hash().to_hex());
})
})
}
describe('Ledger', function() {
// This is the first recorded ledger with a non empty transaction set
create_ledger_test(38129);
// Because, why not.
create_ledger_test(40000);
});
// vim:sw=2:sts=2:ts=8:et