Updates to allow verify_ledger_json.js to calculate account_state hash

This commit is contained in:
Nicholas Dudfield
2014-05-06 13:34:01 +07:00
parent 473d8a8d8c
commit a222f2be98
7 changed files with 156 additions and 139 deletions

View File

@@ -3497,10 +3497,10 @@ sjcl.ecc.point.prototype.isOnCurve = function() {
var component_b = self.curve.b;
var field_modulus = self.curve.field.modulus;
var y_squared_mod_field_order = self.y.mul(self.y).mod(field_modulus);
var x_cubed_plus_ax_plus_b = self.x.mul(self.x).mul(self.x).add(component_a.mul(self.x)).add(component_b).mod(field_modulus);
var left_hand_side = self.y.mul(self.y).mod(field_modulus);
var right_hand_side = self.x.mul(self.x).mul(self.x).add(component_a.mul(self.x)).add(component_b).mod(field_modulus);
return y_squared_mod_field_order.equals(x_cubed_plus_ax_plus_b);
return left_hand_side.equals(right_hand_side);
};

View File

@@ -9,6 +9,8 @@ if (process.argc < 1) {
var json = fs.readFileSync(process.argv[2], 'utf-8');
var ledger = Ledger.from_json(JSON.parse(json));
console.log("Calculated transaction hash: "+ledger.calc_tx_hash().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().to_hex());

View File

@@ -208,6 +208,7 @@ var base = [
[ 'TransactionType' , REQUIRED ],
[ 'Flags' , OPTIONAL ],
[ 'SourceTag' , OPTIONAL ],
[ 'LastLedgerSequence' , OPTIONAL ],
[ 'Account' , REQUIRED ],
[ 'Sequence' , REQUIRED ],
[ 'Fee' , REQUIRED ],
@@ -274,27 +275,14 @@ exports.tx = {
])
};
exports.ledger = {
AccountRoot: [97],
Contract: [99],
DirectoryNode: [100],
Features: [102],
GeneratorMap: [103],
LedgerHashes: [104],
Nickname: [110],
Offer: [111],
RippleState: [114],
FeeSettings: [115]
};
/*
TODO:
Need `base` factored out
AccountRoot needs AccountTxnID
{
'AccountRoot': [97,
var sleBase = [
['LedgerIndex', OPTIONAL],
['LedgerEntryType', REQUIRED],
['Flags', REQUIRED],
['Flags', REQUIRED]
];
exports.ledger = {
AccountRoot: [97].concat(sleBase,[
['Sequence', REQUIRED],
['PreviousTxnLgrSeq', REQUIRED],
['TransferRate', OPTIONAL],
@@ -302,21 +290,18 @@ AccountRoot needs AccountTxnID
['OwnerCount', REQUIRED],
['EmailHash', OPTIONAL],
['PreviousTxnID', REQUIRED],
['LedgerIndex', OPTIONAL],
['AccountTxnID', OPTIONAL],
['WalletLocator', OPTIONAL],
['Balance', REQUIRED],
['MessageKey', OPTIONAL,],
['Domain', OPTIONAL,],
['MessageKey', OPTIONAL],
['Domain', OPTIONAL],
['Account', REQUIRED],
['RegularKey', OPTIONAL]],
'Contract': [99,
['LedgerEntryType', REQUIRED],
['Flags', REQUIRED],
['RegularKey', OPTIONAL]]),
Contract: [99].concat(sleBase,[
['PreviousTxnLgrSeq', REQUIRED],
['Expiration', REQUIRED],
['BondAmount', REQUIRED],
['PreviousTxnID', REQUIRED],
['LedgerIndex', OPTIONAL],
['Balance', REQUIRED],
['FundCode', OPTIONAL],
['RemoveCode', OPTIONAL],
@@ -324,53 +309,42 @@ AccountRoot needs AccountTxnID
['CreateCode', OPTIONAL],
['Account', REQUIRED],
['Owner', REQUIRED],
['Issuer', REQUIRED]],
'DirectoryNode': [100,
['LedgerEntryType', REQUIRED],
['Flags', REQUIRED],
['Issuer', REQUIRED]]),
DirectoryNode: [100].concat(sleBase,[
['IndexNext', OPTIONAL],
['IndexPrevious', OPTIONAL],
['ExchangeRate', OPTIONAL],
['LedgerIndex', OPTIONAL],
['RootIndex', REQUIRED],
['Owner', OPTIONAL],
['TakerPaysCurrency', OPTIONAL],
['TakerPaysIssuer', OPTIONAL],
['TakerGetsCurrency', OPTIONAL],
['TakerGetsIssuer', OPTIONAL],
['Indexes', REQUIRED]],
'EnabledFeatures': [102,
['LedgerEntryType', REQUIRED],
['Flags', REQUIRED],
['LedgerIndex', OPTIONAL],
['Features', REQUIRED]],
'FeeSettings': [115,
['LedgerEntryType', REQUIRED],
['Flags', REQUIRED],
['Indexes', REQUIRED]]),
EnabledFeatures: [102].concat(sleBase,[
['Features', REQUIRED]]),
FeeSettings: [115].concat(sleBase,[
['ReferenceFeeUnits', REQUIRED],
['ReserveBase', REQUIRED],
['ReserveIncrement', REQUIRED],
['BaseFee', REQUIRED],
['LedgerIndex', OPTIONAL]],
'GeneratorMap': [103,
['LedgerEntryType', REQUIRED],
['Flags', REQUIRED],
['LedgerIndex', OPTIONAL],
['Generator', REQUIRED,]],
'LedgerHashes': [104,
['LedgerIndex', OPTIONAL]]),
GeneratorMap: [103].concat(sleBase,[
['Generator', REQUIRED]]),
LedgerHashes: [104].concat(sleBase,[
['LedgerEntryType', REQUIRED],
['Flags', REQUIRED],
['FirstLedgerSequence', OPTIONAL],
['LastLedgerSequence', OPTIONAL],
['LedgerIndex', OPTIONAL],
['Hashes', REQUIRED]],
'Nickname': [110,
['Hashes', REQUIRED]]),
Nickname: [110].concat(sleBase,[
['LedgerEntryType', REQUIRED],
['Flags', REQUIRED],
['LedgerIndex', OPTIONAL],
['MinimumOffer', OPTIONAL],
['Account', REQUIRED]],
'Offer': [111,
['Account', REQUIRED]]),
Offer: [111].concat(sleBase,[
['LedgerEntryType', REQUIRED],
['Flags', REQUIRED],
['Sequence', REQUIRED],
@@ -383,8 +357,8 @@ AccountRoot needs AccountTxnID
['BookDirectory', REQUIRED],
['TakerPays', REQUIRED],
['TakerGets', REQUIRED],
['Account', REQUIRED]],
'RippleState': [114,
['Account', REQUIRED]]),
RippleState: [114].concat(sleBase,[
['LedgerEntryType', REQUIRED],
['Flags', REQUIRED],
['PreviousTxnLgrSeq', REQUIRED],
@@ -398,9 +372,8 @@ AccountRoot needs AccountTxnID
['LedgerIndex', OPTIONAL],
['Balance', REQUIRED],
['LowLimit', REQUIRED],
['HighLimit', REQUIRED]]
['HighLimit', REQUIRED]])
}
*/
exports.metadata = [
[ 'TransactionIndex' , REQUIRED ],

View File

@@ -17,6 +17,8 @@ exports.HASH_TX_ID = 0x54584E00; // 'TXN'
exports.HASH_TX_NODE = 0x534E4400; // 'TND'
// inner node in tree
exports.HASH_INNER_NODE = 0x4D494E00; // 'MIN'
// leaf node in tree
exports.HASH_LEAF_NODE = 0x4D4C4E00; // 'MLN'
// inner transaction to sign
exports.HASH_TX_SIGN = 0x53545800; // 'STX'
// inner transaction to sign (TESTNET)

View File

@@ -37,4 +37,16 @@ Ledger.prototype.calc_tx_hash = function () {
return tx_map.hash();
};
Ledger.prototype.calc_account_hash = function () {
var account_map = new SHAMap();
this.ledger_json.accountState.forEach(function (le) {
var data = SerializedObject.from_json(le);
account_map.add_item(le.index, data, SHAMapTreeNode.TYPE_ACCOUNT_STATE);
});
return account_map.hash();
};
exports.Ledger = Ledger;

View File

@@ -53,6 +53,14 @@ SerializedObject.from_json = function (obj) {
}
}
if ("number" === typeof obj.TransactionType) {
obj.LedgerEntryType = SerializedObject.lookup_type_le(obj.LedgerEntryType);
if (!obj.LedgerEntryType) {
throw new Error('LedgerEntryType ID is invalid.');
}
}
if ("string" === typeof obj.TransactionType) {
typedef = binformat.tx[obj.TransactionType];
@@ -62,9 +70,16 @@ SerializedObject.from_json = function (obj) {
typedef = typedef.slice();
obj.TransactionType = typedef.shift();
} else if ("undefined" !== typeof obj.LedgerEntryType) {
// XXX: TODO
throw new Error('Ledger entry binary format not yet implemented.');
} else if ("string" === typeof obj.LedgerEntryType) {
typedef = binformat.ledger[obj.LedgerEntryType];
if (!Array.isArray(typedef)) {
throw new Error('LedgerEntryType is invalid');
}
typedef = typedef.slice();
obj.LedgerEntryType = typedef.shift();
} else if ("object" === typeof obj.AffectedNodes) {
typedef = binformat.metadata;
} else {
@@ -94,13 +109,14 @@ SerializedObject.check_no_missing_fields = function (typedef, obj) {
if (missing_fields.length > 0) {
var object_name;
if (obj.TransactionType != null) {
object_name = SerializedObject.lookup_type_tx(obj.TransactionType);
} else if (obj.LedgerEntryType != null){
object_name = SerializedObject.lookup_type_le(obj.LedgerEntryType);
} else {
object_name = "TransactionMetaData";
} /*else {
TODO: LedgerEntryType ...
}*/
}
throw new Error(object_name + " is missing fields: " +
JSON.stringify(missing_fields));
};
@@ -296,4 +312,9 @@ SerializedObject.lookup_type_tx = function (id) {
return TRANSACTION_TYPES[id];
};
SerializedObject.lookup_type_le = function (id) {
assert(typeof id === 'number');
return LEDGER_ENTRY_TYPES[id];
};
exports.SerializedObject = SerializedObject;

View File

@@ -44,13 +44,16 @@ SHAMapTreeNode.prototype.hash = function () {
/**
* Inner (non-leaf) node in a SHAMap tree.
*/
function SHAMapTreeNodeInner() {
function SHAMapTreeNodeInner(depth) {
SHAMapTreeNode.call(this);
this.leaves = {};
this.type = SHAMapTreeNode.INNER;
// TODO
this.depth == depth == null ? 0 : depth;
this.empty = true;
}
@@ -156,6 +159,10 @@ SHAMapTreeNodeLeaf.prototype.set_segment = function (segment) {
SHAMapTreeNodeLeaf.prototype.hash = function () {
var buffer = new SerializedObject();
switch (this.type) {
case SHAMapTreeNode.TYPE_ACCOUNT_STATE:
buffer.append(this.node);
buffer.append(this.tag.to_bytes());
return buffer.hash(hashprefixes.HASH_LEAF_NODE);
case SHAMapTreeNode.TYPE_TRANSACTION_NM:
return this.tag;
case SHAMapTreeNode.TYPE_TRANSACTION_MD: