@iota/bundle
Advanced tools
Comparing version 1.0.0-beta.11 to 1.0.0-beta.12
"use strict"; | ||
/** @module bundle */ | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
exports.__esModule = true; | ||
var converter_1 = require("@iota/converter"); | ||
var kerl_1 = require("@iota/kerl"); | ||
var pad_1 = require("@iota/pad"); | ||
var signing_1 = require("@iota/signing"); | ||
var errors_1 = require("../../errors"); | ||
var errors = require("../../errors"); | ||
require("../../typed-array"); | ||
var HASH_TRITS_SIZE = 243; | ||
var NULL_HASH_TRYTES = '9'.repeat(81); | ||
var NULL_TAG_TRYTES = '9'.repeat(27); | ||
var NULL_NONCE_TRYTES = '9'.repeat(27); | ||
var NULL_SIGNATURE_MESSAGE_FRAGMENT_TRYTES = '9'.repeat(2187); | ||
var getEntryWithDefaults = function (entry) { return ({ | ||
length: entry.length || 1, | ||
address: entry.address || NULL_HASH_TRYTES, | ||
value: entry.value || 0, | ||
tag: entry.tag || NULL_TAG_TRYTES, | ||
timestamp: entry.timestamp || Math.floor(Date.now() / 1000), | ||
signatureMessageFragments: entry.signatureMessageFragments | ||
? entry.signatureMessageFragments.map(pad_1.padTrytes(2187)) | ||
: Array(entry.length || 1).fill(NULL_SIGNATURE_MESSAGE_FRAGMENT_TRYTES) | ||
}); }; | ||
var transaction_1 = require("@iota/transaction"); | ||
/** | ||
@@ -41,9 +15,9 @@ * Creates a bundle with given transaction entries. | ||
* | ||
* @param {BundleEntry[]} entries - Entries of single or multiple transactions with the same address | ||
* @param {BundleEntry[]} [entries=[]] - Entries of single or multiple transactions with the same address | ||
* | ||
* @return {Transaction[]} List of transactions in the bundle | ||
* @return {Int8Array[]} List of transactions in the bundle | ||
*/ | ||
exports.createBundle = function (entries) { | ||
if (entries === void 0) { entries = []; } | ||
return entries.reduce(function (bundle, entry) { return exports.addEntry(bundle, entry); }, []); | ||
return entries.reduce(function (bundle, entry) { return exports.addEntry(bundle, entry); }, new Int8Array(0)); | ||
}; | ||
@@ -55,105 +29,189 @@ /** | ||
* | ||
* @param {Transaction[]} transactions - List of transactions currently in the bundle | ||
* @param {object} entry - Entry of a single or multiple transactions with the same address. | ||
* @param {Int8Array} entry.address - Address. | ||
* @param {Int8Array} entry.value - Value to transfer in iotas. | ||
* @param {Int8Array} [entry.signatureOrMessage] - Signature or message fragment(s). | ||
* @param {Int8Array} [entry.timestamp] - Issuance timestamp (in seconds). | ||
* @param {Int8Array} [entry.tag] - Optional Tag, **Deprecated**. | ||
* @param {Int8Array} bundle - Bundle buffer. | ||
* | ||
* @param {object} entry - Entry of a single or multiple transactions with the same address | ||
* @param {number} [entry.length = 1] - Entry length, which indicates how many transactions in the bundle it will occupy | ||
* @param {Hash} [entry.address] - Address, defaults to all-9s | ||
* @param {number} [entry.value = 0] - Value to transfer in iotas | ||
* @param {Trytes[]} [entry.signatureMessageFragments] - List of signature message fragments, defaults to all-9s | ||
* @param {number} [entry.timestamp] - Transaction timestamp, defaults to `Math.floor(Date.now() / 1000)` | ||
* @param {string} [entry.tag] - Optional Tag, defaults to null tag (all-9s) | ||
* | ||
* @return {Transaction[]} List of transactions in the updated bundle | ||
* @return {Int8Array} Bundle copy with new entries. | ||
*/ | ||
exports.addEntry = function (transactions, entry) { | ||
var entryWithDefaults = getEntryWithDefaults(entry); | ||
var length = entryWithDefaults.length, address = entryWithDefaults.address, value = entryWithDefaults.value, timestamp = entryWithDefaults.timestamp, signatureMessageFragments = entryWithDefaults.signatureMessageFragments; | ||
var lastIndex = transactions.length - 1 + length; | ||
var tag = pad_1.padTag(entryWithDefaults.tag); | ||
var obsoleteTag = tag; | ||
if (value !== 0 && converter_1.trits(address)[HASH_TRITS_SIZE - 1] !== 0) { | ||
throw new Error(errors_1.INVALID_ADDRESS_LAST_TRIT); | ||
exports.addEntry = function (bundle, entry) { | ||
var signatureOrMessage = entry.signatureOrMessage, | ||
// extraDataDigest, | ||
address = entry.address, value = entry.value, obsoleteTag = entry.obsoleteTag, issuanceTimestamp = entry.issuanceTimestamp, tag = entry.tag; | ||
/* | ||
warning( | ||
signatureOrMessage && !isNullTrits(signatureOrMessage), | ||
'Deprecation warning: \n' + | ||
' - Use of "signatureOrMessage" field before bundle finalization is deprecated and will be removed in v1.0.0. \n' | ||
) | ||
warning( | ||
obsoleteTag && !isNullTrits(obsoleteTag), | ||
'Deprecation warning: \n' + | ||
' - "obseleteTag" field is deprecated and will be removed in implementation of final design. \n' + | ||
' - Use of "obsoleteTag" or "tag" field before bundle finalization is deprecated and will be removed in v1.0.0. \n' | ||
) | ||
warning( | ||
tag && !isNullTrits(tag), | ||
'Deprecation warning: \n' + | ||
' - Use of "tag" field before bundle finalization is deprecated and will be removed in v1.0.0. \n' | ||
) | ||
*/ | ||
if (!transaction_1.isMultipleOfTransactionLength(bundle.length)) { | ||
throw new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH); | ||
} | ||
return transactions.map(function (transaction) { return (__assign({}, transaction, { lastIndex: lastIndex })); }).concat(Array(length) | ||
.fill(null) | ||
.map(function (_, i) { return ({ | ||
address: address, | ||
value: i === 0 ? value : 0, | ||
tag: tag, | ||
obsoleteTag: obsoleteTag, | ||
currentIndex: transactions.length + i, | ||
lastIndex: lastIndex, | ||
timestamp: timestamp, | ||
signatureMessageFragment: signatureMessageFragments[i], | ||
trunkTransaction: NULL_HASH_TRYTES, | ||
branchTransaction: NULL_HASH_TRYTES, | ||
attachmentTimestamp: 0, | ||
attachmentTimestampLowerBound: 0, | ||
attachmentTimestampUpperBound: 0, | ||
bundle: NULL_HASH_TRYTES, | ||
nonce: NULL_NONCE_TRYTES, | ||
hash: NULL_HASH_TRYTES | ||
}); })); | ||
if (signatureOrMessage && | ||
(signatureOrMessage.length === 0 || signatureOrMessage.length % transaction_1.SIGNATURE_OR_MESSAGE_LENGTH !== 0)) { | ||
throw new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH); | ||
} | ||
if (address && address.length !== transaction_1.ADDRESS_LENGTH) { | ||
throw new RangeError(errors.ILLEGAL_ADDRESS_LENGTH); | ||
} | ||
if (value && value.length > transaction_1.VALUE_LENGTH) { | ||
throw new RangeError(errors.ILLEGAL_VALUE_LENGTH); | ||
} | ||
if (obsoleteTag && obsoleteTag.length > transaction_1.OBSOLETE_TAG_LENGTH) { | ||
throw new RangeError(errors.ILLEGAL_OBSOLETE_TAG_LENGTH); | ||
} | ||
if (issuanceTimestamp && issuanceTimestamp.length > transaction_1.ISSUANCE_TIMESTAMP_LENGTH) { | ||
throw new RangeError(errors.ILLEGAL_ISSUANCE_TIMESTAMP_LENGTH); | ||
} | ||
if (tag && tag.length > transaction_1.TAG_LENGTH) { | ||
throw new RangeError(errors.ILLEGAL_TAG_LENGTH); | ||
} | ||
var signatureOrMessageCopy = signatureOrMessage | ||
? signatureOrMessage.slice() | ||
: new Int8Array(transaction_1.SIGNATURE_OR_MESSAGE_LENGTH); | ||
var numberOfFragments = signatureOrMessageCopy.length / transaction_1.SIGNATURE_OR_MESSAGE_LENGTH; | ||
var bundleCopy = new Int8Array(bundle.length + numberOfFragments * transaction_1.TRANSACTION_LENGTH); | ||
var currentIndexBuffer = bundle.length > 0 ? signing_1.increment(transaction_1.lastIndex(bundle)) : new Int8Array(transaction_1.LAST_INDEX_LENGTH); | ||
var lastIndexBuffer = currentIndexBuffer.slice(); | ||
var fragmentIndex = 0; | ||
bundleCopy.set(bundle.slice()); | ||
// Create and append transactions to the bundle. | ||
for (var offset = bundle.length; offset < bundleCopy.length; offset += transaction_1.TRANSACTION_LENGTH) { | ||
var signatureOrMessageCopyFragment = signatureOrMessageCopy.subarray(fragmentIndex * transaction_1.SIGNATURE_OR_MESSAGE_LENGTH, (fragmentIndex + 1) * transaction_1.SIGNATURE_OR_MESSAGE_LENGTH); | ||
bundleCopy.set(signatureOrMessageCopyFragment, offset + transaction_1.SIGNATURE_OR_MESSAGE_OFFSET); | ||
if (address) { | ||
bundleCopy.set(address, offset + transaction_1.ADDRESS_OFFSET); | ||
} | ||
if (value && fragmentIndex === 0) { | ||
bundleCopy.set(value, offset + transaction_1.VALUE_OFFSET); | ||
} | ||
if (obsoleteTag) { | ||
bundleCopy.set(obsoleteTag, offset + transaction_1.OBSOLETE_TAG_OFFSET); | ||
} | ||
if (issuanceTimestamp) { | ||
bundleCopy.set(issuanceTimestamp, offset + transaction_1.ISSUANCE_TIMESTAMP_OFFSET); | ||
} | ||
bundleCopy.set(currentIndexBuffer, offset + transaction_1.CURRENT_INDEX_OFFSET); | ||
if (tag) { | ||
bundleCopy.set(tag, offset + transaction_1.TAG_OFFSET); | ||
} | ||
lastIndexBuffer.set(currentIndexBuffer.slice()); | ||
currentIndexBuffer.set(signing_1.increment(currentIndexBuffer)); | ||
fragmentIndex++; | ||
} | ||
for (var offset = transaction_1.LAST_INDEX_OFFSET; offset < bundleCopy.length; offset += transaction_1.TRANSACTION_LENGTH) { | ||
bundleCopy.set(lastIndexBuffer, offset); | ||
} | ||
return bundleCopy; | ||
}; | ||
/** | ||
* Adds signature message fragments to transactions in a bundle starting at offset. | ||
* Finalizes a bundle by calculating the bundle hash. | ||
* | ||
* @method addTrytes | ||
* @method finalizeBundle | ||
* | ||
* @param {Transaction[]} transactions - List of transactions in the bundle | ||
* @param {Int8Array} bundle - Bundle transaction trits | ||
* | ||
* @param {Trytes[]} fragments - List of signature message fragments to add | ||
* | ||
* @param {number} [offset = 0] - Optional offset to start appending signature message fragments | ||
* | ||
* @return {Transaction[]} List of transactions in the updated bundle | ||
* @return {Int8Array} List of transactions in the finalized bundle | ||
*/ | ||
exports.addTrytes = function (transactions, fragments, offset) { | ||
if (offset === void 0) { offset = 0; } | ||
return transactions.map(function (transaction, i) { | ||
return i >= offset && i < offset + fragments.length | ||
? __assign({}, transaction, { signatureMessageFragment: pad_1.padTrytes(27 * 81)(fragments[i - offset] || '') }) : transaction; | ||
}); | ||
exports.finalizeBundle = function (bundle) { | ||
if (!transaction_1.isMultipleOfTransactionLength(bundle.length)) { | ||
throw new Error(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH); | ||
} | ||
var sponge = new kerl_1["default"](); | ||
var bundleCopy = bundle.slice(); | ||
var bundleHash = new Int8Array(transaction_1.BUNDLE_LENGTH); | ||
// This block recomputes bundle hash by incrementing `obsoleteTag` field of first transaction in the bundle. | ||
// Normalized bundle should NOT contain value `13`. | ||
while (true) { | ||
// Absorb essence trits to squeeze bundle hash. | ||
for (var offset = 0; offset < bundle.length; offset += transaction_1.TRANSACTION_LENGTH) { | ||
sponge.absorb(transaction_1.transactionEssence(bundleCopy, offset), 0, transaction_1.TRANSACTION_ESSENCE_LENGTH); | ||
} | ||
// Set new bundle hash value. | ||
sponge.squeeze(bundleHash, 0, transaction_1.BUNDLE_LENGTH); | ||
// Stop mutation if essence results to secure bundle. | ||
if (signing_1.normalizedBundle(bundleHash).indexOf(signing_1.MAX_TRYTE_VALUE /* 13 */) === -1) { | ||
// Essence results to secure bundle. | ||
break; | ||
} | ||
// Essence results to insecure bundle. (Normalized bundle hash contains value `13`.) | ||
bundleCopy.set(signing_1.increment(bundleCopy.subarray(transaction_1.OBSOLETE_TAG_OFFSET, transaction_1.OBSOLETE_TAG_OFFSET + transaction_1.OBSOLETE_TAG_LENGTH)), transaction_1.OBSOLETE_TAG_OFFSET); | ||
sponge.reset(); | ||
} | ||
// Set bundle field of each transaction. | ||
for (var offset = transaction_1.BUNDLE_OFFSET; offset < bundle.length; offset += transaction_1.TRANSACTION_LENGTH) { | ||
bundleCopy.set(bundleHash, offset); | ||
} | ||
return bundleCopy; | ||
}; | ||
/** | ||
* Finalizes a bundle by calculating the bundle hash. | ||
* Adds signature message fragments to transactions in a bundle starting at offset. | ||
* | ||
* @method finalizeBundle | ||
* @method addSignatureOrMessage | ||
* | ||
* @param {Transaction[]} transactions - List of transactions in the bundle | ||
* @param {Int8Array} bundle - Bundle buffer. | ||
* @param {Int8Array} signatureOrMessage - Signature or message to add. | ||
* @param {number} index - Transaction index as entry point for signature or message fragments. | ||
* | ||
* @return {Transaction[]} List of transactions in the finalized bundle | ||
* @return {Int8Array} List of transactions in the updated bundle | ||
*/ | ||
exports.finalizeBundle = function (transactions) { | ||
var validBundle = false; | ||
var valueTrits = transactions.map(function (tx) { return converter_1.trits(tx.value); }).map(pad_1.padTrits(81)); | ||
var timestampTrits = transactions.map(function (tx) { return converter_1.trits(tx.timestamp); }).map(pad_1.padTrits(27)); | ||
var currentIndexTrits = transactions.map(function (tx) { return converter_1.trits(tx.currentIndex); }).map(pad_1.padTrits(27)); | ||
var lastIndexTrits = pad_1.padTrits(27)(converter_1.trits(transactions[0].lastIndex)); | ||
var obsoleteTagTrits = transactions.map(function (tx) { return converter_1.trits(tx.obsoleteTag); }).map(pad_1.padTrits(81)); | ||
var bundleHashTrits = new Int8Array(kerl_1["default"].HASH_LENGTH); | ||
while (!validBundle) { | ||
var sponge = new kerl_1["default"](); | ||
for (var i = 0; i < transactions.length; i++) { | ||
var essence = converter_1.trits(transactions[i].address + | ||
converter_1.trytes(valueTrits[i]) + | ||
converter_1.trytes(obsoleteTagTrits[i]) + | ||
converter_1.trytes(timestampTrits[i]) + | ||
converter_1.trytes(currentIndexTrits[i]) + | ||
converter_1.trytes(lastIndexTrits)); | ||
sponge.absorb(essence, 0, essence.length); | ||
} | ||
sponge.squeeze(bundleHashTrits, 0, kerl_1["default"].HASH_LENGTH); | ||
if (signing_1.normalizedBundle(bundleHashTrits).indexOf(13) !== -1) { | ||
// Insecure bundle, increment obsoleteTag and recompute bundle hash | ||
obsoleteTagTrits[0] = signing_1.add(obsoleteTagTrits[0], new Int8Array(1).fill(1)); | ||
} | ||
else { | ||
validBundle = true; | ||
} | ||
exports.addSignatureOrMessage = function (bundle, signatureOrMessage, index) { | ||
if (!transaction_1.isMultipleOfTransactionLength(bundle.length)) { | ||
throw new Error(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH); | ||
} | ||
return transactions.map(function (transaction, i) { return (__assign({}, transaction, { | ||
// overwrite obsoleteTag in first entry | ||
obsoleteTag: i === 0 ? converter_1.trytes(obsoleteTagTrits[0]) : transaction.obsoleteTag, bundle: converter_1.trytes(bundleHashTrits) })); }); | ||
if (!Number.isInteger(index)) { | ||
throw new TypeError(errors.ILLEGAL_TRANSACTION_INDEX); | ||
} | ||
if (signatureOrMessage.length === 0 || signatureOrMessage.length % transaction_1.SIGNATURE_OR_MESSAGE_LENGTH !== 0) { | ||
throw new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH); | ||
} | ||
if (index < 0 || bundle.length - index - signatureOrMessage.length / transaction_1.SIGNATURE_OR_MESSAGE_LENGTH < 0) { | ||
throw new RangeError(errors.ILLEGAL_TRANSACTION_INDEX); | ||
} | ||
var bundleCopy = bundle.slice(); | ||
var numberOfFragmentsToAdd = signatureOrMessage.length / transaction_1.SIGNATURE_OR_MESSAGE_LENGTH; | ||
for (var i = 0; i < numberOfFragmentsToAdd; i++) { | ||
bundleCopy.set(signatureOrMessage.slice(i * transaction_1.SIGNATURE_OR_MESSAGE_LENGTH, (i + 1) * transaction_1.SIGNATURE_OR_MESSAGE_LENGTH), (index + i) * transaction_1.TRANSACTION_LENGTH + transaction_1.SIGNATURE_OR_MESSAGE_OFFSET); | ||
} | ||
return bundleCopy; | ||
}; | ||
exports.valueSum = function (buffer, offset, length) { | ||
if (!transaction_1.isMultipleOfTransactionLength(buffer.length)) { | ||
throw new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH); | ||
} | ||
if (!Number.isInteger(offset)) { | ||
throw new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET); | ||
} | ||
if (!transaction_1.isMultipleOfTransactionLength(offset)) { | ||
throw new RangeError(errors.ILLEGAL_TRANSACTION_OFFSET); | ||
} | ||
if (!Number.isInteger(length)) { | ||
throw new TypeError(errors.ILLEGAL_BUNDLE_LENGTH); | ||
} | ||
if (!transaction_1.isMultipleOfTransactionLength(length)) { | ||
throw new RangeError(errors.ILLEGAL_BUNDLE_LENGTH); | ||
} | ||
var sum = 0; | ||
for (var bundleOffset = 0; bundleOffset < length; bundleOffset += transaction_1.TRANSACTION_LENGTH) { | ||
sum += converter_1.tritsToValue(transaction_1.value(buffer, offset + bundleOffset)); | ||
} | ||
return sum; | ||
}; | ||
//# sourceMappingURL=index.js.map |
@@ -13,118 +13,468 @@ "use strict"; | ||
}; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
var _this = this; | ||
exports.__esModule = true; | ||
var converter_1 = require("@iota/converter"); | ||
var ava_1 = require("ava"); | ||
var errors_1 = require("../../errors"); | ||
var kerl_1 = require("@iota/kerl"); | ||
var signing_1 = require("@iota/signing"); | ||
var transaction_1 = require("@iota/transaction"); | ||
var src_1 = require("../src"); | ||
var HASH_TRITS_SIZE = 243; | ||
var NULL_HASH = '9'.repeat(81); | ||
var NULL_NONCE = '9'.repeat(27); | ||
var addresses = ['A'.repeat(81), 'B'.repeat(81)]; | ||
var tag = 'TAG' + '9'.repeat(24); | ||
var bundle = [ | ||
var riteway_1 = require("riteway"); | ||
var errors = require("../../errors"); | ||
var samples_1 = require("./samples"); | ||
var bundleHash = function (bundleTrits) { | ||
var sponge = new kerl_1["default"](); | ||
var out = new Int8Array(transaction_1.BUNDLE_LENGTH); | ||
for (var offset = 0; offset < transaction_1.bundle.length; offset += transaction_1.TRANSACTION_LENGTH) { | ||
sponge.absorb(transaction_1.transactionEssence(bundleTrits, offset), 0, transaction_1.TRANSACTION_ESSENCE_LENGTH); | ||
} | ||
sponge.squeeze(out, 0, transaction_1.BUNDLE_LENGTH); | ||
return out; | ||
}; | ||
var entries = [ | ||
{ | ||
address: addresses[0], | ||
value: -2, | ||
tag: tag, | ||
obsoleteTag: tag, | ||
currentIndex: 0, | ||
lastIndex: 2, | ||
timestamp: 1522219, | ||
signatureMessageFragment: '9'.repeat(81 * 27), | ||
trunkTransaction: NULL_HASH, | ||
branchTransaction: NULL_HASH, | ||
attachmentTimestamp: 0, | ||
attachmentTimestampLowerBound: 0, | ||
attachmentTimestampUpperBound: 0, | ||
bundle: NULL_HASH, | ||
nonce: NULL_NONCE, | ||
hash: NULL_HASH | ||
signatureOrMessage: samples_1.signaturesOrMessages[0], | ||
address: samples_1.addresses[0], | ||
value: samples_1.values[0], | ||
obsoleteTag: samples_1.obsoleteTag, | ||
issuanceTimestamp: samples_1.issuanceTimestamp, | ||
tag: samples_1.tag | ||
}, | ||
{ | ||
address: addresses[0], | ||
value: 0, | ||
tag: tag, | ||
obsoleteTag: tag, | ||
currentIndex: 1, | ||
lastIndex: 2, | ||
timestamp: 1522219, | ||
signatureMessageFragment: '9'.repeat(81 * 27), | ||
trunkTransaction: NULL_HASH, | ||
branchTransaction: NULL_HASH, | ||
attachmentTimestamp: 0, | ||
attachmentTimestampLowerBound: 0, | ||
attachmentTimestampUpperBound: 0, | ||
bundle: NULL_HASH, | ||
nonce: NULL_NONCE, | ||
hash: NULL_HASH | ||
signatureOrMessage: samples_1.signaturesOrMessages[1], | ||
address: samples_1.addresses[1], | ||
value: samples_1.values[1], | ||
obsoleteTag: samples_1.obsoleteTag, | ||
issuanceTimestamp: samples_1.issuanceTimestamp, | ||
tag: samples_1.tag | ||
}, | ||
{ | ||
address: addresses[1], | ||
value: 2, | ||
tag: tag, | ||
obsoleteTag: tag, | ||
currentIndex: 2, | ||
lastIndex: 2, | ||
timestamp: 1522219, | ||
signatureMessageFragment: '9'.repeat(81 * 27), | ||
trunkTransaction: NULL_HASH, | ||
branchTransaction: NULL_HASH, | ||
attachmentTimestamp: 0, | ||
attachmentTimestampLowerBound: 0, | ||
attachmentTimestampUpperBound: 0, | ||
bundle: NULL_HASH, | ||
nonce: NULL_NONCE, | ||
hash: NULL_HASH | ||
signatureOrMessage: samples_1.signaturesOrMessages[2], | ||
address: samples_1.addresses[2], | ||
value: samples_1.values[2], | ||
obsoleteTag: samples_1.obsoleteTag, | ||
issuanceTimestamp: samples_1.issuanceTimestamp, | ||
tag: samples_1.tag | ||
}, | ||
]; | ||
ava_1["default"]('createBundle() returns correct transactions.', function (t) { | ||
t.deepEqual(src_1.createBundle([ | ||
{ | ||
length: 2, | ||
address: addresses[0], | ||
value: -2, | ||
tag: 'TAG', | ||
timestamp: 1522219 | ||
}, | ||
{ | ||
length: 1, | ||
address: addresses[1], | ||
value: 2, | ||
tag: 'TAG', | ||
timestamp: 1522219 | ||
}, | ||
]), bundle, 'createBundle() should return correct transactions.'); | ||
var actualInterimBundle = src_1.createBundle(entries); | ||
var actualInterimBundlePartial = src_1.createBundle(entries.slice(0, entries.length - 1)); | ||
var actualFinalBundle = src_1.finalizeBundle(actualInterimBundle); | ||
var actualFinalSignedBundle = signing_1.signatureFragments(samples_1.seed, 0, 2, transaction_1.bundle(actualFinalBundle)).then(function (signature) { | ||
return src_1.addSignatureOrMessage(actualFinalBundle, signature, 1); | ||
}); | ||
ava_1["default"]('addEntry() adds new entry and returns correct transactions.', function (t) { | ||
t.deepEqual(src_1.addEntry(bundle.slice(0, 2), { | ||
length: 1, | ||
address: addresses[1], | ||
value: 2, | ||
tag: 'TAG', | ||
timestamp: 1522219 | ||
}), bundle, 'addEntry() should add new entry and return correct trasnactions.'); | ||
}); | ||
ava_1["default"]('addEntry() throws error for entry with value and address with last trit !== 0.', function (t) { | ||
var invalidAddressTrits = converter_1.trytesToTrits(addresses[1]); | ||
invalidAddressTrits[HASH_TRITS_SIZE - 1] = 1; | ||
var invalidAddressTrytes = converter_1.tritsToTrytes(invalidAddressTrits); | ||
var entry = { | ||
length: 1, | ||
address: invalidAddressTrytes, | ||
value: 1, | ||
tag: 'TAG', | ||
timestamp: 1522219 | ||
}; | ||
t.is(t.throws(function () { return src_1.addEntry([], entry); }).message, errors_1.INVALID_ADDRESS_LAST_TRIT, 'addEntry() should throw error for entry with value and address with last trit !== 0.'); | ||
t.is(t.throws(function () { return src_1.addEntry([], __assign({}, entry, { value: -1 })); }).message, errors_1.INVALID_ADDRESS_LAST_TRIT, 'addEntry() should throw error for entry with value and address with last trit !== 0.'); | ||
}); | ||
ava_1["default"]('addTrytes() adds trytes and returns correct transactions.', function (t) { | ||
t.deepEqual(src_1.addTrytes(bundle, ['TRYTES', 'TRYTES', 'TRYTES']), bundle.map(function (transaction) { return (__assign({}, transaction, { signatureMessageFragment: 'TRYTES' + '9'.repeat(81 * 27 - 6) })); }), 'addEntry should add trytes and return correct transactions.'); | ||
}); | ||
ava_1["default"]('finalizeBundle() adds correct bundle hash.', function (t) { | ||
var bundleHash = 'VRGXKZDODWIVGFYFCCXJRNDCQJVYUVBRIWJXKFGBIEWUPHHTJLTKH99JW9OLJ9JCIXCEIRRXJKLWOBDZZ'; | ||
var incrObsoleteTag = 'ZUH'.concat('9'.repeat(24)); | ||
var expected = bundle.map(function (transaction, i) { return (__assign({}, transaction, { obsoleteTag: i === 0 ? incrObsoleteTag : transaction.obsoleteTag, bundle: bundleHash })); }); | ||
t.deepEqual(src_1.finalizeBundle(bundle), expected, 'finalizeBundle() should add correct bundle hash.'); | ||
}); | ||
riteway_1.describe('createBundle(entries: ReadonlyArray<Partial<BundleEntry>>)', function (assert) { return __awaiter(_this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
assert({ | ||
given: 'entries with signatureOrMessage of length that is not multiple of fragment length', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.createBundle, [{ signatureOrMessage: new Int8Array(transaction_1.SIGNATURE_OR_MESSAGE_LENGTH - 1) }]), | ||
expected: new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entries with signatureOrMessage of 0 length', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.createBundle, [{ signatureOrMessage: new Int8Array(0) }]), | ||
expected: new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entries with address of illegal length (< exact length)', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.createBundle, [{ address: new Int8Array(transaction_1.ADDRESS_LENGTH - 1) }]), | ||
expected: new RangeError(errors.ILLEGAL_ADDRESS_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entries with address of illegal length (> exact length)', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.createBundle, [{ address: new Int8Array(transaction_1.ADDRESS_LENGTH + 1) }]), | ||
expected: new RangeError(errors.ILLEGAL_ADDRESS_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entries with value of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.createBundle, [{ value: new Int8Array(transaction_1.VALUE_LENGTH + 1) }]), | ||
expected: new RangeError(errors.ILLEGAL_VALUE_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entries with obsoleteTag of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.createBundle, [{ obsoleteTag: new Int8Array(transaction_1.OBSOLETE_TAG_LENGTH + 1) }]), | ||
expected: new RangeError(errors.ILLEGAL_OBSOLETE_TAG_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entries with issuanceTimestamp of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.createBundle, [{ issuanceTimestamp: new Int8Array(transaction_1.ISSUANCE_TIMESTAMP_LENGTH + 1) }]), | ||
expected: new RangeError(errors.ILLEGAL_ISSUANCE_TIMESTAMP_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entries with tag of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.createBundle, [{ tag: new Int8Array(transaction_1.TAG_LENGTH + 1) }]), | ||
expected: new RangeError(errors.ILLEGAL_TAG_LENGTH) | ||
}); | ||
assert({ | ||
given: 'valid entries', | ||
should: 'produce correct interim bundle', | ||
actual: actualInterimBundle, | ||
expected: samples_1.interimBundle | ||
}); | ||
assert({ | ||
given: 'empty entries', | ||
should: 'produce empty interim bundle', | ||
actual: src_1.createBundle([{}]), | ||
expected: new Int8Array(transaction_1.TRANSACTION_LENGTH) | ||
}); | ||
assert({ | ||
given: 'no entries', | ||
should: 'produce no bundle', | ||
actual: src_1.createBundle(), | ||
expected: new Int8Array(0) | ||
}); | ||
return [2 /*return*/]; | ||
}); | ||
}); }); | ||
riteway_1.describe('addEntry(bundle: Int8Array, entry: Partial<BundleEntry>)', function (assert) { return __awaiter(_this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
assert({ | ||
given: 'given bundle of length that is not multiple of transaction length', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.addEntry, new Int8Array(transaction_1.TRANSACTION_LENGTH - 1), entries[0]), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entry with signatureOrMessage of length that is not multiple of fragment length', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.addEntry, new Int8Array(0), { | ||
signatureOrMessage: new Int8Array(transaction_1.SIGNATURE_OR_MESSAGE_LENGTH - 1) | ||
}), | ||
expected: new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entry with signatureOrMessage of 0 length', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.addEntry, new Int8Array(0), { signatureOrMessage: new Int8Array(0) }), | ||
expected: new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entry with address of illegal length (< exact length)', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.addEntry, new Int8Array(0), { address: new Int8Array(transaction_1.ADDRESS_LENGTH - 1) }), | ||
expected: new RangeError(errors.ILLEGAL_ADDRESS_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entry with address of illegal length (> exact length)', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.addEntry, new Int8Array(0), { address: new Int8Array(transaction_1.ADDRESS_LENGTH + 1) }), | ||
expected: new RangeError(errors.ILLEGAL_ADDRESS_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entry with value of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.addEntry, new Int8Array(0), { value: new Int8Array(transaction_1.VALUE_LENGTH + 1) }), | ||
expected: new RangeError(errors.ILLEGAL_VALUE_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entry with obsoleteTag of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.addEntry, new Int8Array(0), { | ||
obsoleteTag: new Int8Array(transaction_1.OBSOLETE_TAG_LENGTH + 1) | ||
}), | ||
expected: new RangeError(errors.ILLEGAL_OBSOLETE_TAG_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entry with issuanceTimestamp of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.addEntry, new Int8Array(0), { | ||
issuanceTimestamp: new Int8Array(transaction_1.ISSUANCE_TIMESTAMP_LENGTH + 1) | ||
}), | ||
expected: new RangeError(errors.ILLEGAL_ISSUANCE_TIMESTAMP_LENGTH) | ||
}); | ||
assert({ | ||
given: 'entry with tag of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.addEntry, new Int8Array(0), __assign({}, entries[0], { tag: new Int8Array(transaction_1.TAG_LENGTH + 1) })), | ||
expected: new RangeError(errors.ILLEGAL_TAG_LENGTH) | ||
}); | ||
assert({ | ||
given: 'valid entry', | ||
should: 'produce correct interim bundle', | ||
actual: src_1.addEntry(actualInterimBundlePartial, entries[entries.length - 1]), | ||
expected: samples_1.interimBundle | ||
}); | ||
assert({ | ||
given: 'empty entry', | ||
should: 'do nothing', | ||
actual: src_1.addEntry(new Int8Array(0), {}), | ||
expected: new Int8Array(transaction_1.TRANSACTION_LENGTH) | ||
}); | ||
return [2 /*return*/]; | ||
}); | ||
}); }); | ||
riteway_1.describe('finalizeBundle(bundle: Int8Array)', function (assert) { return __awaiter(_this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
assert({ | ||
given: 'given bundle of 0 length', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.finalizeBundle, new Int8Array(0)), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH) | ||
}); | ||
assert({ | ||
given: 'given bundle of length that is not multiple of transaction length', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.finalizeBundle, new Int8Array(transaction_1.TRANSACTION_LENGTH - 1)), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH) | ||
}); | ||
assert({ | ||
given: 'valid interim bundle', | ||
should: 'produce correct final bundle', | ||
actual: actualFinalBundle, | ||
expected: samples_1.finalBundle | ||
}); | ||
assert({ | ||
given: 'insecure bundle (normalized bundle hash contains value 13)', | ||
should: 'increment obsolete tag and recompute bundle hash', | ||
actual: { | ||
insecureInterimBundle: signing_1.normalizedBundle(bundleHash(actualInterimBundle)).indexOf(signing_1.MAX_TRYTE_VALUE /* 13 */) > -1, | ||
secureFinalBundle: signing_1.normalizedBundle(transaction_1.bundle(actualFinalBundle)).indexOf(signing_1.MAX_TRYTE_VALUE /* 13 */) === -1, | ||
obsoleteTag: transaction_1.obsoleteTag(actualFinalBundle) | ||
}, | ||
expected: { | ||
insecureInterimBundle: true, | ||
secureFinalBundle: true, | ||
obsoleteTag: converter_1.trytesToTrits('EF9999999999999999999999999') | ||
} | ||
}); | ||
return [2 /*return*/]; | ||
}); | ||
}); }); | ||
riteway_1.describe('addSignatureOrMessage(bundle: Int8Array, signatureOrMessage: Int8Array, index: number)', function (assert) { return __awaiter(_this, void 0, void 0, function () { | ||
var _a, _b, _c; | ||
return __generator(this, function (_d) { | ||
switch (_d.label) { | ||
case 0: | ||
assert({ | ||
given: 'given bundle of 0 length', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.addSignatureOrMessage, new Int8Array(0), new Int8Array(transaction_1.SIGNATURE_OR_MESSAGE_LENGTH), 0), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH) | ||
}); | ||
assert({ | ||
given: 'given bundle of length that is not multiple of transaction length', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.addSignatureOrMessage, new Int8Array(transaction_1.TRANSACTION_LENGTH - 1), new Int8Array(transaction_1.SIGNATURE_OR_MESSAGE_LENGTH), 0), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH) | ||
}); | ||
assert({ | ||
given: 'given signatureOrMessage of length that is not multiple of fragment length', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.addSignatureOrMessage, new Int8Array(transaction_1.TRANSACTION_LENGTH), new Int8Array(transaction_1.SIGNATURE_OR_MESSAGE_LENGTH - 1), 0), | ||
expected: new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH) | ||
}); | ||
assert({ | ||
given: 'given signatureOrMessage of 0 length', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.addSignatureOrMessage, new Int8Array(transaction_1.TRANSACTION_LENGTH), new Int8Array(0), 0), | ||
expected: new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH) | ||
}); | ||
assert({ | ||
given: 'index = undefined', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.addSignatureOrMessage, new Int8Array(transaction_1.TRANSACTION_LENGTH), new Int8Array(transaction_1.SIGNATURE_OR_MESSAGE_LENGTH), undefined), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_INDEX) | ||
}); | ||
assert({ | ||
given: 'index = NaN', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.addSignatureOrMessage, new Int8Array(transaction_1.TRANSACTION_LENGTH), new Int8Array(transaction_1.SIGNATURE_OR_MESSAGE_LENGTH), NaN), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_INDEX) | ||
}); | ||
assert({ | ||
given: 'index = null', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.addSignatureOrMessage, new Int8Array(transaction_1.TRANSACTION_LENGTH), new Int8Array(transaction_1.SIGNATURE_OR_MESSAGE_LENGTH), null), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_INDEX) | ||
}); | ||
assert({ | ||
given: 'index = Infinity', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.addSignatureOrMessage, new Int8Array(transaction_1.TRANSACTION_LENGTH), new Int8Array(transaction_1.SIGNATURE_OR_MESSAGE_LENGTH), Infinity), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_INDEX) | ||
}); | ||
assert({ | ||
given: 'index = "0" (string)', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.addSignatureOrMessage, new Int8Array(transaction_1.TRANSACTION_LENGTH), new Int8Array(transaction_1.SIGNATURE_OR_MESSAGE_LENGTH), '0'), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_INDEX) | ||
}); | ||
assert({ | ||
given: 'out-of-range index (< 0)', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.addSignatureOrMessage, new Int8Array(transaction_1.TRANSACTION_LENGTH), new Int8Array(transaction_1.SIGNATURE_OR_MESSAGE_LENGTH), -1), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_INDEX) | ||
}); | ||
assert({ | ||
given: 'out-of-range index (> 0)', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.addSignatureOrMessage, new Int8Array(transaction_1.TRANSACTION_LENGTH * 3), new Int8Array(transaction_1.SIGNATURE_OR_MESSAGE_LENGTH * 2), 2), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_INDEX) | ||
}); | ||
_a = assert; | ||
_b = { | ||
given: 'valid final bundle', | ||
should: 'produce correct signed bundle' | ||
}; | ||
_c = converter_1.tritsToTrytes; | ||
return [4 /*yield*/, actualFinalSignedBundle]; | ||
case 1: | ||
_a.apply(void 0, [(_b.actual = _c.apply(void 0, [_d.sent()]), | ||
_b.expected = converter_1.tritsToTrytes(samples_1.finalSignedBundle), | ||
_b)]); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); }); | ||
riteway_1.describe('valueSum(buffer: Int8Array, offset: number, length: number): number', function (assert) { return __awaiter(_this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
assert({ | ||
given: 'buffer of length that is not multiple of transaction length', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH - 1), 0, transaction_1.TRANSACTION_LENGTH), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH) | ||
}); | ||
assert({ | ||
given: 'offset that is not multiple of transaction length', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH), 1, transaction_1.TRANSACTION_LENGTH), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
}); | ||
assert({ | ||
given: 'length that is not multiple of transaction length', | ||
should: 'throw RangeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH), 0, transaction_1.TRANSACTION_LENGTH - 1), | ||
expected: new RangeError(errors.ILLEGAL_BUNDLE_LENGTH) | ||
}); | ||
assert({ | ||
given: 'offset = undefined', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH), undefined, transaction_1.TRANSACTION_LENGTH), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
}); | ||
assert({ | ||
given: 'offset = NaN', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH), NaN, transaction_1.TRANSACTION_LENGTH), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
}); | ||
assert({ | ||
given: 'offset = null', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH), null, transaction_1.TRANSACTION_LENGTH), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
}); | ||
assert({ | ||
given: 'offset = Infinity', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH), Infinity, transaction_1.TRANSACTION_LENGTH), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
}); | ||
assert({ | ||
given: 'offset = "0" (string)', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH), '0', transaction_1.TRANSACTION_LENGTH), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
}); | ||
assert({ | ||
given: 'offset = 0.1', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH), 0.1, transaction_1.TRANSACTION_LENGTH), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
}); | ||
assert({ | ||
given: 'length = undefined', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH), 0, undefined), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
}); | ||
assert({ | ||
given: 'length = NaN', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH), 0, NaN), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
}); | ||
assert({ | ||
given: 'length = null', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH), 0, null), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
}); | ||
assert({ | ||
given: 'length = Infinity', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH), 0, Infinity), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
}); | ||
assert({ | ||
given: 'length = "0" (string)', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH), 0, '0'), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
}); | ||
assert({ | ||
given: 'length = 0.1', | ||
should: 'throw TypeError', | ||
actual: riteway_1.Try(src_1.valueSum, new Int8Array(transaction_1.TRANSACTION_LENGTH), 0, 0.1), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
}); | ||
assert({ | ||
given: 'valid buffer', | ||
should: 'calculate value sum', | ||
actual: (function () { | ||
var buffer = new Int8Array(3 * transaction_1.TRANSACTION_LENGTH).fill(0); | ||
var offset = transaction_1.TRANSACTION_LENGTH; | ||
var length = transaction_1.TRANSACTION_LENGTH * 2; | ||
buffer.set(converter_1.valueToTrits(10000), transaction_1.VALUE_OFFSET); | ||
buffer.set(converter_1.valueToTrits(-9), offset + transaction_1.VALUE_OFFSET); | ||
buffer.set(converter_1.valueToTrits(10), offset + transaction_1.TRANSACTION_LENGTH + transaction_1.VALUE_OFFSET); | ||
return src_1.valueSum(buffer, offset, length); | ||
})(), | ||
expected: 1 | ||
}); | ||
return [2 /*return*/]; | ||
}); | ||
}); }); | ||
//# sourceMappingURL=bundle.test.js.map |
@@ -6,2 +6,3 @@ "use strict"; | ||
exports.ILLEGAL_SUBSEED_LENGTH = 'Illegal subseed length'; | ||
exports.ILLEGAL_NUMBER_OF_FRAGMENTS = 'Illegal number of fragments'; | ||
exports.ILLEGAL_KEY_LENGTH = 'Illegal key length'; | ||
@@ -15,2 +16,30 @@ exports.ILLEGAL_DIGESTS_LENGTH = 'Illegal digests length'; | ||
exports.ILLEGAL_TRYTE_CONVERSION_INPUT = 'Illegal conversion input. Expected trytes string or integer.'; | ||
exports.ILLEGAL_MIN_WEIGHT_MAGNITUDE = 'Illegal minWeightMagnitude value.'; | ||
exports.ILLEGAL_ADDRESS_LAST_TRIT = 'Illegal address. Last trit must be 0.'; | ||
exports.ILLEGAL_ADDRESS_LENGTH = 'Illegal address length.'; | ||
exports.ILLEGAL_BUNDLE_LENGTH = 'Illegal bundle hash length.'; | ||
exports.ILLEGAL_OBSOLETE_TAG_LENGTH = 'Illegal obsoleteTag length.'; | ||
exports.ILLEGAL_SIGNATURE_OR_MESSAGE = 'Illegal signature or message.'; | ||
exports.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH = 'Illegal signatureOrMessage length.'; | ||
exports.ILLEGAL_TAG_LENGTH = 'Illegal tag length.'; | ||
exports.ILLEGAL_ISSUANCE_TIMESTAMP = 'Illegal issuance timestamp'; | ||
exports.ILLEGAL_ISSUANCE_TIMESTAMP_LENGTH = 'Illegal issuanceTimestamp length.'; | ||
exports.ILLEGAL_VALUE_LENGTH = 'Illegal value length.'; | ||
exports.ILLEGAL_TRANSACTION_FIELD_OFFSET = 'Illegal transaction field offset.'; | ||
exports.ILLEGAL_TRANSACTION_FIELD_LENGTH = 'Illegal transaction field length.'; | ||
exports.ILLEGAL_LENGTH_OR_OFFSET = 'Illegal length or offset.'; | ||
exports.ILLEGAL_TRANSACTION_BUFFER = 'Illegal transaction buffer. Expected `Int8Array`.'; | ||
exports.ILLEGAL_TRANSACTION_BUFFER_LENGTH = 'Illegal transaction buffer length.'; | ||
exports.ILLEGAL_TRANSACTION_OFFSET = 'Illegal transaction offset.'; | ||
exports.ILLEGAL_TRANSACTION_LENGTH = 'Illegal transaction length.'; | ||
exports.ILLEGAL_TRANSACTION_ORDER = 'Illegal transaction order.'; | ||
exports.ILLEGAL_TRANSACTION_INDEX = 'Illegal transaction index.'; | ||
exports.ILLEGAL_SEED_LENGTH = 'Illegal seed length. Expected length of 243 trits.'; | ||
exports.ILLEGAL_KEY_INDEX = 'Illegal key index.'; | ||
exports.ILLEGAL_CDA_LENGTH = 'Illegal cda length.'; | ||
exports.ILLEGAL_BATCH = 'Illegal batch.'; | ||
exports.CDA_ALREADY_IN_STORE = 'CDA is already in store.'; | ||
exports.ILLEGAL_PERSISTENCE_ID = 'Illegal persistence id.'; | ||
exports.ILLEGAL_PERSISTENCE_PATH = 'Illegal persistence path.'; | ||
exports.ILLEGAL_PADDING_LENGTH = 'Illegal padding length. Input value length exceeds padding length.'; | ||
exports.INCONSISTENT_SUBTANGLE = 'Inconsistent subtangle'; | ||
@@ -60,3 +89,2 @@ exports.INSUFFICIENT_BALANCE = 'Insufficient balance'; | ||
exports.INVALID_DELAY = 'Invalid delay.'; | ||
exports.INVALID_ADDRESS_LAST_TRIT = 'Invalid address: Last trit of address of value transaction must be 0.'; | ||
//# sourceMappingURL=errors.js.map |
{ | ||
"name": "@iota/bundle", | ||
"version": "1.0.0-beta.11", | ||
"version": "1.0.0-beta.12", | ||
"description": "Utilities for generating and signing bundles", | ||
@@ -12,4 +12,5 @@ "main": "./out/bundle/src/index.js", | ||
"prepare": "tsc", | ||
"test": "tsc && nyc ava", | ||
"test-ci": "nyc ava", | ||
"test": "tsc && nyc riteway out/bundle/test/bundle.test.js", | ||
"test-ci": "nyc riteway out/bundle/test/bundle.test.js", | ||
"watch": "watch 'clear && npm run -s test'", | ||
"lint": "tslint --project .", | ||
@@ -23,27 +24,19 @@ "docs": "tsc && jsdoc2md --no-cache --plugin dmd-clear -t README_tpl.hbs --files './out/**/*.js' > README.md" | ||
], | ||
"ava": { | ||
"files": "out/bundle/test/*.test.js", | ||
"failFast": true, | ||
"failWithoutAssertions": false, | ||
"compileEnhancements": false, | ||
"verbose": true | ||
}, | ||
"nyc": { | ||
"watermarks": { | ||
"functions": [ | ||
80, | ||
95 | ||
100, | ||
100 | ||
], | ||
"branches": [ | ||
80, | ||
95 | ||
100, | ||
100 | ||
], | ||
"statements": [ | ||
80, | ||
95 | ||
100, | ||
100 | ||
] | ||
}, | ||
"include": [ | ||
"out/*/src/*.js", | ||
"out/*/test/*.js" | ||
"out/*/src/*.js" | ||
] | ||
@@ -66,10 +59,17 @@ }, | ||
"type": "git", | ||
"url": "https://github.com/iotaledger/iota.js.git/tree/develop/packages/crypto" | ||
"url": "https://github.com/iotaledger/iota.js/tree/next/packages/bundle" | ||
}, | ||
"dependencies": { | ||
"@iota/converter": "^1.0.0-beta.11", | ||
"@iota/kerl": "^1.0.0-beta.11", | ||
"@iota/pad": "^1.0.0-beta.11", | ||
"@iota/signing": "^1.0.0-beta.11" | ||
} | ||
"@iota/converter": "^1.0.0-beta.12", | ||
"@iota/kerl": "^1.0.0-beta.12", | ||
"@iota/signing": "^1.0.0-beta.12", | ||
"@iota/transaction": "^1.0.0-beta.12", | ||
"@types/warning": "^3.0.0", | ||
"warning": "^4.0.3" | ||
}, | ||
"devDependencies": { | ||
"riteway": "^6.0.3", | ||
"watch": "^1.0.2" | ||
}, | ||
"gitHead": "0777d33f7a01a2751b570774e917ce5e2485cd40" | ||
} |
396
src/index.ts
/** @module bundle */ | ||
import { trits, trytes } from '@iota/converter' | ||
import { tritsToValue } from '@iota/converter' | ||
import Kerl from '@iota/kerl' | ||
import { padTag, padTrits, padTrytes } from '@iota/pad' | ||
import { add, normalizedBundle } from '@iota/signing' | ||
import { INVALID_ADDRESS_LAST_TRIT } from '../../errors' | ||
import { increment, MAX_TRYTE_VALUE, normalizedBundle } from '@iota/signing' | ||
import * as errors from '../../errors' | ||
import '../../typed-array' | ||
import { | ||
Bundle, | ||
Hash, | ||
Transaction, // tslint:disable-line no-unused-variable | ||
Trytes, | ||
} from '../../types' | ||
ADDRESS_LENGTH, | ||
ADDRESS_OFFSET, | ||
BUNDLE_LENGTH, | ||
BUNDLE_OFFSET, | ||
CURRENT_INDEX_OFFSET, | ||
isMultipleOfTransactionLength, | ||
ISSUANCE_TIMESTAMP_LENGTH, | ||
ISSUANCE_TIMESTAMP_OFFSET, | ||
LAST_INDEX_LENGTH, | ||
LAST_INDEX_OFFSET, | ||
lastIndex, | ||
OBSOLETE_TAG_LENGTH, | ||
OBSOLETE_TAG_OFFSET, | ||
SIGNATURE_OR_MESSAGE_LENGTH, | ||
SIGNATURE_OR_MESSAGE_OFFSET, | ||
TAG_LENGTH, | ||
TAG_OFFSET, | ||
TRANSACTION_ESSENCE_LENGTH, | ||
TRANSACTION_LENGTH, | ||
transactionEssence, | ||
value as transactionValue, | ||
VALUE_LENGTH, | ||
VALUE_OFFSET, | ||
} from '@iota/transaction' | ||
const HASH_TRITS_SIZE = 243 | ||
const NULL_HASH_TRYTES = '9'.repeat(81) | ||
const NULL_TAG_TRYTES = '9'.repeat(27) | ||
const NULL_NONCE_TRYTES = '9'.repeat(27) | ||
const NULL_SIGNATURE_MESSAGE_FRAGMENT_TRYTES = '9'.repeat(2187) | ||
export interface BundleEntry { | ||
readonly length: number | ||
readonly address: Hash | ||
readonly value: number | ||
readonly tag: string | ||
readonly timestamp: number | ||
readonly signatureMessageFragments: ReadonlyArray<Trytes> | ||
readonly signatureOrMessage: Int8Array | ||
// readonly extraDataDigest: Int8Array | ||
readonly address: Int8Array | ||
readonly value: Int8Array | ||
readonly obsoleteTag: Int8Array | ||
readonly issuanceTimestamp: Int8Array | ||
readonly tag: Int8Array | ||
} | ||
export { Transaction, Bundle } | ||
const getEntryWithDefaults = (entry: Partial<BundleEntry>): BundleEntry => ({ | ||
length: entry.length || 1, | ||
address: entry.address || NULL_HASH_TRYTES, | ||
value: entry.value || 0, | ||
tag: entry.tag || NULL_TAG_TRYTES, | ||
timestamp: entry.timestamp || Math.floor(Date.now() / 1000), | ||
signatureMessageFragments: entry.signatureMessageFragments | ||
? entry.signatureMessageFragments.map(padTrytes(2187)) | ||
: Array(entry.length || 1).fill(NULL_SIGNATURE_MESSAGE_FRAGMENT_TRYTES), | ||
}) | ||
/** | ||
@@ -49,8 +50,8 @@ * Creates a bundle with given transaction entries. | ||
* | ||
* @param {BundleEntry[]} entries - Entries of single or multiple transactions with the same address | ||
* @param {BundleEntry[]} [entries=[]] - Entries of single or multiple transactions with the same address | ||
* | ||
* @return {Transaction[]} List of transactions in the bundle | ||
* @return {Int8Array[]} List of transactions in the bundle | ||
*/ | ||
export const createBundle = (entries: ReadonlyArray<Partial<BundleEntry>> = []): Bundle => | ||
entries.reduce((bundle: Bundle, entry) => addEntry(bundle, entry), []) | ||
export const createBundle = (entries: ReadonlyArray<Partial<BundleEntry>> = []): Int8Array => | ||
entries.reduce((bundle, entry) => addEntry(bundle, entry), new Int8Array(0)) | ||
@@ -62,123 +63,250 @@ /** | ||
* | ||
* @param {Transaction[]} transactions - List of transactions currently in the bundle | ||
* @param {object} entry - Entry of a single or multiple transactions with the same address. | ||
* @param {Int8Array} entry.address - Address. | ||
* @param {Int8Array} entry.value - Value to transfer in iotas. | ||
* @param {Int8Array} [entry.signatureOrMessage] - Signature or message fragment(s). | ||
* @param {Int8Array} [entry.timestamp] - Issuance timestamp (in seconds). | ||
* @param {Int8Array} [entry.tag] - Optional Tag, **Deprecated**. | ||
* @param {Int8Array} bundle - Bundle buffer. | ||
* | ||
* @param {object} entry - Entry of a single or multiple transactions with the same address | ||
* @param {number} [entry.length = 1] - Entry length, which indicates how many transactions in the bundle it will occupy | ||
* @param {Hash} [entry.address] - Address, defaults to all-9s | ||
* @param {number} [entry.value = 0] - Value to transfer in iotas | ||
* @param {Trytes[]} [entry.signatureMessageFragments] - List of signature message fragments, defaults to all-9s | ||
* @param {number} [entry.timestamp] - Transaction timestamp, defaults to `Math.floor(Date.now() / 1000)` | ||
* @param {string} [entry.tag] - Optional Tag, defaults to null tag (all-9s) | ||
* | ||
* @return {Transaction[]} List of transactions in the updated bundle | ||
* @return {Int8Array} Bundle copy with new entries. | ||
*/ | ||
export const addEntry = (transactions: Bundle, entry: Partial<BundleEntry>): Bundle => { | ||
const entryWithDefaults = getEntryWithDefaults(entry) | ||
const { length, address, value, timestamp, signatureMessageFragments } = entryWithDefaults | ||
const lastIndex = transactions.length - 1 + length | ||
const tag = padTag(entryWithDefaults.tag) | ||
const obsoleteTag = tag | ||
export const addEntry = (bundle: Int8Array, entry: Partial<BundleEntry>): Int8Array => { | ||
const { | ||
signatureOrMessage, | ||
// extraDataDigest, | ||
address, | ||
value, | ||
obsoleteTag, | ||
issuanceTimestamp, | ||
tag, | ||
} = entry | ||
if (value !== 0 && trits(address)[HASH_TRITS_SIZE - 1] !== 0) { | ||
throw new Error(INVALID_ADDRESS_LAST_TRIT) | ||
/* | ||
warning( | ||
signatureOrMessage && !isNullTrits(signatureOrMessage), | ||
'Deprecation warning: \n' + | ||
' - Use of "signatureOrMessage" field before bundle finalization is deprecated and will be removed in v1.0.0. \n' | ||
) | ||
warning( | ||
obsoleteTag && !isNullTrits(obsoleteTag), | ||
'Deprecation warning: \n' + | ||
' - "obseleteTag" field is deprecated and will be removed in implementation of final design. \n' + | ||
' - Use of "obsoleteTag" or "tag" field before bundle finalization is deprecated and will be removed in v1.0.0. \n' | ||
) | ||
warning( | ||
tag && !isNullTrits(tag), | ||
'Deprecation warning: \n' + | ||
' - Use of "tag" field before bundle finalization is deprecated and will be removed in v1.0.0. \n' | ||
) | ||
*/ | ||
if (!isMultipleOfTransactionLength(bundle.length)) { | ||
throw new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH) | ||
} | ||
return transactions.map(transaction => ({ ...transaction, lastIndex })).concat( | ||
Array(length) | ||
.fill(null) | ||
.map((_, i) => ({ | ||
address, | ||
value: i === 0 ? value : 0, | ||
tag, | ||
obsoleteTag, | ||
currentIndex: transactions.length + i, | ||
lastIndex, | ||
timestamp, | ||
signatureMessageFragment: signatureMessageFragments[i], | ||
trunkTransaction: NULL_HASH_TRYTES, | ||
branchTransaction: NULL_HASH_TRYTES, | ||
attachmentTimestamp: 0, | ||
attachmentTimestampLowerBound: 0, | ||
attachmentTimestampUpperBound: 0, | ||
bundle: NULL_HASH_TRYTES, | ||
nonce: NULL_NONCE_TRYTES, | ||
hash: NULL_HASH_TRYTES, | ||
})) | ||
) | ||
if ( | ||
signatureOrMessage && | ||
(signatureOrMessage.length === 0 || signatureOrMessage.length % SIGNATURE_OR_MESSAGE_LENGTH !== 0) | ||
) { | ||
throw new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH) | ||
} | ||
if (address && address.length !== ADDRESS_LENGTH) { | ||
throw new RangeError(errors.ILLEGAL_ADDRESS_LENGTH) | ||
} | ||
if (value && value.length > VALUE_LENGTH) { | ||
throw new RangeError(errors.ILLEGAL_VALUE_LENGTH) | ||
} | ||
if (obsoleteTag && obsoleteTag.length > OBSOLETE_TAG_LENGTH) { | ||
throw new RangeError(errors.ILLEGAL_OBSOLETE_TAG_LENGTH) | ||
} | ||
if (issuanceTimestamp && issuanceTimestamp.length > ISSUANCE_TIMESTAMP_LENGTH) { | ||
throw new RangeError(errors.ILLEGAL_ISSUANCE_TIMESTAMP_LENGTH) | ||
} | ||
if (tag && tag.length > TAG_LENGTH) { | ||
throw new RangeError(errors.ILLEGAL_TAG_LENGTH) | ||
} | ||
const signatureOrMessageCopy = signatureOrMessage | ||
? signatureOrMessage.slice() | ||
: new Int8Array(SIGNATURE_OR_MESSAGE_LENGTH) | ||
const numberOfFragments = signatureOrMessageCopy.length / SIGNATURE_OR_MESSAGE_LENGTH | ||
const bundleCopy = new Int8Array(bundle.length + numberOfFragments * TRANSACTION_LENGTH) | ||
const currentIndexBuffer = bundle.length > 0 ? increment(lastIndex(bundle)) : new Int8Array(LAST_INDEX_LENGTH) | ||
const lastIndexBuffer = currentIndexBuffer.slice() | ||
let fragmentIndex = 0 | ||
bundleCopy.set(bundle.slice()) | ||
// Create and append transactions to the bundle. | ||
for (let offset = bundle.length; offset < bundleCopy.length; offset += TRANSACTION_LENGTH) { | ||
const signatureOrMessageCopyFragment = signatureOrMessageCopy.subarray( | ||
fragmentIndex * SIGNATURE_OR_MESSAGE_LENGTH, | ||
(fragmentIndex + 1) * SIGNATURE_OR_MESSAGE_LENGTH | ||
) | ||
bundleCopy.set(signatureOrMessageCopyFragment, offset + SIGNATURE_OR_MESSAGE_OFFSET) | ||
if (address) { | ||
bundleCopy.set(address, offset + ADDRESS_OFFSET) | ||
} | ||
if (value && fragmentIndex === 0) { | ||
bundleCopy.set(value, offset + VALUE_OFFSET) | ||
} | ||
if (obsoleteTag) { | ||
bundleCopy.set(obsoleteTag, offset + OBSOLETE_TAG_OFFSET) | ||
} | ||
if (issuanceTimestamp) { | ||
bundleCopy.set(issuanceTimestamp, offset + ISSUANCE_TIMESTAMP_OFFSET) | ||
} | ||
bundleCopy.set(currentIndexBuffer, offset + CURRENT_INDEX_OFFSET) | ||
if (tag) { | ||
bundleCopy.set(tag, offset + TAG_OFFSET) | ||
} | ||
lastIndexBuffer.set(currentIndexBuffer.slice()) | ||
currentIndexBuffer.set(increment(currentIndexBuffer)) | ||
fragmentIndex++ | ||
} | ||
for (let offset = LAST_INDEX_OFFSET; offset < bundleCopy.length; offset += TRANSACTION_LENGTH) { | ||
bundleCopy.set(lastIndexBuffer, offset) | ||
} | ||
return bundleCopy | ||
} | ||
/** | ||
* Adds signature message fragments to transactions in a bundle starting at offset. | ||
* Finalizes a bundle by calculating the bundle hash. | ||
* | ||
* @method addTrytes | ||
* @method finalizeBundle | ||
* | ||
* @param {Transaction[]} transactions - List of transactions in the bundle | ||
* @param {Int8Array} bundle - Bundle transaction trits | ||
* | ||
* @param {Trytes[]} fragments - List of signature message fragments to add | ||
* | ||
* @param {number} [offset = 0] - Optional offset to start appending signature message fragments | ||
* | ||
* @return {Transaction[]} List of transactions in the updated bundle | ||
* @return {Int8Array} List of transactions in the finalized bundle | ||
*/ | ||
export const addTrytes = (transactions: Bundle, fragments: ReadonlyArray<Trytes>, offset = 0): Bundle => | ||
transactions.map( | ||
(transaction, i) => | ||
i >= offset && i < offset + fragments.length | ||
? { | ||
...transaction, | ||
signatureMessageFragment: padTrytes(27 * 81)(fragments[i - offset] || ''), | ||
} | ||
: transaction | ||
) | ||
export const finalizeBundle = (bundle: Int8Array): Int8Array => { | ||
if (!isMultipleOfTransactionLength(bundle.length)) { | ||
throw new Error(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH) | ||
} | ||
const sponge = new Kerl() | ||
const bundleCopy = bundle.slice() | ||
const bundleHash = new Int8Array(BUNDLE_LENGTH) | ||
// This block recomputes bundle hash by incrementing `obsoleteTag` field of first transaction in the bundle. | ||
// Normalized bundle should NOT contain value `13`. | ||
while (true) { | ||
// Absorb essence trits to squeeze bundle hash. | ||
for (let offset = 0; offset < bundle.length; offset += TRANSACTION_LENGTH) { | ||
sponge.absorb(transactionEssence(bundleCopy, offset), 0, TRANSACTION_ESSENCE_LENGTH) | ||
} | ||
// Set new bundle hash value. | ||
sponge.squeeze(bundleHash, 0, BUNDLE_LENGTH) | ||
// Stop mutation if essence results to secure bundle. | ||
if (normalizedBundle(bundleHash).indexOf(MAX_TRYTE_VALUE /* 13 */) === -1) { | ||
// Essence results to secure bundle. | ||
break | ||
} | ||
// Essence results to insecure bundle. (Normalized bundle hash contains value `13`.) | ||
bundleCopy.set( | ||
increment(bundleCopy.subarray(OBSOLETE_TAG_OFFSET, OBSOLETE_TAG_OFFSET + OBSOLETE_TAG_LENGTH)), | ||
OBSOLETE_TAG_OFFSET | ||
) | ||
sponge.reset() | ||
} | ||
// Set bundle field of each transaction. | ||
for (let offset = BUNDLE_OFFSET; offset < bundle.length; offset += TRANSACTION_LENGTH) { | ||
bundleCopy.set(bundleHash, offset) | ||
} | ||
return bundleCopy | ||
} | ||
/** | ||
* Finalizes a bundle by calculating the bundle hash. | ||
* Adds signature message fragments to transactions in a bundle starting at offset. | ||
* | ||
* @method finalizeBundle | ||
* @method addSignatureOrMessage | ||
* | ||
* @param {Transaction[]} transactions - List of transactions in the bundle | ||
* @param {Int8Array} bundle - Bundle buffer. | ||
* @param {Int8Array} signatureOrMessage - Signature or message to add. | ||
* @param {number} index - Transaction index as entry point for signature or message fragments. | ||
* | ||
* @return {Transaction[]} List of transactions in the finalized bundle | ||
* @return {Int8Array} List of transactions in the updated bundle | ||
*/ | ||
export const finalizeBundle = (transactions: Bundle): Bundle => { | ||
let validBundle: boolean = false | ||
export const addSignatureOrMessage = (bundle: Int8Array, signatureOrMessage: Int8Array, index: number): Int8Array => { | ||
if (!isMultipleOfTransactionLength(bundle.length)) { | ||
throw new Error(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH) | ||
} | ||
const valueTrits = transactions.map(tx => trits(tx.value)).map(padTrits(81)) | ||
const timestampTrits = transactions.map(tx => trits(tx.timestamp)).map(padTrits(27)) | ||
const currentIndexTrits = transactions.map(tx => trits(tx.currentIndex)).map(padTrits(27)) | ||
const lastIndexTrits = padTrits(27)(trits(transactions[0].lastIndex)) | ||
const obsoleteTagTrits = transactions.map(tx => trits(tx.obsoleteTag)).map(padTrits(81)) | ||
const bundleHashTrits = new Int8Array(Kerl.HASH_LENGTH) | ||
if (!Number.isInteger(index)) { | ||
throw new TypeError(errors.ILLEGAL_TRANSACTION_INDEX) | ||
} | ||
while (!validBundle) { | ||
const sponge = new Kerl() | ||
if (signatureOrMessage.length === 0 || signatureOrMessage.length % SIGNATURE_OR_MESSAGE_LENGTH !== 0) { | ||
throw new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH) | ||
} | ||
for (let i = 0; i < transactions.length; i++) { | ||
const essence = trits( | ||
transactions[i].address + | ||
trytes(valueTrits[i]) + | ||
trytes(obsoleteTagTrits[i]) + | ||
trytes(timestampTrits[i]) + | ||
trytes(currentIndexTrits[i]) + | ||
trytes(lastIndexTrits) | ||
) | ||
sponge.absorb(essence, 0, essence.length) | ||
} | ||
if (index < 0 || bundle.length - index - signatureOrMessage.length / SIGNATURE_OR_MESSAGE_LENGTH < 0) { | ||
throw new RangeError(errors.ILLEGAL_TRANSACTION_INDEX) | ||
} | ||
sponge.squeeze(bundleHashTrits, 0, Kerl.HASH_LENGTH) | ||
const bundleCopy = bundle.slice() | ||
const numberOfFragmentsToAdd = signatureOrMessage.length / SIGNATURE_OR_MESSAGE_LENGTH | ||
if (normalizedBundle(bundleHashTrits).indexOf(13) !== -1) { | ||
// Insecure bundle, increment obsoleteTag and recompute bundle hash | ||
obsoleteTagTrits[0] = add(obsoleteTagTrits[0], new Int8Array(1).fill(1)) | ||
} else { | ||
validBundle = true | ||
} | ||
for (let i = 0; i < numberOfFragmentsToAdd; i++) { | ||
bundleCopy.set( | ||
signatureOrMessage.slice(i * SIGNATURE_OR_MESSAGE_LENGTH, (i + 1) * SIGNATURE_OR_MESSAGE_LENGTH), | ||
(index + i) * TRANSACTION_LENGTH + SIGNATURE_OR_MESSAGE_OFFSET | ||
) | ||
} | ||
return transactions.map((transaction, i) => ({ | ||
...transaction, | ||
// overwrite obsoleteTag in first entry | ||
obsoleteTag: i === 0 ? trytes(obsoleteTagTrits[0]) : transaction.obsoleteTag, | ||
bundle: trytes(bundleHashTrits), | ||
})) | ||
return bundleCopy | ||
} | ||
export const valueSum = (buffer: Int8Array, offset: number, length: number): number => { | ||
if (!isMultipleOfTransactionLength(buffer.length)) { | ||
throw new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH) | ||
} | ||
if (!Number.isInteger(offset)) { | ||
throw new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
} | ||
if (!isMultipleOfTransactionLength(offset)) { | ||
throw new RangeError(errors.ILLEGAL_TRANSACTION_OFFSET) | ||
} | ||
if (!Number.isInteger(length)) { | ||
throw new TypeError(errors.ILLEGAL_BUNDLE_LENGTH) | ||
} | ||
if (!isMultipleOfTransactionLength(length)) { | ||
throw new RangeError(errors.ILLEGAL_BUNDLE_LENGTH) | ||
} | ||
let sum = 0 | ||
for (let bundleOffset = 0; bundleOffset < length; bundleOffset += TRANSACTION_LENGTH) { | ||
sum += tritsToValue(transactionValue(buffer, offset + bundleOffset)) | ||
} | ||
return sum | ||
} |
@@ -1,154 +0,539 @@ | ||
import { tritsToTrytes, trytesToTrits } from '@iota/converter' | ||
import test from 'ava' | ||
import { INVALID_ADDRESS_LAST_TRIT } from '../../errors' | ||
import { addEntry, addTrytes, createBundle, finalizeBundle } from '../src' | ||
import { tritsToTrytes, trytesToTrits, valueToTrits } from '@iota/converter' | ||
import Kerl from '@iota/kerl' | ||
import { MAX_TRYTE_VALUE, normalizedBundle, signatureFragments } from '@iota/signing' | ||
import { | ||
ADDRESS_LENGTH, | ||
bundle, | ||
BUNDLE_LENGTH, | ||
ISSUANCE_TIMESTAMP_LENGTH, | ||
OBSOLETE_TAG_LENGTH, | ||
obsoleteTag as obsoleteTagCopy, | ||
SIGNATURE_OR_MESSAGE_LENGTH, | ||
TAG_LENGTH, | ||
TRANSACTION_ESSENCE_LENGTH, | ||
TRANSACTION_LENGTH, | ||
transactionEssence, | ||
VALUE_LENGTH, | ||
VALUE_OFFSET, | ||
} from '@iota/transaction' | ||
import { addEntry, addSignatureOrMessage, createBundle, finalizeBundle, valueSum } from '../src' | ||
const HASH_TRITS_SIZE = 243 | ||
const NULL_HASH = '9'.repeat(81) | ||
const NULL_NONCE = '9'.repeat(27) | ||
const addresses = ['A'.repeat(81), 'B'.repeat(81)] | ||
const tag = 'TAG' + '9'.repeat(24) | ||
import { describe, Try } from 'riteway' | ||
import * as errors from '../../errors' | ||
const bundle = [ | ||
import { | ||
addresses, | ||
finalBundle as expectedFinalBundle, | ||
finalSignedBundle as expectedFinalSignedBundle, | ||
interimBundle as expectedInterimBundle, | ||
issuanceTimestamp, | ||
obsoleteTag, | ||
seed, | ||
signaturesOrMessages, | ||
tag, | ||
values, | ||
} from './samples' | ||
const bundleHash = (bundleTrits: Int8Array) => { | ||
const sponge = new Kerl() | ||
const out = new Int8Array(BUNDLE_LENGTH) | ||
for (let offset = 0; offset < bundle.length; offset += TRANSACTION_LENGTH) { | ||
sponge.absorb(transactionEssence(bundleTrits, offset), 0, TRANSACTION_ESSENCE_LENGTH) | ||
} | ||
sponge.squeeze(out, 0, BUNDLE_LENGTH) | ||
return out | ||
} | ||
const entries = [ | ||
{ | ||
signatureOrMessage: signaturesOrMessages[0], | ||
address: addresses[0], | ||
value: -2, | ||
value: values[0], | ||
obsoleteTag, | ||
issuanceTimestamp, | ||
tag, | ||
obsoleteTag: tag, | ||
currentIndex: 0, | ||
lastIndex: 2, | ||
timestamp: 1522219, | ||
signatureMessageFragment: '9'.repeat(81 * 27), | ||
trunkTransaction: NULL_HASH, | ||
branchTransaction: NULL_HASH, | ||
attachmentTimestamp: 0, | ||
attachmentTimestampLowerBound: 0, | ||
attachmentTimestampUpperBound: 0, | ||
bundle: NULL_HASH, | ||
nonce: NULL_NONCE, | ||
hash: NULL_HASH, | ||
}, | ||
{ | ||
address: addresses[0], | ||
value: 0, | ||
signatureOrMessage: signaturesOrMessages[1], | ||
address: addresses[1], | ||
value: values[1], | ||
obsoleteTag, | ||
issuanceTimestamp, | ||
tag, | ||
obsoleteTag: tag, | ||
currentIndex: 1, | ||
lastIndex: 2, | ||
timestamp: 1522219, | ||
signatureMessageFragment: '9'.repeat(81 * 27), | ||
trunkTransaction: NULL_HASH, | ||
branchTransaction: NULL_HASH, | ||
attachmentTimestamp: 0, | ||
attachmentTimestampLowerBound: 0, | ||
attachmentTimestampUpperBound: 0, | ||
bundle: NULL_HASH, | ||
nonce: NULL_NONCE, | ||
hash: NULL_HASH, | ||
}, | ||
{ | ||
address: addresses[1], | ||
value: 2, | ||
signatureOrMessage: signaturesOrMessages[2], | ||
address: addresses[2], | ||
value: values[2], | ||
obsoleteTag, | ||
issuanceTimestamp, | ||
tag, | ||
obsoleteTag: tag, | ||
currentIndex: 2, | ||
lastIndex: 2, | ||
timestamp: 1522219, | ||
signatureMessageFragment: '9'.repeat(81 * 27), | ||
trunkTransaction: NULL_HASH, | ||
branchTransaction: NULL_HASH, | ||
attachmentTimestamp: 0, | ||
attachmentTimestampLowerBound: 0, | ||
attachmentTimestampUpperBound: 0, | ||
bundle: NULL_HASH, | ||
nonce: NULL_NONCE, | ||
hash: NULL_HASH, | ||
}, | ||
] | ||
const actualInterimBundle = createBundle(entries) | ||
const actualInterimBundlePartial = createBundle(entries.slice(0, entries.length - 1)) | ||
const actualFinalBundle = finalizeBundle(actualInterimBundle) | ||
const actualFinalSignedBundle = signatureFragments(seed, 0, 2, bundle(actualFinalBundle)).then(signature => | ||
addSignatureOrMessage(actualFinalBundle, signature, 1) | ||
) | ||
test('createBundle() returns correct transactions.', t => { | ||
t.deepEqual( | ||
createBundle([ | ||
{ | ||
length: 2, | ||
address: addresses[0], | ||
value: -2, | ||
tag: 'TAG', | ||
timestamp: 1522219, | ||
}, | ||
{ | ||
length: 1, | ||
address: addresses[1], | ||
value: 2, | ||
tag: 'TAG', | ||
timestamp: 1522219, | ||
}, | ||
]), | ||
bundle, | ||
'createBundle() should return correct transactions.' | ||
) | ||
describe('createBundle(entries: ReadonlyArray<Partial<BundleEntry>>)', async assert => { | ||
assert({ | ||
given: 'entries with signatureOrMessage of length that is not multiple of fragment length', | ||
should: 'throw RangeError', | ||
actual: Try(createBundle, [{ signatureOrMessage: new Int8Array(SIGNATURE_OR_MESSAGE_LENGTH - 1) }]), | ||
expected: new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entries with signatureOrMessage of 0 length', | ||
should: 'throw RangeError', | ||
actual: Try(createBundle, [{ signatureOrMessage: new Int8Array(0) }]), | ||
expected: new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entries with address of illegal length (< exact length)', | ||
should: 'throw RangeError', | ||
actual: Try(createBundle, [{ address: new Int8Array(ADDRESS_LENGTH - 1) }]), | ||
expected: new RangeError(errors.ILLEGAL_ADDRESS_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entries with address of illegal length (> exact length)', | ||
should: 'throw RangeError', | ||
actual: Try(createBundle, [{ address: new Int8Array(ADDRESS_LENGTH + 1) }]), | ||
expected: new RangeError(errors.ILLEGAL_ADDRESS_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entries with value of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: Try(createBundle, [{ value: new Int8Array(VALUE_LENGTH + 1) }]), | ||
expected: new RangeError(errors.ILLEGAL_VALUE_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entries with obsoleteTag of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: Try(createBundle, [{ obsoleteTag: new Int8Array(OBSOLETE_TAG_LENGTH + 1) }]), | ||
expected: new RangeError(errors.ILLEGAL_OBSOLETE_TAG_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entries with issuanceTimestamp of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: Try(createBundle, [{ issuanceTimestamp: new Int8Array(ISSUANCE_TIMESTAMP_LENGTH + 1) }]), | ||
expected: new RangeError(errors.ILLEGAL_ISSUANCE_TIMESTAMP_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entries with tag of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: Try(createBundle, [{ tag: new Int8Array(TAG_LENGTH + 1) }]), | ||
expected: new RangeError(errors.ILLEGAL_TAG_LENGTH), | ||
}) | ||
assert({ | ||
given: 'valid entries', | ||
should: 'produce correct interim bundle', | ||
actual: actualInterimBundle, | ||
expected: expectedInterimBundle, | ||
}) | ||
assert({ | ||
given: 'empty entries', | ||
should: 'produce empty interim bundle', | ||
actual: createBundle([{}]), | ||
expected: new Int8Array(TRANSACTION_LENGTH), | ||
}) | ||
assert({ | ||
given: 'no entries', | ||
should: 'produce no bundle', | ||
actual: createBundle(), | ||
expected: new Int8Array(0), | ||
}) | ||
}) | ||
test('addEntry() adds new entry and returns correct transactions.', t => { | ||
t.deepEqual( | ||
addEntry(bundle.slice(0, 2), { | ||
length: 1, | ||
address: addresses[1], | ||
value: 2, | ||
tag: 'TAG', | ||
timestamp: 1522219, | ||
describe('addEntry(bundle: Int8Array, entry: Partial<BundleEntry>)', async assert => { | ||
assert({ | ||
given: 'given bundle of length that is not multiple of transaction length', | ||
should: 'throw RangeError', | ||
actual: Try(addEntry, new Int8Array(TRANSACTION_LENGTH - 1), entries[0]), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entry with signatureOrMessage of length that is not multiple of fragment length', | ||
should: 'throw RangeError', | ||
actual: Try(addEntry, new Int8Array(0), { | ||
signatureOrMessage: new Int8Array(SIGNATURE_OR_MESSAGE_LENGTH - 1), | ||
}), | ||
bundle, | ||
'addEntry() should add new entry and return correct trasnactions.' | ||
) | ||
expected: new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entry with signatureOrMessage of 0 length', | ||
should: 'throw RangeError', | ||
actual: Try(addEntry, new Int8Array(0), { signatureOrMessage: new Int8Array(0) }), | ||
expected: new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entry with address of illegal length (< exact length)', | ||
should: 'throw RangeError', | ||
actual: Try(addEntry, new Int8Array(0), { address: new Int8Array(ADDRESS_LENGTH - 1) }), | ||
expected: new RangeError(errors.ILLEGAL_ADDRESS_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entry with address of illegal length (> exact length)', | ||
should: 'throw RangeError', | ||
actual: Try(addEntry, new Int8Array(0), { address: new Int8Array(ADDRESS_LENGTH + 1) }), | ||
expected: new RangeError(errors.ILLEGAL_ADDRESS_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entry with value of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: Try(addEntry, new Int8Array(0), { value: new Int8Array(VALUE_LENGTH + 1) }), | ||
expected: new RangeError(errors.ILLEGAL_VALUE_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entry with obsoleteTag of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: Try(addEntry, new Int8Array(0), { | ||
obsoleteTag: new Int8Array(OBSOLETE_TAG_LENGTH + 1), | ||
}), | ||
expected: new RangeError(errors.ILLEGAL_OBSOLETE_TAG_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entry with issuanceTimestamp of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: Try(addEntry, new Int8Array(0), { | ||
issuanceTimestamp: new Int8Array(ISSUANCE_TIMESTAMP_LENGTH + 1), | ||
}), | ||
expected: new RangeError(errors.ILLEGAL_ISSUANCE_TIMESTAMP_LENGTH), | ||
}) | ||
assert({ | ||
given: 'entry with tag of illegal length (> max length)', | ||
should: 'throw RangeError', | ||
actual: Try(addEntry, new Int8Array(0), { ...entries[0], tag: new Int8Array(TAG_LENGTH + 1) }), | ||
expected: new RangeError(errors.ILLEGAL_TAG_LENGTH), | ||
}) | ||
assert({ | ||
given: 'valid entry', | ||
should: 'produce correct interim bundle', | ||
actual: addEntry(actualInterimBundlePartial, entries[entries.length - 1]), | ||
expected: expectedInterimBundle, | ||
}) | ||
assert({ | ||
given: 'empty entry', | ||
should: 'do nothing', | ||
actual: addEntry(new Int8Array(0), {}), | ||
expected: new Int8Array(TRANSACTION_LENGTH), | ||
}) | ||
}) | ||
test('addEntry() throws error for entry with value and address with last trit !== 0.', t => { | ||
const invalidAddressTrits = trytesToTrits(addresses[1]) | ||
invalidAddressTrits[HASH_TRITS_SIZE - 1] = 1 | ||
const invalidAddressTrytes = tritsToTrytes(invalidAddressTrits) | ||
describe('finalizeBundle(bundle: Int8Array)', async assert => { | ||
assert({ | ||
given: 'given bundle of 0 length', | ||
should: 'throw RangeError', | ||
actual: Try(finalizeBundle, new Int8Array(0)), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH), | ||
}) | ||
const entry = { | ||
length: 1, | ||
address: invalidAddressTrytes, | ||
value: 1, | ||
tag: 'TAG', | ||
timestamp: 1522219, | ||
} | ||
assert({ | ||
given: 'given bundle of length that is not multiple of transaction length', | ||
should: 'throw RangeError', | ||
actual: Try(finalizeBundle, new Int8Array(TRANSACTION_LENGTH - 1)), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH), | ||
}) | ||
t.is( | ||
t.throws(() => addEntry([], entry)).message, | ||
INVALID_ADDRESS_LAST_TRIT, | ||
'addEntry() should throw error for entry with value and address with last trit !== 0.' | ||
) | ||
assert({ | ||
given: 'valid interim bundle', | ||
should: 'produce correct final bundle', | ||
actual: actualFinalBundle, | ||
expected: expectedFinalBundle, | ||
}) | ||
t.is( | ||
t.throws(() => addEntry([], { ...entry, value: -1 })).message, | ||
INVALID_ADDRESS_LAST_TRIT, | ||
'addEntry() should throw error for entry with value and address with last trit !== 0.' | ||
) | ||
assert({ | ||
given: 'insecure bundle (normalized bundle hash contains value 13)', | ||
should: 'increment obsolete tag and recompute bundle hash', | ||
actual: { | ||
insecureInterimBundle: | ||
normalizedBundle(bundleHash(actualInterimBundle)).indexOf(MAX_TRYTE_VALUE /* 13 */) > -1, | ||
secureFinalBundle: normalizedBundle(bundle(actualFinalBundle)).indexOf(MAX_TRYTE_VALUE /* 13 */) === -1, | ||
obsoleteTag: obsoleteTagCopy(actualFinalBundle), | ||
}, | ||
expected: { | ||
insecureInterimBundle: true, | ||
secureFinalBundle: true, | ||
obsoleteTag: trytesToTrits('EF9999999999999999999999999'), | ||
}, | ||
}) | ||
}) | ||
test('addTrytes() adds trytes and returns correct transactions.', t => { | ||
t.deepEqual( | ||
addTrytes(bundle, ['TRYTES', 'TRYTES', 'TRYTES']), | ||
bundle.map(transaction => ({ | ||
...transaction, | ||
signatureMessageFragment: 'TRYTES' + '9'.repeat(81 * 27 - 6), | ||
})), | ||
'addEntry should add trytes and return correct transactions.' | ||
) | ||
describe('addSignatureOrMessage(bundle: Int8Array, signatureOrMessage: Int8Array, index: number)', async assert => { | ||
assert({ | ||
given: 'given bundle of 0 length', | ||
should: 'throw RangeError', | ||
actual: Try(addSignatureOrMessage, new Int8Array(0), new Int8Array(SIGNATURE_OR_MESSAGE_LENGTH), 0), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH), | ||
}) | ||
assert({ | ||
given: 'given bundle of length that is not multiple of transaction length', | ||
should: 'throw RangeError', | ||
actual: Try( | ||
addSignatureOrMessage, | ||
new Int8Array(TRANSACTION_LENGTH - 1), | ||
new Int8Array(SIGNATURE_OR_MESSAGE_LENGTH), | ||
0 | ||
), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH), | ||
}) | ||
assert({ | ||
given: 'given signatureOrMessage of length that is not multiple of fragment length', | ||
should: 'throw RangeError', | ||
actual: Try( | ||
addSignatureOrMessage, | ||
new Int8Array(TRANSACTION_LENGTH), | ||
new Int8Array(SIGNATURE_OR_MESSAGE_LENGTH - 1), | ||
0 | ||
), | ||
expected: new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH), | ||
}) | ||
assert({ | ||
given: 'given signatureOrMessage of 0 length', | ||
should: 'throw RangeError', | ||
actual: Try(addSignatureOrMessage, new Int8Array(TRANSACTION_LENGTH), new Int8Array(0), 0), | ||
expected: new RangeError(errors.ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH), | ||
}) | ||
assert({ | ||
given: 'index = undefined', | ||
should: 'throw TypeError', | ||
actual: Try( | ||
addSignatureOrMessage, | ||
new Int8Array(TRANSACTION_LENGTH), | ||
new Int8Array(SIGNATURE_OR_MESSAGE_LENGTH), | ||
undefined as any | ||
), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_INDEX), | ||
}) | ||
assert({ | ||
given: 'index = NaN', | ||
should: 'throw TypeError', | ||
actual: Try( | ||
addSignatureOrMessage, | ||
new Int8Array(TRANSACTION_LENGTH), | ||
new Int8Array(SIGNATURE_OR_MESSAGE_LENGTH), | ||
NaN as any | ||
), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_INDEX), | ||
}) | ||
assert({ | ||
given: 'index = null', | ||
should: 'throw TypeError', | ||
actual: Try( | ||
addSignatureOrMessage, | ||
new Int8Array(TRANSACTION_LENGTH), | ||
new Int8Array(SIGNATURE_OR_MESSAGE_LENGTH), | ||
null as any | ||
), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_INDEX), | ||
}) | ||
assert({ | ||
given: 'index = Infinity', | ||
should: 'throw TypeError', | ||
actual: Try( | ||
addSignatureOrMessage, | ||
new Int8Array(TRANSACTION_LENGTH), | ||
new Int8Array(SIGNATURE_OR_MESSAGE_LENGTH), | ||
Infinity | ||
), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_INDEX), | ||
}) | ||
assert({ | ||
given: 'index = "0" (string)', | ||
should: 'throw TypeError', | ||
actual: Try( | ||
addSignatureOrMessage, | ||
new Int8Array(TRANSACTION_LENGTH), | ||
new Int8Array(SIGNATURE_OR_MESSAGE_LENGTH), | ||
'0' as any | ||
), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_INDEX), | ||
}) | ||
assert({ | ||
given: 'out-of-range index (< 0)', | ||
should: 'throw TypeError', | ||
actual: Try( | ||
addSignatureOrMessage, | ||
new Int8Array(TRANSACTION_LENGTH), | ||
new Int8Array(SIGNATURE_OR_MESSAGE_LENGTH), | ||
-1 | ||
), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_INDEX), | ||
}) | ||
assert({ | ||
given: 'out-of-range index (> 0)', | ||
should: 'throw RangeError', | ||
actual: Try( | ||
addSignatureOrMessage, | ||
new Int8Array(TRANSACTION_LENGTH * 3), | ||
new Int8Array(SIGNATURE_OR_MESSAGE_LENGTH * 2), | ||
2 | ||
), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_INDEX), | ||
}) | ||
assert({ | ||
given: 'valid final bundle', | ||
should: 'produce correct signed bundle', | ||
actual: tritsToTrytes(await actualFinalSignedBundle), | ||
expected: tritsToTrytes(expectedFinalSignedBundle), | ||
}) | ||
}) | ||
test('finalizeBundle() adds correct bundle hash.', t => { | ||
const bundleHash = 'VRGXKZDODWIVGFYFCCXJRNDCQJVYUVBRIWJXKFGBIEWUPHHTJLTKH99JW9OLJ9JCIXCEIRRXJKLWOBDZZ' | ||
const incrObsoleteTag = 'ZUH'.concat('9'.repeat(24)) | ||
describe('valueSum(buffer: Int8Array, offset: number, length: number): number', async assert => { | ||
assert({ | ||
given: 'buffer of length that is not multiple of transaction length', | ||
should: 'throw RangeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH - 1), 0, TRANSACTION_LENGTH), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_BUFFER_LENGTH), | ||
}) | ||
const expected = bundle.map((transaction, i) => ({ | ||
...transaction, | ||
obsoleteTag: i === 0 ? incrObsoleteTag : transaction.obsoleteTag, | ||
bundle: bundleHash, | ||
})) | ||
assert({ | ||
given: 'offset that is not multiple of transaction length', | ||
should: 'throw RangeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH), 1, TRANSACTION_LENGTH), | ||
expected: new RangeError(errors.ILLEGAL_TRANSACTION_OFFSET), | ||
}) | ||
t.deepEqual(finalizeBundle(bundle), expected, 'finalizeBundle() should add correct bundle hash.') | ||
assert({ | ||
given: 'length that is not multiple of transaction length', | ||
should: 'throw RangeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH), 0, TRANSACTION_LENGTH - 1), | ||
expected: new RangeError(errors.ILLEGAL_BUNDLE_LENGTH), | ||
}) | ||
assert({ | ||
given: 'offset = undefined', | ||
should: 'throw TypeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH), undefined as any, TRANSACTION_LENGTH), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET), | ||
}) | ||
assert({ | ||
given: 'offset = NaN', | ||
should: 'throw TypeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH), NaN as any, TRANSACTION_LENGTH), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET), | ||
}) | ||
assert({ | ||
given: 'offset = null', | ||
should: 'throw TypeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH), null as any, TRANSACTION_LENGTH), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET), | ||
}) | ||
assert({ | ||
given: 'offset = Infinity', | ||
should: 'throw TypeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH), Infinity as any, TRANSACTION_LENGTH), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET), | ||
}) | ||
assert({ | ||
given: 'offset = "0" (string)', | ||
should: 'throw TypeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH), '0' as any, TRANSACTION_LENGTH), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET), | ||
}) | ||
assert({ | ||
given: 'offset = 0.1', | ||
should: 'throw TypeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH), 0.1, TRANSACTION_LENGTH), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET), | ||
}) | ||
assert({ | ||
given: 'length = undefined', | ||
should: 'throw TypeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH), 0, undefined as any), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET), | ||
}) | ||
assert({ | ||
given: 'length = NaN', | ||
should: 'throw TypeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH), 0, NaN as any), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET), | ||
}) | ||
assert({ | ||
given: 'length = null', | ||
should: 'throw TypeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH), 0, null as any), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET), | ||
}) | ||
assert({ | ||
given: 'length = Infinity', | ||
should: 'throw TypeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH), 0, Infinity as any), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET), | ||
}) | ||
assert({ | ||
given: 'length = "0" (string)', | ||
should: 'throw TypeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH), 0, '0' as any), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET), | ||
}) | ||
assert({ | ||
given: 'length = 0.1', | ||
should: 'throw TypeError', | ||
actual: Try(valueSum, new Int8Array(TRANSACTION_LENGTH), 0, 0.1), | ||
expected: new TypeError(errors.ILLEGAL_TRANSACTION_OFFSET), | ||
}) | ||
assert({ | ||
given: 'valid buffer', | ||
should: 'calculate value sum', | ||
actual: (() => { | ||
const buffer = new Int8Array(3 * TRANSACTION_LENGTH).fill(0) | ||
const offset = TRANSACTION_LENGTH | ||
const length = TRANSACTION_LENGTH * 2 | ||
buffer.set(valueToTrits(10000), VALUE_OFFSET) | ||
buffer.set(valueToTrits(-9), offset + VALUE_OFFSET) | ||
buffer.set(valueToTrits(10), offset + TRANSACTION_LENGTH + VALUE_OFFSET) | ||
return valueSum(buffer, offset, length) | ||
})(), | ||
expected: 1, | ||
}) | ||
}) |
@@ -18,2 +18,2 @@ { | ||
] | ||
} | ||
} |
/** @module bundle */ | ||
import '../../typed-array'; | ||
import { Bundle, Hash, Transaction, // tslint:disable-line no-unused-variable | ||
Trytes } from '../../types'; | ||
export interface BundleEntry { | ||
readonly length: number; | ||
readonly address: Hash; | ||
readonly value: number; | ||
readonly tag: string; | ||
readonly timestamp: number; | ||
readonly signatureMessageFragments: ReadonlyArray<Trytes>; | ||
readonly signatureOrMessage: Int8Array; | ||
readonly address: Int8Array; | ||
readonly value: Int8Array; | ||
readonly obsoleteTag: Int8Array; | ||
readonly issuanceTimestamp: Int8Array; | ||
readonly tag: Int8Array; | ||
} | ||
export { Transaction, Bundle }; | ||
/** | ||
@@ -19,7 +16,7 @@ * Creates a bundle with given transaction entries. | ||
* | ||
* @param {BundleEntry[]} entries - Entries of single or multiple transactions with the same address | ||
* @param {BundleEntry[]} [entries=[]] - Entries of single or multiple transactions with the same address | ||
* | ||
* @return {Transaction[]} List of transactions in the bundle | ||
* @return {Int8Array[]} List of transactions in the bundle | ||
*/ | ||
export declare const createBundle: (entries?: ReadonlyArray<Partial<BundleEntry>>) => ReadonlyArray<Transaction>; | ||
export declare const createBundle: (entries?: ReadonlyArray<Partial<BundleEntry>>) => Int8Array; | ||
/** | ||
@@ -30,38 +27,35 @@ * Adds given transaction entry to a bundle. | ||
* | ||
* @param {Transaction[]} transactions - List of transactions currently in the bundle | ||
* @param {object} entry - Entry of a single or multiple transactions with the same address. | ||
* @param {Int8Array} entry.address - Address. | ||
* @param {Int8Array} entry.value - Value to transfer in iotas. | ||
* @param {Int8Array} [entry.signatureOrMessage] - Signature or message fragment(s). | ||
* @param {Int8Array} [entry.timestamp] - Issuance timestamp (in seconds). | ||
* @param {Int8Array} [entry.tag] - Optional Tag, **Deprecated**. | ||
* @param {Int8Array} bundle - Bundle buffer. | ||
* | ||
* @param {object} entry - Entry of a single or multiple transactions with the same address | ||
* @param {number} [entry.length = 1] - Entry length, which indicates how many transactions in the bundle it will occupy | ||
* @param {Hash} [entry.address] - Address, defaults to all-9s | ||
* @param {number} [entry.value = 0] - Value to transfer in iotas | ||
* @param {Trytes[]} [entry.signatureMessageFragments] - List of signature message fragments, defaults to all-9s | ||
* @param {number} [entry.timestamp] - Transaction timestamp, defaults to `Math.floor(Date.now() / 1000)` | ||
* @param {string} [entry.tag] - Optional Tag, defaults to null tag (all-9s) | ||
* | ||
* @return {Transaction[]} List of transactions in the updated bundle | ||
* @return {Int8Array} Bundle copy with new entries. | ||
*/ | ||
export declare const addEntry: (transactions: ReadonlyArray<Transaction>, entry: Partial<BundleEntry>) => ReadonlyArray<Transaction>; | ||
export declare const addEntry: (bundle: Int8Array, entry: Partial<BundleEntry>) => Int8Array; | ||
/** | ||
* Adds signature message fragments to transactions in a bundle starting at offset. | ||
* Finalizes a bundle by calculating the bundle hash. | ||
* | ||
* @method addTrytes | ||
* @method finalizeBundle | ||
* | ||
* @param {Transaction[]} transactions - List of transactions in the bundle | ||
* @param {Int8Array} bundle - Bundle transaction trits | ||
* | ||
* @param {Trytes[]} fragments - List of signature message fragments to add | ||
* | ||
* @param {number} [offset = 0] - Optional offset to start appending signature message fragments | ||
* | ||
* @return {Transaction[]} List of transactions in the updated bundle | ||
* @return {Int8Array} List of transactions in the finalized bundle | ||
*/ | ||
export declare const addTrytes: (transactions: ReadonlyArray<Transaction>, fragments: ReadonlyArray<string>, offset?: number) => ReadonlyArray<Transaction>; | ||
export declare const finalizeBundle: (bundle: Int8Array) => Int8Array; | ||
/** | ||
* Finalizes a bundle by calculating the bundle hash. | ||
* Adds signature message fragments to transactions in a bundle starting at offset. | ||
* | ||
* @method finalizeBundle | ||
* @method addSignatureOrMessage | ||
* | ||
* @param {Transaction[]} transactions - List of transactions in the bundle | ||
* @param {Int8Array} bundle - Bundle buffer. | ||
* @param {Int8Array} signatureOrMessage - Signature or message to add. | ||
* @param {number} index - Transaction index as entry point for signature or message fragments. | ||
* | ||
* @return {Transaction[]} List of transactions in the finalized bundle | ||
* @return {Int8Array} List of transactions in the updated bundle | ||
*/ | ||
export declare const finalizeBundle: (transactions: ReadonlyArray<Transaction>) => ReadonlyArray<Transaction>; | ||
export declare const addSignatureOrMessage: (bundle: Int8Array, signatureOrMessage: Int8Array, index: number) => Int8Array; | ||
export declare const valueSum: (buffer: Int8Array, offset: number, length: number) => number; |
export declare const ILLEGAL_LENGTH = "Illegal trits length"; | ||
export declare const ILLEGAL_SUBSEED_INDEX = "Illegal subseed length"; | ||
export declare const ILLEGAL_SUBSEED_LENGTH = "Illegal subseed length"; | ||
export declare const ILLEGAL_NUMBER_OF_FRAGMENTS = "Illegal number of fragments"; | ||
export declare const ILLEGAL_KEY_LENGTH = "Illegal key length"; | ||
@@ -12,2 +13,30 @@ export declare const ILLEGAL_DIGESTS_LENGTH = "Illegal digests length"; | ||
export declare const ILLEGAL_TRYTE_CONVERSION_INPUT = "Illegal conversion input. Expected trytes string or integer."; | ||
export declare const ILLEGAL_MIN_WEIGHT_MAGNITUDE = "Illegal minWeightMagnitude value."; | ||
export declare const ILLEGAL_ADDRESS_LAST_TRIT = "Illegal address. Last trit must be 0."; | ||
export declare const ILLEGAL_ADDRESS_LENGTH = "Illegal address length."; | ||
export declare const ILLEGAL_BUNDLE_LENGTH = "Illegal bundle hash length."; | ||
export declare const ILLEGAL_OBSOLETE_TAG_LENGTH = "Illegal obsoleteTag length."; | ||
export declare const ILLEGAL_SIGNATURE_OR_MESSAGE = "Illegal signature or message."; | ||
export declare const ILLEGAL_SIGNATURE_OR_MESSAGE_LENGTH = "Illegal signatureOrMessage length."; | ||
export declare const ILLEGAL_TAG_LENGTH = "Illegal tag length."; | ||
export declare const ILLEGAL_ISSUANCE_TIMESTAMP = "Illegal issuance timestamp"; | ||
export declare const ILLEGAL_ISSUANCE_TIMESTAMP_LENGTH = "Illegal issuanceTimestamp length."; | ||
export declare const ILLEGAL_VALUE_LENGTH = "Illegal value length."; | ||
export declare const ILLEGAL_TRANSACTION_FIELD_OFFSET = "Illegal transaction field offset."; | ||
export declare const ILLEGAL_TRANSACTION_FIELD_LENGTH = "Illegal transaction field length."; | ||
export declare const ILLEGAL_LENGTH_OR_OFFSET = "Illegal length or offset."; | ||
export declare const ILLEGAL_TRANSACTION_BUFFER = "Illegal transaction buffer. Expected `Int8Array`."; | ||
export declare const ILLEGAL_TRANSACTION_BUFFER_LENGTH = "Illegal transaction buffer length."; | ||
export declare const ILLEGAL_TRANSACTION_OFFSET = "Illegal transaction offset."; | ||
export declare const ILLEGAL_TRANSACTION_LENGTH = "Illegal transaction length."; | ||
export declare const ILLEGAL_TRANSACTION_ORDER = "Illegal transaction order."; | ||
export declare const ILLEGAL_TRANSACTION_INDEX = "Illegal transaction index."; | ||
export declare const ILLEGAL_SEED_LENGTH = "Illegal seed length. Expected length of 243 trits."; | ||
export declare const ILLEGAL_KEY_INDEX = "Illegal key index."; | ||
export declare const ILLEGAL_CDA_LENGTH = "Illegal cda length."; | ||
export declare const ILLEGAL_BATCH = "Illegal batch."; | ||
export declare const CDA_ALREADY_IN_STORE = "CDA is already in store."; | ||
export declare const ILLEGAL_PERSISTENCE_ID = "Illegal persistence id."; | ||
export declare const ILLEGAL_PERSISTENCE_PATH = "Illegal persistence path."; | ||
export declare const ILLEGAL_PADDING_LENGTH = "Illegal padding length. Input value length exceeds padding length."; | ||
export declare const INCONSISTENT_SUBTANGLE = "Inconsistent subtangle"; | ||
@@ -57,2 +86,1 @@ export declare const INSUFFICIENT_BALANCE = "Insufficient balance"; | ||
export declare const INVALID_DELAY = "Invalid delay."; | ||
export declare const INVALID_ADDRESS_LAST_TRIT = "Invalid address: Last trit of address of value transaction must be 0."; |
@@ -0,2 +1,4 @@ | ||
/// <reference types="node" /> | ||
import * as Promise from 'bluebird'; | ||
import { EventEmitter } from 'events'; | ||
export declare type Maybe<T> = T | void; | ||
@@ -47,2 +49,9 @@ export declare type Hash = string; | ||
} | ||
export interface TransactionEssence { | ||
readonly address: Int8Array; | ||
readonly value: Int8Array; | ||
readonly obsoleteTag?: Int8Array; | ||
readonly issuanceTimestamp?: Int8Array; | ||
readonly currentIndex: Int8Array; | ||
} | ||
export declare type Bundle = ReadonlyArray<Transaction>; | ||
@@ -228,3 +237,50 @@ export interface Neighbor { | ||
export declare type NativeGenerateSignatureFunction = (seed: number[], index: number, numberOfFragments: number, bundle: number[]) => Promise<number[]>; | ||
export declare const asArray: <T>(x: T | ReadonlyArray<T>) => ReadonlyArray<T>; | ||
export declare const asArray: <T>(x: T | readonly T[]) => readonly T[]; | ||
export declare const getOptionsWithDefaults: <T>(defaults: Readonly<T>) => (options: Readonly<Partial<T>>) => Readonly<T>; | ||
export interface PersistenceIteratorOptions<K = any> { | ||
gt?: K; | ||
gte?: K; | ||
lt?: K; | ||
lte?: K; | ||
reverse?: boolean; | ||
limit?: number; | ||
keys?: boolean; | ||
values?: boolean; | ||
keyAsBuffer?: boolean; | ||
valueAsBuffer?: boolean; | ||
} | ||
export interface PersistenceError extends Error { | ||
notFound?: boolean; | ||
} | ||
export interface PersistenceBatch<V> { | ||
readonly type: 'writeBundle' | 'deleteBundle' | 'writeCDA' | 'deleteCDA'; | ||
readonly value: V; | ||
} | ||
export declare type CreatePersistenceReadStream<V> = (onData: (data: V) => any, onError: (error: Error) => any, onClose: () => any, onEnd: () => any, options?: PersistenceIteratorOptions) => NodeJS.ReadableStream; | ||
export interface Persistence<T = Int8Array> extends EventEmitter { | ||
readonly nextIndex: () => Promise<T>; | ||
readonly writeBundle: (bundle: T) => Promise<void>; | ||
readonly deleteBundle: (bundle: T) => Promise<void>; | ||
readonly readCDA: (address: T) => Promise<T>; | ||
readonly writeCDA: (cda: T) => Promise<void>; | ||
readonly deleteCDA: (cda: T) => Promise<void>; | ||
readonly batch: (ops: PersistenceBatch<T>) => Promise<void>; | ||
readonly createReadStream: CreatePersistenceReadStream<T>; | ||
} | ||
export declare type PersistenceAdapterBatch<K, V> = PersistenceAdapterWriteOp<K, V> | PersistenceAdapterDeleteOp<K>; | ||
export interface PersistenceAdapterWriteOp<K, V> { | ||
readonly type: 'write'; | ||
readonly key: K; | ||
readonly value: V; | ||
} | ||
export interface PersistenceAdapterDeleteOp<K> { | ||
readonly type: 'delete'; | ||
readonly key: K; | ||
} | ||
export interface PersistenceAdapter<K = Buffer, V = Buffer> { | ||
readonly read: (key: K) => Promise<V>; | ||
readonly write: (key: K, value: V) => Promise<void>; | ||
readonly delete: (key: K) => Promise<void>; | ||
readonly batch: (ops: ReadonlyArray<PersistenceAdapterBatch<K, V>>) => Promise<void>; | ||
readonly createReadStream: CreatePersistenceReadStream<V>; | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
255088
33
2924
6
2
3
1
+ Added@types/warning@^3.0.0
+ Addedwarning@^4.0.3
+ Added@iota/curl@1.0.0-beta.cda45022(transitive)
+ Added@iota/transaction@1.0.0-beta.cda45022(transitive)
+ Added@types/warning@3.0.3(transitive)
+ Addedjs-tokens@4.0.0(transitive)
+ Addedloose-envify@1.4.0(transitive)
+ Addedwarning@4.0.3(transitive)
- Removed@iota/pad@^1.0.0-beta.11
Updated@iota/kerl@^1.0.0-beta.12
Updated@iota/signing@^1.0.0-beta.12