diff --git a/bin/update_binformat.js b/bin/update_binformat.js new file mode 100644 index 000000000..f12e008ce --- /dev/null +++ b/bin/update_binformat.js @@ -0,0 +1,108 @@ +/** + * bin/update_bintypes.js + * + * This unholy abomination of a script generates the JavaScript file + * src/js/bintypes.js from various parts of the C++ source code. + * + * This should *NOT* be part of any automatic build process unless the C++ + * source data are brought into a more easily parseable format. Until then, + * simply run this script manually and fix as needed. + */ + +// XXX: Process LedgerFormats.(h|cpp) as well. + +var filenameProto = __dirname + '/../src/cpp/ripple/SerializeProto.h', + filenameTxFormatsH = __dirname + '/../src/cpp/ripple/TransactionFormats.h', + filenameTxFormats = __dirname + '/../src/cpp/ripple/TransactionFormats.cpp', + + filenameOut = __dirname + '/../src/js/binformat.js'; + +var fs = require('fs'); + +var output = []; + +// Stage 1: Get the field types and codes from SerializeProto.h +var types = {}, + fields = []; +String(fs.readFileSync(filenameProto)).split('\n').forEach(function (line) { + line = line.replace(/^\s+|\s+$/g, '').replace(/\s+/g, ''); + if (!line.length || line.slice(0, 2) === '//' || line.slice(-1) !== ')') return; + + var tmp = line.slice(0, -1).split('('), + type = tmp[0], + opts = tmp[1].split(','); + + if (type === 'TYPE') types[opts[1]] = [opts[0], +opts[2]]; + else if (type === 'FIELD') fields.push([opts[0], types[opts[1]][0], +opts[2]]); +}); + +output.push('var ST = require("./serializedtypes");'); +output.push(''); +output.push('var REQUIRED = 0,'); +output.push(' OPTIONAL = 1,'); +output.push(' DEFAULT = 2,'); +output.push(''); + +function pad(s, n) { while (s.length < n) s += ' '; return s; } +fields.forEach(function (field) { + output.push(' '+pad(field[0], 19) + ' = [' + + pad("'"+field[0]+"'", 22) + ', ST.'+field[1] + + ', '+field[2] + '],'); +}); + +// Stage 2: Get the transaction type IDs from TransactionFormats.h +var ttConsts = {}; +String(fs.readFileSync(filenameTxFormatsH)).split('\n').forEach(function (line) { + var regex = /tt([A-Z_]+)\s+=\s+([0-9-]+)/; + var match = line.match(regex); + if (match) ttConsts[match[1]] = +match[2]; +}); + +// Stage 3: Get the transaction formats from TransactionFormats.cpp +var base = [], + sections = [], + current = base; +String(fs.readFileSync(filenameTxFormats)).split('\n').forEach(function (line) { + line = line.replace(/^\s+|\s+$/g, '').replace(/\s+/g, ''); + + var d_regex = /DECLARE_TF\(([A-Za-z]+),tt([A-Z_]+)/; + var d_match = line.match(d_regex); + + var s_regex = /SOElement\(sf([a-z]+),SOE_(REQUIRED|OPTIONAL|DEFAULT)/i; + var s_match = line.match(s_regex); + + if (d_match) sections.push(current = [d_match[1], ttConsts[d_match[2]]]); + else if (s_match) current.push([s_match[1], s_match[2]]); +}); + +function removeFinalComma(arr) { + arr[arr.length-1] = arr[arr.length-1].slice(0, -1); +} + +output.push(''); +output.push(' base = ['); +base.forEach(function (field) { + output.push(' [ '+pad(field[0], 19)+', '+pad(field[1], 8)+' ],'); +}); +removeFinalComma(output); +output.push(' ];'); +output.push(''); + + +output.push('exports.tx = {'); +sections.forEach(function (section) { + var name = section.shift(), + ttid = section.shift(); + + output.push(' '+name+': ['+ttid+'].concat(base, ['); + section.forEach(function (field) { + output.push(' [ '+pad(field[0], 19)+', '+pad(field[1], 8)+' ],'); + }); + removeFinalComma(output); + output.push(' ],'); +}); +removeFinalComma(output); +output.push('};'); +output.push(''); + +fs.writeFileSync(filenameOut, output.join('\n')); diff --git a/src/js/binformat.js b/src/js/binformat.js new file mode 100644 index 000000000..8078f4c7d --- /dev/null +++ b/src/js/binformat.js @@ -0,0 +1,182 @@ +var ST = require("./serializedtypes"); + +var REQUIRED = 0, + OPTIONAL = 1, + DEFAULT = 2, + + CloseResolution = ['CloseResolution' , ST.Int8, 1], + TemplateEntryType = ['TemplateEntryType' , ST.Int8, 2], + TransactionResult = ['TransactionResult' , ST.Int8, 3], + LedgerEntryType = ['LedgerEntryType' , ST.Int16, 1], + TransactionType = ['TransactionType' , ST.Int16, 2], + Flags = ['Flags' , ST.Int32, 2], + SourceTag = ['SourceTag' , ST.Int32, 3], + Sequence = ['Sequence' , ST.Int32, 4], + PreviousTxnLgrSeq = ['PreviousTxnLgrSeq' , ST.Int32, 5], + LedgerSequence = ['LedgerSequence' , ST.Int32, 6], + CloseTime = ['CloseTime' , ST.Int32, 7], + ParentCloseTime = ['ParentCloseTime' , ST.Int32, 8], + SigningTime = ['SigningTime' , ST.Int32, 9], + Expiration = ['Expiration' , ST.Int32, 10], + TransferRate = ['TransferRate' , ST.Int32, 11], + WalletSize = ['WalletSize' , ST.Int32, 12], + OwnerCount = ['OwnerCount' , ST.Int32, 13], + DestinationTag = ['DestinationTag' , ST.Int32, 14], + HighQualityIn = ['HighQualityIn' , ST.Int32, 16], + HighQualityOut = ['HighQualityOut' , ST.Int32, 17], + LowQualityIn = ['LowQualityIn' , ST.Int32, 18], + LowQualityOut = ['LowQualityOut' , ST.Int32, 19], + QualityIn = ['QualityIn' , ST.Int32, 20], + QualityOut = ['QualityOut' , ST.Int32, 21], + StampEscrow = ['StampEscrow' , ST.Int32, 22], + BondAmount = ['BondAmount' , ST.Int32, 23], + LoadFee = ['LoadFee' , ST.Int32, 24], + OfferSequence = ['OfferSequence' , ST.Int32, 25], + LastLedgerSequence = ['LastLedgerSequence' , ST.Int32, 27], + TransactionIndex = ['TransactionIndex' , ST.Int32, 28], + OperationLimit = ['OperationLimit' , ST.Int32, 29], + ReferenceFeeUnits = ['ReferenceFeeUnits' , ST.Int32, 30], + ReserveBase = ['ReserveBase' , ST.Int32, 31], + ReserveIncrement = ['ReserveIncrement' , ST.Int32, 32], + IndexNext = ['IndexNext' , ST.Int64, 1], + IndexPrevious = ['IndexPrevious' , ST.Int64, 2], + BookNode = ['BookNode' , ST.Int64, 3], + OwnerNode = ['OwnerNode' , ST.Int64, 4], + BaseFee = ['BaseFee' , ST.Int64, 5], + ExchangeRate = ['ExchangeRate' , ST.Int64, 6], + LowNode = ['LowNode' , ST.Int64, 7], + HighNode = ['HighNode' , ST.Int64, 8], + EmailHash = ['EmailHash' , ST.Hash128, 1], + LedgerHash = ['LedgerHash' , ST.Hash256, 1], + ParentHash = ['ParentHash' , ST.Hash256, 2], + TransactionHash = ['TransactionHash' , ST.Hash256, 3], + AccountHash = ['AccountHash' , ST.Hash256, 4], + PreviousTxnID = ['PreviousTxnID' , ST.Hash256, 5], + LedgerIndex = ['LedgerIndex' , ST.Hash256, 6], + WalletLocator = ['WalletLocator' , ST.Hash256, 7], + RootIndex = ['RootIndex' , ST.Hash256, 8], + BookDirectory = ['BookDirectory' , ST.Hash256, 16], + InvoiceID = ['InvoiceID' , ST.Hash256, 17], + Nickname = ['Nickname' , ST.Hash256, 18], + Feature = ['Feature' , ST.Hash256, 19], + TakerPaysCurrency = ['TakerPaysCurrency' , ST.Hash160, 1], + TakerPaysIssuer = ['TakerPaysIssuer' , ST.Hash160, 2], + TakerGetsCurrency = ['TakerGetsCurrency' , ST.Hash160, 3], + TakerGetsIssuer = ['TakerGetsIssuer' , ST.Hash160, 4], + Amount = ['Amount' , ST.Amount, 1], + Balance = ['Balance' , ST.Amount, 2], + LimitAmount = ['LimitAmount' , ST.Amount, 3], + TakerPays = ['TakerPays' , ST.Amount, 4], + TakerGets = ['TakerGets' , ST.Amount, 5], + LowLimit = ['LowLimit' , ST.Amount, 6], + HighLimit = ['HighLimit' , ST.Amount, 7], + Fee = ['Fee' , ST.Amount, 8], + SendMax = ['SendMax' , ST.Amount, 9], + MinimumOffer = ['MinimumOffer' , ST.Amount, 16], + RippleEscrow = ['RippleEscrow' , ST.Amount, 17], + PublicKey = ['PublicKey' , ST.VariableLength, 1], + MessageKey = ['MessageKey' , ST.VariableLength, 2], + SigningPubKey = ['SigningPubKey' , ST.VariableLength, 3], + TxnSignature = ['TxnSignature' , ST.VariableLength, 4], + Generator = ['Generator' , ST.VariableLength, 5], + Signature = ['Signature' , ST.VariableLength, 6], + Domain = ['Domain' , ST.VariableLength, 7], + FundCode = ['FundCode' , ST.VariableLength, 8], + RemoveCode = ['RemoveCode' , ST.VariableLength, 9], + ExpireCode = ['ExpireCode' , ST.VariableLength, 10], + CreateCode = ['CreateCode' , ST.VariableLength, 11], + Account = ['Account' , ST.Account, 1], + Owner = ['Owner' , ST.Account, 2], + Destination = ['Destination' , ST.Account, 3], + Issuer = ['Issuer' , ST.Account, 4], + Target = ['Target' , ST.Account, 7], + RegularKey = ['RegularKey' , ST.Account, 8], + Paths = ['Paths' , ST.PathSet, 1], + Indexes = ['Indexes' , ST.Vector256, 1], + Hashes = ['Hashes' , ST.Vector256, 2], + TransactionMetaData = ['TransactionMetaData' , ST.Object, 2], + CreatedNode = ['CreatedNode' , ST.Object, 3], + DeletedNode = ['DeletedNode' , ST.Object, 4], + ModifiedNode = ['ModifiedNode' , ST.Object, 5], + PreviousFields = ['PreviousFields' , ST.Object, 6], + FinalFields = ['FinalFields' , ST.Object, 7], + NewFields = ['NewFields' , ST.Object, 8], + TemplateEntry = ['TemplateEntry' , ST.Object, 9], + SigningAccounts = ['SigningAccounts' , ST.Array, 2], + TxnSignatures = ['TxnSignatures' , ST.Array, 3], + Signatures = ['Signatures' , ST.Array, 4], + Template = ['Template' , ST.Array, 5], + Necessary = ['Necessary' , ST.Array, 6], + Sufficient = ['Sufficient' , ST.Array, 7], + AffectedNodes = ['AffectedNodes' , ST.Array, 8], + Features = ['Features' , ST.Array, 9], + + base = [ + [ TransactionType , REQUIRED ], + [ Flags , OPTIONAL ], + [ SourceTag , OPTIONAL ], + [ Account , REQUIRED ], + [ Sequence , REQUIRED ], + [ Fee , REQUIRED ], + [ OperationLimit , OPTIONAL ], + [ SigningPubKey , REQUIRED ], + [ TxnSignature , OPTIONAL ] + ]; + +exports.tx = { + AccountSet: [3].concat(base, [ + [ EmailHash , OPTIONAL ], + [ WalletLocator , OPTIONAL ], + [ WalletSize , OPTIONAL ], + [ MessageKey , OPTIONAL ], + [ Domain , OPTIONAL ], + [ TransferRate , OPTIONAL ] + ], + TrustSet: [20].concat(base, [ + [ LimitAmount , OPTIONAL ], + [ QualityIn , OPTIONAL ], + [ QualityOut , OPTIONAL ] + ], + OfferCreate: [7].concat(base, [ + [ TakerPays , REQUIRED ], + [ TakerGets , REQUIRED ], + [ Expiration , OPTIONAL ] + ], + OfferCancel: [8].concat(base, [ + [ OfferSequence , REQUIRED ] + ], + SetRegularKey: [5].concat(base, [ + [ RegularKey , REQUIRED ] + ], + Payment: [0].concat(base, [ + [ Destination , REQUIRED ], + [ Amount , REQUIRED ], + [ SendMax , OPTIONAL ], + [ Paths , DEFAULT ], + [ InvoiceID , OPTIONAL ], + [ DestinationTag , OPTIONAL ] + ], + Contract: [9].concat(base, [ + [ Expiration , REQUIRED ], + [ BondAmount , REQUIRED ], + [ StampEscrow , REQUIRED ], + [ RippleEscrow , REQUIRED ], + [ CreateCode , OPTIONAL ], + [ FundCode , OPTIONAL ], + [ RemoveCode , OPTIONAL ], + [ ExpireCode , OPTIONAL ] + ], + RemoveContract: [10].concat(base, [ + [ Target , REQUIRED ] + ], + EnableFeature: [100].concat(base, [ + [ Feature , REQUIRED ] + ], + SetFee: [101].concat(base, [ + [ Features , REQUIRED ], + [ BaseFee , REQUIRED ], + [ ReferenceFeeUnits , REQUIRED ], + [ ReserveBase , REQUIRED ], + [ ReserveIncrement , REQUIRED ] + ] +}; diff --git a/src/js/serializedtypes.js b/src/js/serializedtypes.js new file mode 100644 index 000000000..11acd294f --- /dev/null +++ b/src/js/serializedtypes.js @@ -0,0 +1,129 @@ +var SerializedType = function () { + +}; + +exports.Int8 = new SerializedType({ + serialize: function (so, val) { + return so.append([val & 0xff]); + }, + parse: function (so) { + return so.read(1)[0]; + } +}); + +exports.Int16 = new SerializedType({ + serialize: function (so, val) { + // XXX + }, + parse: function (so) { + // XXX + } +}); + +exports.Int32 = new SerializedType({ + serialize: function (so, val) { + // XXX + }, + parse: function (so) { + // XXX + } +}); + +exports.Int64 = new SerializedType({ + serialize: function (so, val) { + // XXX + }, + parse: function (so) { + // XXX + } +}); + +exports.Hash128 = new SerializedType({ + serialize: function (so, val) { + // XXX + }, + parse: function (so) { + // XXX + } +}); + +exports.Hash256 = new SerializedType({ + serialize: function (so, val) { + // XXX + }, + parse: function (so) { + // XXX + } +}); + +exports.Hash160 = new SerializedType({ + serialize: function (so, val) { + // XXX + }, + parse: function (so) { + // XXX + } +}); + +exports.Amount = new SerializedType({ + serialize: function (so, val) { + // XXX + }, + parse: function (so) { + // XXX + } +}); + +exports.VariableLength = new SerializedType({ + serialize: function (so, val) { + // XXX + }, + parse: function (so) { + // XXX + } +}); + +exports.Account = new SerializedType({ + serialize: function (so, val) { + // XXX + }, + parse: function (so) { + // XXX + } +}); + +exports.PathSet = new SerializedType({ + serialize: function (so, val) { + // XXX + }, + parse: function (so) { + // XXX + } +}); + +exports.Vector256 = new SerializedType({ + serialize: function (so, val) { + // XXX + }, + parse: function (so) { + // XXX + } +}); + +exports.Object = new SerializedType({ + serialize: function (so, val) { + // XXX + }, + parse: function (so) { + // XXX + } +}); + +exports.Array = new SerializedType({ + serialize: function (so, val) { + // XXX + }, + parse: function (so) { + // XXX + } +});