mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-20 12:15:51 +00:00
Updates to allow verify_ledger_json.js to calculate account_state hash
This commit is contained in:
@@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -208,6 +208,7 @@ var base = [
|
||||
[ 'TransactionType' , REQUIRED ],
|
||||
[ 'Flags' , OPTIONAL ],
|
||||
[ 'SourceTag' , OPTIONAL ],
|
||||
[ 'LastLedgerSequence' , OPTIONAL ],
|
||||
[ 'Account' , REQUIRED ],
|
||||
[ 'Sequence' , REQUIRED ],
|
||||
[ 'Fee' , REQUIRED ],
|
||||
@@ -274,133 +275,105 @@ 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
|
||||
var sleBase = [
|
||||
['LedgerIndex', OPTIONAL],
|
||||
['LedgerEntryType', REQUIRED],
|
||||
['Flags', REQUIRED]
|
||||
];
|
||||
|
||||
{
|
||||
'AccountRoot': [97,
|
||||
['LedgerEntryType', REQUIRED],
|
||||
['Flags', REQUIRED],
|
||||
['Sequence', REQUIRED],
|
||||
['PreviousTxnLgrSeq', REQUIRED],
|
||||
['TransferRate', OPTIONAL],
|
||||
['WalletSize', OPTIONAL],
|
||||
['OwnerCount', REQUIRED],
|
||||
['EmailHash', OPTIONAL],
|
||||
['PreviousTxnID', REQUIRED],
|
||||
['LedgerIndex', OPTIONAL],
|
||||
['WalletLocator', OPTIONAL],
|
||||
['Balance', REQUIRED],
|
||||
['MessageKey', OPTIONAL,],
|
||||
['Domain', OPTIONAL,],
|
||||
['Account', REQUIRED],
|
||||
['RegularKey', OPTIONAL]],
|
||||
'Contract': [99,
|
||||
['LedgerEntryType', REQUIRED],
|
||||
['Flags', REQUIRED],
|
||||
['PreviousTxnLgrSeq', REQUIRED],
|
||||
['Expiration', REQUIRED],
|
||||
['BondAmount', REQUIRED],
|
||||
['PreviousTxnID', REQUIRED],
|
||||
['LedgerIndex', OPTIONAL],
|
||||
['Balance', REQUIRED],
|
||||
['FundCode', OPTIONAL],
|
||||
['RemoveCode', OPTIONAL],
|
||||
['ExpireCode', OPTIONAL],
|
||||
['CreateCode', OPTIONAL],
|
||||
['Account', REQUIRED],
|
||||
['Owner', REQUIRED],
|
||||
['Issuer', REQUIRED]],
|
||||
'DirectoryNode': [100,
|
||||
['LedgerEntryType', REQUIRED],
|
||||
['Flags', REQUIRED],
|
||||
['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],
|
||||
['ReferenceFeeUnits', REQUIRED],
|
||||
['ReserveBase', REQUIRED],
|
||||
['ReserveIncrement', REQUIRED],
|
||||
['BaseFee', REQUIRED],
|
||||
['LedgerIndex', OPTIONAL]],
|
||||
'GeneratorMap': [103,
|
||||
['LedgerEntryType', REQUIRED],
|
||||
['Flags', REQUIRED],
|
||||
['LedgerIndex', OPTIONAL],
|
||||
['Generator', REQUIRED,]],
|
||||
'LedgerHashes': [104,
|
||||
['LedgerEntryType', REQUIRED],
|
||||
['Flags', REQUIRED],
|
||||
['FirstLedgerSequence', OPTIONAL],
|
||||
['LastLedgerSequence', OPTIONAL],
|
||||
['LedgerIndex', OPTIONAL],
|
||||
['Hashes', REQUIRED]],
|
||||
'Nickname': [110,
|
||||
['LedgerEntryType', REQUIRED],
|
||||
['Flags', REQUIRED],
|
||||
['LedgerIndex', OPTIONAL],
|
||||
['MinimumOffer', OPTIONAL],
|
||||
['Account', REQUIRED]],
|
||||
'Offer': [111,
|
||||
['LedgerEntryType', REQUIRED],
|
||||
['Flags', REQUIRED],
|
||||
['Sequence', REQUIRED],
|
||||
['PreviousTxnLgrSeq', REQUIRED],
|
||||
['Expiration', OPTIONAL],
|
||||
['BookNode', REQUIRED],
|
||||
['OwnerNode', REQUIRED],
|
||||
['PreviousTxnID', REQUIRED],
|
||||
['LedgerIndex', OPTIONAL],
|
||||
['BookDirectory', REQUIRED],
|
||||
['TakerPays', REQUIRED],
|
||||
['TakerGets', REQUIRED],
|
||||
['Account', REQUIRED]],
|
||||
'RippleState': [114,
|
||||
['LedgerEntryType', REQUIRED],
|
||||
['Flags', REQUIRED],
|
||||
['PreviousTxnLgrSeq', REQUIRED],
|
||||
['HighQualityIn', OPTIONAL],
|
||||
['HighQualityOut', OPTIONAL],
|
||||
['LowQualityIn', OPTIONAL],
|
||||
['LowQualityOut', OPTIONAL],
|
||||
['LowNode', OPTIONAL],
|
||||
['HighNode', OPTIONAL],
|
||||
['PreviousTxnID', REQUIRED],
|
||||
['LedgerIndex', OPTIONAL],
|
||||
['Balance', REQUIRED],
|
||||
['LowLimit', REQUIRED],
|
||||
['HighLimit', REQUIRED]]
|
||||
exports.ledger = {
|
||||
AccountRoot: [97].concat(sleBase,[
|
||||
['Sequence', REQUIRED],
|
||||
['PreviousTxnLgrSeq', REQUIRED],
|
||||
['TransferRate', OPTIONAL],
|
||||
['WalletSize', OPTIONAL],
|
||||
['OwnerCount', REQUIRED],
|
||||
['EmailHash', OPTIONAL],
|
||||
['PreviousTxnID', REQUIRED],
|
||||
['AccountTxnID', OPTIONAL],
|
||||
['WalletLocator', OPTIONAL],
|
||||
['Balance', REQUIRED],
|
||||
['MessageKey', OPTIONAL],
|
||||
['Domain', OPTIONAL],
|
||||
['Account', REQUIRED],
|
||||
['RegularKey', OPTIONAL]]),
|
||||
Contract: [99].concat(sleBase,[
|
||||
['PreviousTxnLgrSeq', REQUIRED],
|
||||
['Expiration', REQUIRED],
|
||||
['BondAmount', REQUIRED],
|
||||
['PreviousTxnID', REQUIRED],
|
||||
['Balance', REQUIRED],
|
||||
['FundCode', OPTIONAL],
|
||||
['RemoveCode', OPTIONAL],
|
||||
['ExpireCode', OPTIONAL],
|
||||
['CreateCode', OPTIONAL],
|
||||
['Account', REQUIRED],
|
||||
['Owner', REQUIRED],
|
||||
['Issuer', REQUIRED]]),
|
||||
DirectoryNode: [100].concat(sleBase,[
|
||||
['IndexNext', OPTIONAL],
|
||||
['IndexPrevious', OPTIONAL],
|
||||
['ExchangeRate', OPTIONAL],
|
||||
['RootIndex', REQUIRED],
|
||||
['Owner', OPTIONAL],
|
||||
['TakerPaysCurrency', OPTIONAL],
|
||||
['TakerPaysIssuer', OPTIONAL],
|
||||
['TakerGetsCurrency', OPTIONAL],
|
||||
['TakerGetsIssuer', OPTIONAL],
|
||||
['Indexes', REQUIRED]]),
|
||||
EnabledFeatures: [102].concat(sleBase,[
|
||||
['Features', REQUIRED]]),
|
||||
FeeSettings: [115].concat(sleBase,[
|
||||
['ReferenceFeeUnits', REQUIRED],
|
||||
['ReserveBase', REQUIRED],
|
||||
['ReserveIncrement', REQUIRED],
|
||||
['BaseFee', REQUIRED],
|
||||
['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].concat(sleBase,[
|
||||
['LedgerEntryType', REQUIRED],
|
||||
['Flags', REQUIRED],
|
||||
['LedgerIndex', OPTIONAL],
|
||||
['MinimumOffer', OPTIONAL],
|
||||
['Account', REQUIRED]]),
|
||||
Offer: [111].concat(sleBase,[
|
||||
['LedgerEntryType', REQUIRED],
|
||||
['Flags', REQUIRED],
|
||||
['Sequence', REQUIRED],
|
||||
['PreviousTxnLgrSeq', REQUIRED],
|
||||
['Expiration', OPTIONAL],
|
||||
['BookNode', REQUIRED],
|
||||
['OwnerNode', REQUIRED],
|
||||
['PreviousTxnID', REQUIRED],
|
||||
['LedgerIndex', OPTIONAL],
|
||||
['BookDirectory', REQUIRED],
|
||||
['TakerPays', REQUIRED],
|
||||
['TakerGets', REQUIRED],
|
||||
['Account', REQUIRED]]),
|
||||
RippleState: [114].concat(sleBase,[
|
||||
['LedgerEntryType', REQUIRED],
|
||||
['Flags', REQUIRED],
|
||||
['PreviousTxnLgrSeq', REQUIRED],
|
||||
['HighQualityIn', OPTIONAL],
|
||||
['HighQualityOut', OPTIONAL],
|
||||
['LowQualityIn', OPTIONAL],
|
||||
['LowQualityOut', OPTIONAL],
|
||||
['LowNode', OPTIONAL],
|
||||
['HighNode', OPTIONAL],
|
||||
['PreviousTxnID', REQUIRED],
|
||||
['LedgerIndex', OPTIONAL],
|
||||
['Balance', REQUIRED],
|
||||
['LowLimit', REQUIRED],
|
||||
['HighLimit', REQUIRED]])
|
||||
}
|
||||
*/
|
||||
|
||||
exports.metadata = [
|
||||
[ 'TransactionIndex' , REQUIRED ],
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
@@ -81,7 +96,7 @@ SerializedObject.from_json = function (obj) {
|
||||
|
||||
SerializedObject.check_no_missing_fields = function (typedef, obj) {
|
||||
var missing_fields = [];
|
||||
|
||||
|
||||
for (var i = typedef.length - 1; i >= 0; i--) {
|
||||
var spec = typedef[i];
|
||||
var field = spec[0]
|
||||
@@ -91,17 +106,18 @@ SerializedObject.check_no_missing_fields = function (typedef, obj) {
|
||||
missing_fields.push(field);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
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: " +
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user