@iota/bundle
Advanced tools
Comparing version 1.0.0-beta.5 to 1.0.0-beta.722117ce
"use strict"; | ||
/** @module bundle */ | ||
var __assign = (this && this.__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; | ||
}; | ||
exports.__esModule = true; | ||
var bundle_1 = require("./bundle"); | ||
exports.createBundle = bundle_1.createBundle; | ||
exports.addEntry = bundle_1.addEntry; | ||
exports.addTrytes = bundle_1.addTrytes; | ||
exports.finalizeBundle = bundle_1.finalizeBundle; | ||
var converter_1 = require("@iota/converter"); | ||
var kerl_1 = require("@iota/kerl"); | ||
var pad_1 = require("@iota/pad"); | ||
var signing_1 = require("@iota/signing"); | ||
require("../../typed-array"); | ||
var t = new Int8Array(1).slice(); | ||
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) | ||
}); }; | ||
/** | ||
* Creates a bunlde with given transaction entries. | ||
* | ||
* @method createBundle | ||
* | ||
* @param {BundleEntry[]} entries - Entries of signle or multiple transactions with the same address | ||
* | ||
* @return {Transaction[]} 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); }, []); | ||
}; | ||
/** | ||
* Creates a bunlde with given transaction entries | ||
* | ||
* @method addEntry | ||
* | ||
* @param {Transaction[]} transactions - List of transactions currently in the bundle | ||
* | ||
* @param {object} entry - Entry of single or multiple transactions with the same address | ||
* @param {number} [entry.length=1] - Entry length, which indicates how many transactions in the bundle will occupy | ||
* @param {string} [entry.address] - Address, defaults to all-9s | ||
* @param {number} [entry.value = 0] - Value to transfer in _IOTAs_ | ||
* @param {string[]} [entry.signatureMessageFragments] - Array of signature message fragments trytes, 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[]} Bundle | ||
*/ | ||
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; | ||
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 | ||
}); })); | ||
}; | ||
/** | ||
* Adds a list of trytes in the bundle starting at offset | ||
* | ||
* @method addTrytes | ||
* | ||
* @param {Transaction[]} transactions - Transactions in the bundle | ||
* | ||
* @param {Trytes[]} fragments - Message signature fragments to add | ||
* | ||
* @param {number} [offset=0] - Optional offset to start appending signature message fragments | ||
* | ||
* @return {Transaction[]} Transactions of 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; | ||
}); | ||
}; | ||
/** | ||
* Finalizes the bundle by calculating the bundle hash | ||
* | ||
* @method finalizeBundle | ||
* | ||
* @param {Transaction[]} transactions - Transactions in the bundle | ||
* | ||
* @return {Transaction[]} Transactions of finalized bundle | ||
*/ | ||
exports.finalizeBundle = function (transactions) { | ||
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 bundleHash; | ||
var validBundle = false; | ||
while (!validBundle) { | ||
var kerl = new kerl_1["default"](); | ||
kerl.initialize(); | ||
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)); | ||
kerl.absorb(essence, 0, essence.length); | ||
} | ||
var bundleHashTrits = new Int8Array(kerl_1["default"].HASH_LENGTH); | ||
kerl.squeeze(bundleHashTrits, 0, kerl_1["default"].HASH_LENGTH); | ||
bundleHash = converter_1.trytes(bundleHashTrits); | ||
if (signing_1.normalizedBundleHash(bundleHash).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; | ||
} | ||
} | ||
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: bundleHash })); }); | ||
}; | ||
//# sourceMappingURL=index.js.map |
@@ -12,3 +12,3 @@ "use strict"; | ||
var ava_1 = require("ava"); | ||
var bundle_1 = require("../src/bundle"); | ||
var src_1 = require("../src"); | ||
var NULL_HASH = '9'.repeat(81); | ||
@@ -75,3 +75,3 @@ var NULL_NONCE = '9'.repeat(27); | ||
ava_1["default"]('createBundle() returns correct transactions.', function (t) { | ||
t.deepEqual(bundle_1.createBundle([ | ||
t.deepEqual(src_1.createBundle([ | ||
{ | ||
@@ -94,3 +94,3 @@ length: 2, | ||
ava_1["default"]('addEntry() adds new entry and returns correct transactions.', function (t) { | ||
t.deepEqual(bundle_1.addEntry(bundle.slice(0, 2), { | ||
t.deepEqual(src_1.addEntry(bundle.slice(0, 2), { | ||
length: 1, | ||
@@ -104,3 +104,3 @@ address: addresses[1], | ||
ava_1["default"]('addTrytes() adds trytes and returns correct transactions.', function (t) { | ||
t.deepEqual(bundle_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.'); | ||
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.'); | ||
}); | ||
@@ -111,4 +111,4 @@ ava_1["default"]('finalizeBundle() adds correct bundle hash.', function (t) { | ||
var expected = bundle.map(function (transaction, i) { return (__assign({}, transaction, { obsoleteTag: i === 0 ? incrObsoleteTag : transaction.obsoleteTag, bundle: bundleHash })); }); | ||
t.deepEqual(bundle_1.finalizeBundle(bundle), expected, 'finalizeBundle() should add correct bundle hash.'); | ||
t.deepEqual(src_1.finalizeBundle(bundle), expected, 'finalizeBundle() should add correct bundle hash.'); | ||
}); | ||
//# sourceMappingURL=bundle.test.js.map |
{ | ||
"name": "@iota/bundle", | ||
"version": "1.0.0-beta.5", | ||
"version": "1.0.0-beta.722117ce", | ||
"description": "Utilities for generating and signing bundles", | ||
@@ -67,7 +67,7 @@ "main": "./out/bundle/src/index.js", | ||
"dependencies": { | ||
"@iota/converter": "^1.0.0-beta.5", | ||
"@iota/kerl": "^1.0.0-beta.5", | ||
"@iota/pad": "^1.0.0-beta.5", | ||
"@iota/signing": "^1.0.0-beta.5" | ||
"@iota/converter": "^1.0.0-beta.722117ce", | ||
"@iota/kerl": "^1.0.0-beta.722117ce", | ||
"@iota/pad": "^1.0.0-beta.722117ce", | ||
"@iota/signing": "^1.0.0-beta.722117ce" | ||
} | ||
} |
177
src/index.ts
@@ -1,1 +0,176 @@ | ||
export { BundleEntry, createBundle, addEntry, addTrytes, finalizeBundle } from './bundle' | ||
/** @module bundle */ | ||
import { trits, trytes } from '@iota/converter' | ||
import Kerl from '@iota/kerl' | ||
import { padTag, padTrits, padTrytes } from '@iota/pad' | ||
import { add, normalizedBundleHash } from '@iota/signing' | ||
import '../../typed-array' | ||
import { Bundle, Hash, Transaction, Trytes } from '../../types' | ||
const t = new Int8Array(1).slice() | ||
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> | ||
} | ||
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), | ||
}) | ||
/** | ||
* Creates a bunlde with given transaction entries. | ||
* | ||
* @method createBundle | ||
* | ||
* @param {BundleEntry[]} entries - Entries of signle or multiple transactions with the same address | ||
* | ||
* @return {Transaction[]} List of transactions in the bundle | ||
*/ | ||
export const createBundle = (entries: ReadonlyArray<Partial<BundleEntry>> = []): Bundle => | ||
entries.reduce((bundle: Bundle, entry) => addEntry(bundle, entry), []) | ||
/** | ||
* Creates a bunlde with given transaction entries | ||
* | ||
* @method addEntry | ||
* | ||
* @param {Transaction[]} transactions - List of transactions currently in the bundle | ||
* | ||
* @param {object} entry - Entry of single or multiple transactions with the same address | ||
* @param {number} [entry.length=1] - Entry length, which indicates how many transactions in the bundle will occupy | ||
* @param {string} [entry.address] - Address, defaults to all-9s | ||
* @param {number} [entry.value = 0] - Value to transfer in _IOTAs_ | ||
* @param {string[]} [entry.signatureMessageFragments] - Array of signature message fragments trytes, 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[]} Bundle | ||
*/ | ||
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 | ||
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, | ||
})) | ||
) | ||
} | ||
/** | ||
* Adds a list of trytes in the bundle starting at offset | ||
* | ||
* @method addTrytes | ||
* | ||
* @param {Transaction[]} transactions - Transactions in the bundle | ||
* | ||
* @param {Trytes[]} fragments - Message signature fragments to add | ||
* | ||
* @param {number} [offset=0] - Optional offset to start appending signature message fragments | ||
* | ||
* @return {Transaction[]} Transactions of 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 | ||
) | ||
/** | ||
* Finalizes the bundle by calculating the bundle hash | ||
* | ||
* @method finalizeBundle | ||
* | ||
* @param {Transaction[]} transactions - Transactions in the bundle | ||
* | ||
* @return {Transaction[]} Transactions of finalized bundle | ||
*/ | ||
export const finalizeBundle = (transactions: Bundle): Bundle => { | ||
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)) | ||
let bundleHash: Hash | ||
let validBundle: boolean = false | ||
while (!validBundle) { | ||
const kerl = new Kerl() | ||
kerl.initialize() | ||
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) | ||
) | ||
kerl.absorb(essence, 0, essence.length) | ||
} | ||
const bundleHashTrits = new Int8Array(Kerl.HASH_LENGTH) | ||
kerl.squeeze(bundleHashTrits, 0, Kerl.HASH_LENGTH) | ||
bundleHash = trytes(bundleHashTrits) | ||
if (normalizedBundleHash(bundleHash).indexOf(13) !== -1) { | ||
// Insecure bundle, increment obsoleteTag and recompute bundle hash | ||
obsoleteTagTrits[0] = add(obsoleteTagTrits[0], new Int8Array(1).fill(1)) | ||
} else { | ||
validBundle = true | ||
} | ||
} | ||
return transactions.map((transaction, i) => ({ | ||
...transaction, | ||
// overwrite obsoleteTag in first entry | ||
obsoleteTag: i === 0 ? trytes(obsoleteTagTrits[0]) : transaction.obsoleteTag, | ||
bundle: bundleHash, | ||
})) | ||
} |
import test from 'ava' | ||
import { addEntry, addTrytes, createBundle, finalizeBundle } from '../src/bundle' | ||
import { addEntry, addTrytes, createBundle, finalizeBundle } from '../src' | ||
@@ -4,0 +4,0 @@ const NULL_HASH = '9'.repeat(81) |
@@ -1,1 +0,62 @@ | ||
export { BundleEntry, createBundle, addEntry, addTrytes, finalizeBundle } from './bundle'; | ||
import '../../typed-array'; | ||
import { Hash, Transaction, 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>; | ||
} | ||
/** | ||
* Creates a bunlde with given transaction entries. | ||
* | ||
* @method createBundle | ||
* | ||
* @param {BundleEntry[]} entries - Entries of signle or multiple transactions with the same address | ||
* | ||
* @return {Transaction[]} List of transactions in the bundle | ||
*/ | ||
export declare const createBundle: (entries?: ReadonlyArray<Partial<BundleEntry>>) => ReadonlyArray<Transaction>; | ||
/** | ||
* Creates a bunlde with given transaction entries | ||
* | ||
* @method addEntry | ||
* | ||
* @param {Transaction[]} transactions - List of transactions currently in the bundle | ||
* | ||
* @param {object} entry - Entry of single or multiple transactions with the same address | ||
* @param {number} [entry.length=1] - Entry length, which indicates how many transactions in the bundle will occupy | ||
* @param {string} [entry.address] - Address, defaults to all-9s | ||
* @param {number} [entry.value = 0] - Value to transfer in _IOTAs_ | ||
* @param {string[]} [entry.signatureMessageFragments] - Array of signature message fragments trytes, 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[]} Bundle | ||
*/ | ||
export declare const addEntry: (transactions: ReadonlyArray<Transaction>, entry: Partial<BundleEntry>) => ReadonlyArray<Transaction>; | ||
/** | ||
* Adds a list of trytes in the bundle starting at offset | ||
* | ||
* @method addTrytes | ||
* | ||
* @param {Transaction[]} transactions - Transactions in the bundle | ||
* | ||
* @param {Trytes[]} fragments - Message signature fragments to add | ||
* | ||
* @param {number} [offset=0] - Optional offset to start appending signature message fragments | ||
* | ||
* @return {Transaction[]} Transactions of finalized bundle | ||
*/ | ||
export declare const addTrytes: (transactions: ReadonlyArray<Transaction>, fragments: ReadonlyArray<string>, offset?: number) => ReadonlyArray<Transaction>; | ||
/** | ||
* Finalizes the bundle by calculating the bundle hash | ||
* | ||
* @method finalizeBundle | ||
* | ||
* @param {Transaction[]} transactions - Transactions in the bundle | ||
* | ||
* @return {Transaction[]} Transactions of finalized bundle | ||
*/ | ||
export declare const finalizeBundle: (transactions: ReadonlyArray<Transaction>) => ReadonlyArray<Transaction>; |
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
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
66893
950
22