Fix merge conflicts

This commit is contained in:
wltsmrz
2014-05-19 12:07:24 -07:00
13 changed files with 349 additions and 204 deletions

View File

@@ -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 ],

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,41 @@ Ledger.prototype.calc_tx_hash = function () {
return tx_map.hash();
};
/**
* @param options.sanity_test {Boolean}
*
* If `true`, will serialize each accountState item to binary and then back to
* json before finally serializing for hashing. This is mostly to expose any
* issues with ripple-lib's binary <--> json codecs.
*
*/
Ledger.prototype.calc_account_hash = function (options) {
var account_map = new SHAMap();
var erred;
this.ledger_json.accountState.forEach(function (le) {
var data = SerializedObject.from_json(le);
if (options != null && options.sanity_test) {
try {
var json = data.to_json();
data = SerializedObject.from_json(json);
} catch (e) {
console.log("account state item: ", le);
console.log("to_json() ",json);
console.log("exception: ", e);
erred = true;
}
};
account_map.add_item(le.index, data, SHAMapTreeNode.TYPE_ACCOUNT_STATE);
});
if (erred) {
throw new Error("There were errors with sanity_test"); // all logged above
}
return account_map.hash();
};
exports.Ledger = Ledger;

View File

@@ -52,6 +52,14 @@ SerializedObject.from_json = function(obj) {
}
}
if (typeof obj.LedgerEntryType === 'number') {
obj.LedgerEntryType = SerializedObject.lookup_type_le(obj.LedgerEntryType);
if (!obj.LedgerEntryType) {
throw new Error('LedgerEntryType ID is invalid.');
}
}
if (typeof obj.TransactionType === 'string') {
typedef = binformat.tx[obj.TransactionType];
if (!Array.isArray(typedef)) {
@@ -60,9 +68,16 @@ SerializedObject.from_json = function(obj) {
typedef = typedef.slice();
obj.TransactionType = typedef.shift();
} else if (typeof obj.LedgerEntryType !== 'undefined') {
// XXX: TODO
throw new Error('Ledger entry binary format not yet implemented.');
} else if (typeof obj.LedgerEntryType === 'string') {
typedef = binformat.ledger[obj.LedgerEntryType];
if (!Array.isArray(typedef)) {
throw new Error('LedgerEntryType is invalid');
}
typedef = typedef.slice();
obj.LedgerEntryType = typedef.shift();
} else if (typeof obj.AffectedNodes === 'object') {
typedef = binformat.metadata;
} else {
@@ -80,7 +95,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--) {
for (var i = typedef.length - 1; i >= 0; i--) {
var spec = typedef[i];
var field = spec[0];
var requirement = spec[1];
@@ -95,13 +110,14 @@ SerializedObject.check_no_missing_fields = function(typedef, obj) {
if (obj.TransactionType !== void(0)) {
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 ...
}*/
object_name = "TransactionMetaData";
}
throw new Error(object_name + ' is missing fields: ' + JSON.stringify(missing_fields));
throw new Error(object_name + " is missing fields: " +
JSON.stringify(missing_fields));
};
};
@@ -302,4 +318,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

@@ -220,7 +220,10 @@ var STInt64 = exports.Int64 = new SerializedType({
serialize_hex(so, hex, true); //noLength = true
},
parse: function (so) {
var result = new BigInteger(so.read(8), 256);
var bytes = so.read(8);
// We need to add a 0, so if the high bit is set it won't think it's a
// pessimistic numeric fraek. What doth lief?
var result = new BigInteger([0].concat(bytes), 256);
assert(result instanceof BigInteger);
return result;
}

View File

@@ -7,7 +7,7 @@ var UInt256 = require('./uint256').UInt256;
var SerializedObject = require('./serializedobject').SerializedObject;
function SHAMap() {
this.root = new SHAMapTreeNodeInner();
this.root = new SHAMapTreeNodeInner(0);
};
SHAMap.prototype.add_item = function(tag, node, type) {
@@ -31,7 +31,10 @@ SHAMapTreeNode.TYPE_TRANSACTION_NM = 2;
SHAMapTreeNode.TYPE_TRANSACTION_MD = 3;
SHAMapTreeNode.TYPE_ACCOUNT_STATE = 4;
SHAMapTreeNode.prototype.add_item = function(tag_segment, node) {
/**
* @param tag {String} 64 hexadecimal characters
*/
SHAMapTreeNode.prototype.add_item = function(tag, node) {
throw new Error('Called unimplemented virtual method SHAMapTreeNode#add_item.');
};
@@ -42,48 +45,48 @@ 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;
this.depth = depth == null ? 0 : depth;
this.empty = true;
}
util.inherits(SHAMapTreeNodeInner, SHAMapTreeNode);
SHAMapTreeNodeInner.prototype.add_item = function(tag_segment, node) {
var current_node = this.get_node(tag_segment[0]);
/**
* @param tag {String} (equates to a ledger entries `index`)
*/
SHAMapTreeNodeInner.prototype.add_item = function (tag, node) {
var depth = this.depth;
var existing_node = this.get_node(tag[depth]);
if (current_node) {
if (existing_node) {
// A node already exists in this slot
if (current_node instanceof SHAMapTreeNodeInner) {
if (existing_node instanceof SHAMapTreeNodeInner) {
// There is an inner node, so we need to go deeper
current_node.add_item(tag_segment.slice(1), node);
} else if (current_node.get_segment() === tag_segment) {
existing_node.add_item(tag, node);
} else if (existing_node.tag === tag) {
// Collision
throw new Error('Tried to add a node to a SHAMap that was already in there.');
} else {
// Turn it into an inner node
var new_inner_node = new SHAMapTreeNodeInner();
var new_inner_node = new SHAMapTreeNodeInner(depth + 1);
// Move the existing leaf node down one level
current_node.set_segment(current_node.get_segment().slice(1));
new_inner_node.set_node(current_node.get_segment()[0], current_node);
// Add the new node next to it
new_inner_node.add_item(tag_segment.slice(1), node);
// Parent new and existing node
new_inner_node.add_item(existing_node.tag, existing_node);
new_inner_node.add_item(tag, node);
// And place the newly created inner node in the slot
this.set_node(tag_segment[0], new_inner_node);
this.set_node(tag[depth], new_inner_node);
}
} else {
// Neat, we have a nice open spot for the new node
node.set_segment(tag_segment);
this.set_node(tag_segment[0], node);
this.set_node(tag[depth], node);
}
};
@@ -129,37 +132,30 @@ SHAMapTreeNodeInner.prototype.hash = function() {
function SHAMapTreeNodeLeaf(tag, node, type) {
SHAMapTreeNode.call(this);
if (typeof tag === 'string') {
tag = UInt256.from_hex(tag);
} else if (!(tag instanceof UInt256)){
if (typeof tag !== 'string') {
throw new Error('Tag is unexpected type.');
}
this.tag = tag;
this.tag_segment = null;
this.tag_bytes = UInt256.from_hex(this.tag).to_bytes();
this.type = type;
this.node = node;
};
util.inherits(SHAMapTreeNodeLeaf, SHAMapTreeNode);
SHAMapTreeNodeLeaf.prototype.get_segment = function(segment) {
return this.tag_segment;
};
SHAMapTreeNodeLeaf.prototype.set_segment = function(segment) {
this.tag_segment = segment;
};
SHAMapTreeNodeLeaf.prototype.hash = function() {
SHAMapTreeNodeLeaf.prototype.hash = function () {
var buffer = new SerializedObject();
switch (this.type) {
case SHAMapTreeNode.TYPE_ACCOUNT_STATE:
buffer.append(this.node);
buffer.append(this.tag_bytes);
return buffer.hash(hashprefixes.HASH_LEAF_NODE);
case SHAMapTreeNode.TYPE_TRANSACTION_NM:
return this.tag;
return this.tag_bytes;
case SHAMapTreeNode.TYPE_TRANSACTION_MD:
buffer.append(this.node);
buffer.append(this.tag.to_bytes());
buffer.append(this.tag_bytes);
return buffer.hash(hashprefixes.HASH_TX_NODE);
default:
throw new Error('Tried to hash a SHAMap node of unknown type.');