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 component_b = self.curve.b;
|
||||||
var field_modulus = self.curve.field.modulus;
|
var field_modulus = self.curve.field.modulus;
|
||||||
|
|
||||||
var y_squared_mod_field_order = self.y.mul(self.y).mod(field_modulus);
|
var left_hand_side = 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 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 json = fs.readFileSync(process.argv[2], 'utf-8');
|
||||||
var ledger = Ledger.from_json(JSON.parse(json));
|
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("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 ],
|
[ 'TransactionType' , REQUIRED ],
|
||||||
[ 'Flags' , OPTIONAL ],
|
[ 'Flags' , OPTIONAL ],
|
||||||
[ 'SourceTag' , OPTIONAL ],
|
[ 'SourceTag' , OPTIONAL ],
|
||||||
|
[ 'LastLedgerSequence' , OPTIONAL ],
|
||||||
[ 'Account' , REQUIRED ],
|
[ 'Account' , REQUIRED ],
|
||||||
[ 'Sequence' , REQUIRED ],
|
[ 'Sequence' , REQUIRED ],
|
||||||
[ 'Fee' , REQUIRED ],
|
[ 'Fee' , REQUIRED ],
|
||||||
@@ -274,133 +275,105 @@ exports.tx = {
|
|||||||
])
|
])
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.ledger = {
|
var sleBase = [
|
||||||
AccountRoot: [97],
|
['LedgerIndex', OPTIONAL],
|
||||||
Contract: [99],
|
['LedgerEntryType', REQUIRED],
|
||||||
DirectoryNode: [100],
|
['Flags', REQUIRED]
|
||||||
Features: [102],
|
];
|
||||||
GeneratorMap: [103],
|
|
||||||
LedgerHashes: [104],
|
|
||||||
Nickname: [110],
|
|
||||||
Offer: [111],
|
|
||||||
RippleState: [114],
|
|
||||||
FeeSettings: [115]
|
|
||||||
};
|
|
||||||
/*
|
|
||||||
TODO:
|
|
||||||
Need `base` factored out
|
|
||||||
AccountRoot needs AccountTxnID
|
|
||||||
|
|
||||||
{
|
exports.ledger = {
|
||||||
'AccountRoot': [97,
|
AccountRoot: [97].concat(sleBase,[
|
||||||
['LedgerEntryType', REQUIRED],
|
['Sequence', REQUIRED],
|
||||||
['Flags', REQUIRED],
|
['PreviousTxnLgrSeq', REQUIRED],
|
||||||
['Sequence', REQUIRED],
|
['TransferRate', OPTIONAL],
|
||||||
['PreviousTxnLgrSeq', REQUIRED],
|
['WalletSize', OPTIONAL],
|
||||||
['TransferRate', OPTIONAL],
|
['OwnerCount', REQUIRED],
|
||||||
['WalletSize', OPTIONAL],
|
['EmailHash', OPTIONAL],
|
||||||
['OwnerCount', REQUIRED],
|
['PreviousTxnID', REQUIRED],
|
||||||
['EmailHash', OPTIONAL],
|
['AccountTxnID', OPTIONAL],
|
||||||
['PreviousTxnID', REQUIRED],
|
['WalletLocator', OPTIONAL],
|
||||||
['LedgerIndex', OPTIONAL],
|
['Balance', REQUIRED],
|
||||||
['WalletLocator', OPTIONAL],
|
['MessageKey', OPTIONAL],
|
||||||
['Balance', REQUIRED],
|
['Domain', OPTIONAL],
|
||||||
['MessageKey', OPTIONAL,],
|
['Account', REQUIRED],
|
||||||
['Domain', OPTIONAL,],
|
['RegularKey', OPTIONAL]]),
|
||||||
['Account', REQUIRED],
|
Contract: [99].concat(sleBase,[
|
||||||
['RegularKey', OPTIONAL]],
|
['PreviousTxnLgrSeq', REQUIRED],
|
||||||
'Contract': [99,
|
['Expiration', REQUIRED],
|
||||||
['LedgerEntryType', REQUIRED],
|
['BondAmount', REQUIRED],
|
||||||
['Flags', REQUIRED],
|
['PreviousTxnID', REQUIRED],
|
||||||
['PreviousTxnLgrSeq', REQUIRED],
|
['Balance', REQUIRED],
|
||||||
['Expiration', REQUIRED],
|
['FundCode', OPTIONAL],
|
||||||
['BondAmount', REQUIRED],
|
['RemoveCode', OPTIONAL],
|
||||||
['PreviousTxnID', REQUIRED],
|
['ExpireCode', OPTIONAL],
|
||||||
['LedgerIndex', OPTIONAL],
|
['CreateCode', OPTIONAL],
|
||||||
['Balance', REQUIRED],
|
['Account', REQUIRED],
|
||||||
['FundCode', OPTIONAL],
|
['Owner', REQUIRED],
|
||||||
['RemoveCode', OPTIONAL],
|
['Issuer', REQUIRED]]),
|
||||||
['ExpireCode', OPTIONAL],
|
DirectoryNode: [100].concat(sleBase,[
|
||||||
['CreateCode', OPTIONAL],
|
['IndexNext', OPTIONAL],
|
||||||
['Account', REQUIRED],
|
['IndexPrevious', OPTIONAL],
|
||||||
['Owner', REQUIRED],
|
['ExchangeRate', OPTIONAL],
|
||||||
['Issuer', REQUIRED]],
|
['RootIndex', REQUIRED],
|
||||||
'DirectoryNode': [100,
|
['Owner', OPTIONAL],
|
||||||
['LedgerEntryType', REQUIRED],
|
['TakerPaysCurrency', OPTIONAL],
|
||||||
['Flags', REQUIRED],
|
['TakerPaysIssuer', OPTIONAL],
|
||||||
['IndexNext', OPTIONAL],
|
['TakerGetsCurrency', OPTIONAL],
|
||||||
['IndexPrevious', OPTIONAL],
|
['TakerGetsIssuer', OPTIONAL],
|
||||||
['ExchangeRate', OPTIONAL],
|
['Indexes', REQUIRED]]),
|
||||||
['LedgerIndex', OPTIONAL],
|
EnabledFeatures: [102].concat(sleBase,[
|
||||||
['RootIndex', REQUIRED],
|
['Features', REQUIRED]]),
|
||||||
['Owner', OPTIONAL],
|
FeeSettings: [115].concat(sleBase,[
|
||||||
['TakerPaysCurrency', OPTIONAL],
|
['ReferenceFeeUnits', REQUIRED],
|
||||||
['TakerPaysIssuer', OPTIONAL],
|
['ReserveBase', REQUIRED],
|
||||||
['TakerGetsCurrency', OPTIONAL],
|
['ReserveIncrement', REQUIRED],
|
||||||
['TakerGetsIssuer', OPTIONAL],
|
['BaseFee', REQUIRED],
|
||||||
['Indexes', REQUIRED]],
|
['LedgerIndex', OPTIONAL]]),
|
||||||
'EnabledFeatures': [102,
|
GeneratorMap: [103].concat(sleBase,[
|
||||||
['LedgerEntryType', REQUIRED],
|
['Generator', REQUIRED]]),
|
||||||
['Flags', REQUIRED],
|
LedgerHashes: [104].concat(sleBase,[
|
||||||
['LedgerIndex', OPTIONAL],
|
['LedgerEntryType', REQUIRED],
|
||||||
['Features', REQUIRED]],
|
['Flags', REQUIRED],
|
||||||
'FeeSettings': [115,
|
['FirstLedgerSequence', OPTIONAL],
|
||||||
['LedgerEntryType', REQUIRED],
|
['LastLedgerSequence', OPTIONAL],
|
||||||
['Flags', REQUIRED],
|
['LedgerIndex', OPTIONAL],
|
||||||
['ReferenceFeeUnits', REQUIRED],
|
['Hashes', REQUIRED]]),
|
||||||
['ReserveBase', REQUIRED],
|
Nickname: [110].concat(sleBase,[
|
||||||
['ReserveIncrement', REQUIRED],
|
['LedgerEntryType', REQUIRED],
|
||||||
['BaseFee', REQUIRED],
|
['Flags', REQUIRED],
|
||||||
['LedgerIndex', OPTIONAL]],
|
['LedgerIndex', OPTIONAL],
|
||||||
'GeneratorMap': [103,
|
['MinimumOffer', OPTIONAL],
|
||||||
['LedgerEntryType', REQUIRED],
|
['Account', REQUIRED]]),
|
||||||
['Flags', REQUIRED],
|
Offer: [111].concat(sleBase,[
|
||||||
['LedgerIndex', OPTIONAL],
|
['LedgerEntryType', REQUIRED],
|
||||||
['Generator', REQUIRED,]],
|
['Flags', REQUIRED],
|
||||||
'LedgerHashes': [104,
|
['Sequence', REQUIRED],
|
||||||
['LedgerEntryType', REQUIRED],
|
['PreviousTxnLgrSeq', REQUIRED],
|
||||||
['Flags', REQUIRED],
|
['Expiration', OPTIONAL],
|
||||||
['FirstLedgerSequence', OPTIONAL],
|
['BookNode', REQUIRED],
|
||||||
['LastLedgerSequence', OPTIONAL],
|
['OwnerNode', REQUIRED],
|
||||||
['LedgerIndex', OPTIONAL],
|
['PreviousTxnID', REQUIRED],
|
||||||
['Hashes', REQUIRED]],
|
['LedgerIndex', OPTIONAL],
|
||||||
'Nickname': [110,
|
['BookDirectory', REQUIRED],
|
||||||
['LedgerEntryType', REQUIRED],
|
['TakerPays', REQUIRED],
|
||||||
['Flags', REQUIRED],
|
['TakerGets', REQUIRED],
|
||||||
['LedgerIndex', OPTIONAL],
|
['Account', REQUIRED]]),
|
||||||
['MinimumOffer', OPTIONAL],
|
RippleState: [114].concat(sleBase,[
|
||||||
['Account', REQUIRED]],
|
['LedgerEntryType', REQUIRED],
|
||||||
'Offer': [111,
|
['Flags', REQUIRED],
|
||||||
['LedgerEntryType', REQUIRED],
|
['PreviousTxnLgrSeq', REQUIRED],
|
||||||
['Flags', REQUIRED],
|
['HighQualityIn', OPTIONAL],
|
||||||
['Sequence', REQUIRED],
|
['HighQualityOut', OPTIONAL],
|
||||||
['PreviousTxnLgrSeq', REQUIRED],
|
['LowQualityIn', OPTIONAL],
|
||||||
['Expiration', OPTIONAL],
|
['LowQualityOut', OPTIONAL],
|
||||||
['BookNode', REQUIRED],
|
['LowNode', OPTIONAL],
|
||||||
['OwnerNode', REQUIRED],
|
['HighNode', OPTIONAL],
|
||||||
['PreviousTxnID', REQUIRED],
|
['PreviousTxnID', REQUIRED],
|
||||||
['LedgerIndex', OPTIONAL],
|
['LedgerIndex', OPTIONAL],
|
||||||
['BookDirectory', REQUIRED],
|
['Balance', REQUIRED],
|
||||||
['TakerPays', REQUIRED],
|
['LowLimit', REQUIRED],
|
||||||
['TakerGets', REQUIRED],
|
['HighLimit', 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.metadata = [
|
exports.metadata = [
|
||||||
[ 'TransactionIndex' , REQUIRED ],
|
[ 'TransactionIndex' , REQUIRED ],
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ exports.HASH_TX_ID = 0x54584E00; // 'TXN'
|
|||||||
exports.HASH_TX_NODE = 0x534E4400; // 'TND'
|
exports.HASH_TX_NODE = 0x534E4400; // 'TND'
|
||||||
// inner node in tree
|
// inner node in tree
|
||||||
exports.HASH_INNER_NODE = 0x4D494E00; // 'MIN'
|
exports.HASH_INNER_NODE = 0x4D494E00; // 'MIN'
|
||||||
|
// leaf node in tree
|
||||||
|
exports.HASH_LEAF_NODE = 0x4D4C4E00; // 'MLN'
|
||||||
// inner transaction to sign
|
// inner transaction to sign
|
||||||
exports.HASH_TX_SIGN = 0x53545800; // 'STX'
|
exports.HASH_TX_SIGN = 0x53545800; // 'STX'
|
||||||
// inner transaction to sign (TESTNET)
|
// inner transaction to sign (TESTNET)
|
||||||
|
|||||||
@@ -37,4 +37,16 @@ Ledger.prototype.calc_tx_hash = function () {
|
|||||||
return tx_map.hash();
|
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;
|
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) {
|
if ("string" === typeof obj.TransactionType) {
|
||||||
typedef = binformat.tx[obj.TransactionType];
|
typedef = binformat.tx[obj.TransactionType];
|
||||||
|
|
||||||
@@ -62,9 +70,16 @@ SerializedObject.from_json = function (obj) {
|
|||||||
|
|
||||||
typedef = typedef.slice();
|
typedef = typedef.slice();
|
||||||
obj.TransactionType = typedef.shift();
|
obj.TransactionType = typedef.shift();
|
||||||
} else if ("undefined" !== typeof obj.LedgerEntryType) {
|
} else if ("string" === typeof obj.LedgerEntryType) {
|
||||||
// XXX: TODO
|
typedef = binformat.ledger[obj.LedgerEntryType];
|
||||||
throw new Error('Ledger entry binary format not yet implemented.');
|
|
||||||
|
if (!Array.isArray(typedef)) {
|
||||||
|
throw new Error('LedgerEntryType is invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef = typedef.slice();
|
||||||
|
obj.LedgerEntryType = typedef.shift();
|
||||||
|
|
||||||
} else if ("object" === typeof obj.AffectedNodes) {
|
} else if ("object" === typeof obj.AffectedNodes) {
|
||||||
typedef = binformat.metadata;
|
typedef = binformat.metadata;
|
||||||
} else {
|
} else {
|
||||||
@@ -81,7 +96,7 @@ SerializedObject.from_json = function (obj) {
|
|||||||
|
|
||||||
SerializedObject.check_no_missing_fields = function (typedef, obj) {
|
SerializedObject.check_no_missing_fields = function (typedef, obj) {
|
||||||
var missing_fields = [];
|
var missing_fields = [];
|
||||||
|
|
||||||
for (var i = typedef.length - 1; i >= 0; i--) {
|
for (var i = typedef.length - 1; i >= 0; i--) {
|
||||||
var spec = typedef[i];
|
var spec = typedef[i];
|
||||||
var field = spec[0]
|
var field = spec[0]
|
||||||
@@ -91,17 +106,18 @@ SerializedObject.check_no_missing_fields = function (typedef, obj) {
|
|||||||
missing_fields.push(field);
|
missing_fields.push(field);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
if (missing_fields.length > 0) {
|
if (missing_fields.length > 0) {
|
||||||
var object_name;
|
var object_name;
|
||||||
|
|
||||||
if (obj.TransactionType != null) {
|
if (obj.TransactionType != null) {
|
||||||
object_name = SerializedObject.lookup_type_tx(obj.TransactionType);
|
object_name = SerializedObject.lookup_type_tx(obj.TransactionType);
|
||||||
|
} else if (obj.LedgerEntryType != null){
|
||||||
|
object_name = SerializedObject.lookup_type_le(obj.LedgerEntryType);
|
||||||
} else {
|
} else {
|
||||||
object_name = "TransactionMetaData";
|
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));
|
JSON.stringify(missing_fields));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -296,4 +312,9 @@ SerializedObject.lookup_type_tx = function (id) {
|
|||||||
return TRANSACTION_TYPES[id];
|
return TRANSACTION_TYPES[id];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SerializedObject.lookup_type_le = function (id) {
|
||||||
|
assert(typeof id === 'number');
|
||||||
|
return LEDGER_ENTRY_TYPES[id];
|
||||||
|
};
|
||||||
|
|
||||||
exports.SerializedObject = SerializedObject;
|
exports.SerializedObject = SerializedObject;
|
||||||
|
|||||||
@@ -44,13 +44,16 @@ SHAMapTreeNode.prototype.hash = function () {
|
|||||||
/**
|
/**
|
||||||
* Inner (non-leaf) node in a SHAMap tree.
|
* Inner (non-leaf) node in a SHAMap tree.
|
||||||
*/
|
*/
|
||||||
function SHAMapTreeNodeInner() {
|
function SHAMapTreeNodeInner(depth) {
|
||||||
SHAMapTreeNode.call(this);
|
SHAMapTreeNode.call(this);
|
||||||
|
|
||||||
this.leaves = {};
|
this.leaves = {};
|
||||||
|
|
||||||
this.type = SHAMapTreeNode.INNER;
|
this.type = SHAMapTreeNode.INNER;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
this.depth == depth == null ? 0 : depth;
|
||||||
|
|
||||||
this.empty = true;
|
this.empty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,6 +159,10 @@ SHAMapTreeNodeLeaf.prototype.set_segment = function (segment) {
|
|||||||
SHAMapTreeNodeLeaf.prototype.hash = function () {
|
SHAMapTreeNodeLeaf.prototype.hash = function () {
|
||||||
var buffer = new SerializedObject();
|
var buffer = new SerializedObject();
|
||||||
switch (this.type) {
|
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:
|
case SHAMapTreeNode.TYPE_TRANSACTION_NM:
|
||||||
return this.tag;
|
return this.tag;
|
||||||
case SHAMapTreeNode.TYPE_TRANSACTION_MD:
|
case SHAMapTreeNode.TYPE_TRANSACTION_MD:
|
||||||
|
|||||||
Reference in New Issue
Block a user