mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-27 23:55:49 +00:00
Add hidden computeTreeHashes option
This commit is contained in:
@@ -28,27 +28,25 @@ function hashLedgerHeader(ledgerHeader) {
|
||||
function computeTransactionHash(ledger, version,
|
||||
options: ComputeLedgerHashOptions) {
|
||||
let transactions: any[]
|
||||
if (options.headerOnly === undefined) {
|
||||
options.headerOnly = true // by default, allow rawTransactions to be omitted
|
||||
}
|
||||
if (ledger.rawTransactions === undefined) {
|
||||
if (options.headerOnly === true) {
|
||||
return ledger.transactionHash
|
||||
} else {
|
||||
try {
|
||||
transactions = ledger.transactions.map(tx =>
|
||||
JSON.parse(tx.rawTransaction))
|
||||
} catch (e) {
|
||||
if (e.toString() === 'SyntaxError: Unexpected' +
|
||||
' token u in JSON at position 0') {
|
||||
// one or more of the `tx.rawTransaction`s is undefined
|
||||
throw new common.errors.ValidationError('ledger'
|
||||
+ ' is missing raw transactions')
|
||||
}
|
||||
if (ledger.rawTransactions) {
|
||||
transactions = JSON.parse(ledger.rawTransactions)
|
||||
} else if (ledger.transactions) {
|
||||
try {
|
||||
transactions = ledger.transactions.map(tx =>
|
||||
JSON.parse(tx.rawTransaction))
|
||||
} catch (e) {
|
||||
if (e.toString() === 'SyntaxError: Unexpected' +
|
||||
' token u in JSON at position 0') {
|
||||
// one or more of the `tx.rawTransaction`s is undefined
|
||||
throw new common.errors.ValidationError('ledger'
|
||||
+ ' is missing raw transactions')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
transactions = JSON.parse(ledger.rawTransactions)
|
||||
if (options.computeTreeHashes)
|
||||
throw new common.errors.ValidationError('transactions'
|
||||
+ ' property is missing from the ledger')
|
||||
return ledger.transactionHash
|
||||
}
|
||||
const txs = _.map(transactions, tx => {
|
||||
const mergeTx = _.assign({}, _.omit(tx, 'tx'), tx.tx || {})
|
||||
@@ -69,8 +67,12 @@ function computeTransactionHash(ledger, version,
|
||||
return transactionHash
|
||||
}
|
||||
|
||||
function computeStateHash(ledger, version) {
|
||||
function computeStateHash(ledger, version,
|
||||
options: ComputeLedgerHashOptions) {
|
||||
if (ledger.rawState === undefined) {
|
||||
if (options.computeTreeHashes)
|
||||
throw new common.errors.ValidationError('rawState'
|
||||
+ ' property is missing from the ledger')
|
||||
return ledger.stateHash
|
||||
}
|
||||
const state = JSON.parse(ledger.rawState)
|
||||
@@ -85,7 +87,7 @@ function computeStateHash(ledger, version) {
|
||||
const sLCF_SHAMapV2 = 0x02
|
||||
|
||||
export type ComputeLedgerHashOptions = {
|
||||
headerOnly?: boolean
|
||||
computeTreeHashes?: boolean
|
||||
}
|
||||
|
||||
function computeLedgerHash(ledger: any,
|
||||
@@ -93,7 +95,7 @@ function computeLedgerHash(ledger: any,
|
||||
const version = ((ledger.closeFlags & sLCF_SHAMapV2) === 0) ? 1 : 2
|
||||
const subhashes = {
|
||||
transactionHash: computeTransactionHash(ledger, version, options),
|
||||
stateHash: computeStateHash(ledger, version)
|
||||
stateHash: computeStateHash(ledger, version, options)
|
||||
}
|
||||
return hashLedgerHeader(_.assign({}, ledger, subhashes))
|
||||
}
|
||||
|
||||
@@ -2550,7 +2550,7 @@ describe('RippleAPI', function () {
|
||||
.then(response => {
|
||||
const ledger = _.assign({}, response,
|
||||
{ parentCloseTime: response.closeTime });
|
||||
const hash = this.api.computeLedgerHash(ledger, {headerOnly: false});
|
||||
const hash = this.api.computeLedgerHash(ledger, {computeTreeHashes: true});
|
||||
assert.strictEqual(hash,
|
||||
'E6DB7365949BF9814D76BCC730B01818EB9136A89DB224F3F9F5AAE4569D758E');
|
||||
});
|
||||
@@ -2573,7 +2573,7 @@ describe('RippleAPI', function () {
|
||||
|
||||
let hash;
|
||||
try {
|
||||
hash = this.api.computeLedgerHash(ledger, {headerOnly: false});
|
||||
hash = this.api.computeLedgerHash(ledger, {computeTreeHashes: true});
|
||||
} catch (error) {
|
||||
assert(error instanceof this.api.errors.ValidationError);
|
||||
assert.strictEqual(error.message, 'transactionHash in header does not match computed hash of transactions');
|
||||
@@ -2604,7 +2604,7 @@ describe('RippleAPI', function () {
|
||||
|
||||
let hash;
|
||||
try {
|
||||
hash = this.api.computeLedgerHash(ledger, {headerOnly: false});
|
||||
hash = this.api.computeLedgerHash(ledger, {computeTreeHashes: true});
|
||||
} catch (error) {
|
||||
assert(error instanceof this.api.errors.ValidationError);
|
||||
assert.strictEqual(error.message, 'ledger'
|
||||
@@ -2615,6 +2615,47 @@ describe('RippleAPI', function () {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('computeLedgerHash - given ledger without state or transactions - only compute ledger hash', function () {
|
||||
const request = {
|
||||
includeTransactions: true,
|
||||
includeState: true,
|
||||
includeAllData: true,
|
||||
ledgerVersion: 38129
|
||||
};
|
||||
return this.api.getLedger(request).then(ledger => {
|
||||
assert.strictEqual(ledger.transactions[0].rawTransaction, "{\"Account\":\"r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV\",\"Amount\":\"10000000000\",\"Destination\":\"rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj\",\"Fee\":\"10\",\"Flags\":0,\"Sequence\":62,\"SigningPubKey\":\"034AADB09CFF4A4804073701EC53C3510CDC95917C2BB0150FB742D0C66E6CEE9E\",\"TransactionType\":\"Payment\",\"TxnSignature\":\"3045022022EB32AECEF7C644C891C19F87966DF9C62B1F34BABA6BE774325E4BB8E2DD62022100A51437898C28C2B297112DF8131F2BB39EA5FE613487DDD611525F1796264639\",\"hash\":\"3B1A4E1C9BB6A7208EB146BCDB86ECEA6068ED01466D933528CA2B4C64F753EF\",\"meta\":{\"AffectedNodes\":[{\"CreatedNode\":{\"LedgerEntryType\":\"AccountRoot\",\"LedgerIndex\":\"4C6ACBD635B0F07101F7FA25871B0925F8836155462152172755845CE691C49E\",\"NewFields\":{\"Account\":\"rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj\",\"Balance\":\"10000000000\",\"Sequence\":1}}},{\"ModifiedNode\":{\"FinalFields\":{\"Account\":\"r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV\",\"Balance\":\"981481999380\",\"Flags\":0,\"OwnerCount\":0,\"Sequence\":63},\"LedgerEntryType\":\"AccountRoot\",\"LedgerIndex\":\"B33FDD5CF3445E1A7F2BE9B06336BEBD73A5E3EE885D3EF93F7E3E2992E46F1A\",\"PreviousFields\":{\"Balance\":\"991481999390\",\"Sequence\":62},\"PreviousTxnID\":\"2485FDC606352F1B0785DA5DE96FB9DBAF43EB60ECBB01B7F6FA970F512CDA5F\",\"PreviousTxnLgrSeq\":31317}}],\"TransactionIndex\":0,\"TransactionResult\":\"tesSUCCESS\"},\"ledger_index\":38129}");
|
||||
|
||||
ledger.parentCloseTime = ledger.closeTime;
|
||||
|
||||
const computeLedgerHash = this.api.computeLedgerHash;
|
||||
const ValidationError = this.api.errors.ValidationError
|
||||
function testCompute(ledger, expectedError) {
|
||||
let hash = computeLedgerHash(ledger);
|
||||
assert.strictEqual(hash,
|
||||
'E6DB7365949BF9814D76BCC730B01818EB9136A89DB224F3F9F5AAE4569D758E');
|
||||
|
||||
// fail if required to compute tree hashes
|
||||
try {
|
||||
hash = computeLedgerHash(ledger, {computeTreeHashes: true});
|
||||
} catch (error) {
|
||||
assert(error instanceof ValidationError);
|
||||
assert.strictEqual(error.message, expectedError);
|
||||
return;
|
||||
}
|
||||
assert(false, 'Should throw ValidationError instead of producing hash: ' + hash);
|
||||
}
|
||||
|
||||
const transactions = ledger.transactions;
|
||||
delete ledger.transactions;
|
||||
testCompute(ledger, 'transactions property is missing from the ledger');
|
||||
delete ledger.rawState;
|
||||
testCompute(ledger, 'transactions property is missing from the ledger');
|
||||
ledger.transactions = transactions;
|
||||
testCompute(ledger, 'rawState property is missing from the ledger');
|
||||
});
|
||||
});
|
||||
|
||||
it('computeLedgerHash - wrong hash', function () {
|
||||
const request = {
|
||||
includeTransactions: true,
|
||||
|
||||
Reference in New Issue
Block a user