diff --git a/src/js/ripple/serializedobject.js b/src/js/ripple/serializedobject.js index de19cda2..8118aecc 100644 --- a/src/js/ripple/serializedobject.js +++ b/src/js/ripple/serializedobject.js @@ -216,13 +216,16 @@ SerializedObject.prototype.serialize = function (typedef, obj) { } }; -SerializedObject.prototype.signing_hash = function (prefix) { +SerializedObject.prototype.hash = function (prefix) { var sign_buffer = new SerializedObject(); stypes.Int32.serialize(sign_buffer, prefix); sign_buffer.append(this.buffer); return sign_buffer.hash_sha512_half(); }; +// DEPRECATED +SerializedObject.prototype.signing_hash = SerializedObject.prototype.hash; + SerializedObject.prototype.hash_sha512_half = function () { var bits = sjcl.codec.bytes.toBits(this.buffer); var hash = sjcl.bitArray.bitSlice(sjcl.hash.sha512.hash(bits), 0, 256); diff --git a/src/js/ripple/transaction.js b/src/js/ripple/transaction.js index e33740b5..83c34280 100644 --- a/src/js/ripple/transaction.js +++ b/src/js/ripple/transaction.js @@ -71,8 +71,6 @@ function Transaction(remote) { // Transaction data. this.tx_json = { Flags: 0 }; - this.hash = void(0); - // ledger_current_index was this when transaction was submited. this.submit_index = void(0); @@ -122,8 +120,12 @@ Transaction.flags = { Transaction.formats = require('./binformat').tx; -Transaction.HASH_SIGN = 0x53545800; -Transaction.HASH_SIGN_TESTNET = 0x73747800; +// transaction plus signature to give transaction ID +Transaction.HASH_TXID = 0x54584E00; // 'TXN' +// inner transaction to sign +Transaction.HASH_SIGN = 0x53545800; // 'STX' +// inner transaction to sign (TESTNET) +Transaction.HASH_SIGN_TESTNET = 0x73747800; // 'stx' Transaction.prototype.consts = { telLOCAL_ERROR : -399, @@ -134,6 +136,10 @@ Transaction.prototype.consts = { tecCLAIMED : 100, }; +Transaction.from_json = function (j) { + return (new Transaction()).parse_json(j); +}; + Transaction.prototype.isTelLocal = function (ter) { return ter >= this.consts.telLOCAL_ERROR && ter < this.consts.temMALFORMED; }; @@ -206,8 +212,21 @@ Transaction.prototype.serialize = function () { }; Transaction.prototype.signing_hash = function () { - var prefix = Transaction[config.testnet ? 'HASH_SIGN_TESTNET' : 'HASH_SIGN']; - return SerializedObject.from_json(this.tx_json).signing_hash(prefix); + return this.hash(config.testnet ? 'HASH_SIGN_TESTNET' : 'HASH_SIGN'); +}; + +Transaction.prototype.hash = function (prefix, as_uint256) { + if ("string" === typeof prefix) { + if ("undefined" === typeof Transaction[prefix]) { + throw new Error("Unknown hashing prefix requested."); + } + prefix = Transaction[prefix]; + } else if (!prefix) { + prefix = Transaction['HASH_TXID']; + } + var hash = SerializedObject.from_json(this.tx_json).hash(prefix); + + return as_uint256 ? hash : hash.to_hex(); }; Transaction.prototype.sign = function () { @@ -650,6 +669,12 @@ Transaction.prototype.abort = function(callback) { } }; +Transaction.prototype.parse_json = function (v) { + this.tx_json = v; + + return this; +}; + exports.Transaction = Transaction; // vim:sw=2:sts=2:ts=8:et diff --git a/test/transaction-test.js b/test/transaction-test.js new file mode 100644 index 00000000..1e08fdcb --- /dev/null +++ b/test/transaction-test.js @@ -0,0 +1,58 @@ +var utils = require('./testutils'); +var assert = require('assert'); +var Transaction = utils.load_module('transaction').Transaction; + +describe('Transaction', function() { + it('Hashing', function() { + var input_json = { + Account : "r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS", + Amount : { + currency : "LTC", + issuer : "r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS", + value : "9.985" + }, + Destination : "r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS", + Fee : "15", + Flags : 0, + Paths : [ + [ + { + account : "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q", + currency : "USD", + issuer : "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q", + type : 49, + type_hex : "0000000000000031" + }, + { + currency : "LTC", + issuer : "rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX", + type : 48, + type_hex : "0000000000000030" + }, + { + account : "rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX", + currency : "LTC", + issuer : "rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX", + type : 49, + type_hex : "0000000000000031" + } + ] + ], + SendMax : { + currency : "USD", + issuer : "r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS", + value : "30.30993068" + }, + Sequence : 415, + SigningPubKey : "02854B06CE8F3E65323F89260E9E19B33DA3E01B30EA4CA172612DE77973FAC58A", + TransactionType : "Payment", + TxnSignature : "304602210096C2F385530587DE573936CA51CB86B801A28F777C944E268212BE7341440B7F022100EBF0508A9145A56CDA7FAF314DF3BBE51C6EE450BA7E74D88516891A3608644E" + }; + var expected_hash = "87366146D381AD971B97DD41CFAC1AE4670B0E996AB574B0CE18CE6467811868"; + var transaction = Transaction.from_json(input_json); + + assert.deepEqual(transaction.hash(), expected_hash); + }); +}); + +// vim:sw=2:sts=2:ts=8:et