iota.lib.js
Version:
Javascript Library for IOTA
178 lines (132 loc) • 4.78 kB
JavaScript
var Curl = require("../curl/curl");
var Kerl = require("../kerl/kerl");
var Converter = require("../converter/converter");
var tritAdd = require("../helpers/adder");
/**
*
* @constructor bundle
**/
function Bundle() {
// Declare empty bundle
this.bundle = [];
}
/**
*
*
**/
Bundle.prototype.addEntry = function(signatureMessageLength, address, value, tag, timestamp, index) {
for (var i = 0; i < signatureMessageLength; i++) {
var transactionObject = new Object();
transactionObject.address = address;
transactionObject.value = i == 0 ? value : 0;
transactionObject.obsoleteTag = tag;
transactionObject.tag = tag;
transactionObject.timestamp = timestamp;
this.bundle[this.bundle.length] = transactionObject;
}
}
/**
*
*
**/
Bundle.prototype.addTrytes = function(signatureFragments) {
var emptySignatureFragment = '';
var emptyHash = '999999999999999999999999999999999999999999999999999999999999999999999999999999999';
var emptyTag = '9'.repeat(27);
var emptyTimestamp = '9'.repeat(9);
for (var j = 0; emptySignatureFragment.length < 2187; j++) {
emptySignatureFragment += '9';
}
for (var i = 0; i < this.bundle.length; i++) {
// Fill empty signatureMessageFragment
this.bundle[i].signatureMessageFragment = signatureFragments[i] ? signatureFragments[i] : emptySignatureFragment;
// Fill empty trunkTransaction
this.bundle[i].trunkTransaction = emptyHash;
// Fill empty branchTransaction
this.bundle[i].branchTransaction = emptyHash;
this.bundle[i].attachmentTimestamp = emptyTimestamp;
this.bundle[i].attachmentTimestampLowerBound = emptyTimestamp;
this.bundle[i].attachmentTimestampUpperBound = emptyTimestamp;
// Fill empty nonce
this.bundle[i].nonce = emptyTag;
}
}
/**
*
*
**/
Bundle.prototype.finalize = function() {
var validBundle = false;
while(!validBundle) {
var kerl = new Kerl();
kerl.initialize();
for (var i = 0; i < this.bundle.length; i++) {
var valueTrits = Converter.trits(this.bundle[i].value);
while (valueTrits.length < 81) {
valueTrits[valueTrits.length] = 0;
}
var timestampTrits = Converter.trits(this.bundle[i].timestamp);
while (timestampTrits.length < 27) {
timestampTrits[timestampTrits.length] = 0;
}
var currentIndexTrits = Converter.trits(this.bundle[i].currentIndex = i);
while (currentIndexTrits.length < 27) {
currentIndexTrits[currentIndexTrits.length] = 0;
}
var lastIndexTrits = Converter.trits(this.bundle[i].lastIndex = this.bundle.length - 1);
while (lastIndexTrits.length < 27) {
lastIndexTrits[lastIndexTrits.length] = 0;
}
var bundleEssence = Converter.trits(this.bundle[i].address + Converter.trytes(valueTrits) + this.bundle[i].obsoleteTag + Converter.trytes(timestampTrits) + Converter.trytes(currentIndexTrits) + Converter.trytes(lastIndexTrits));
kerl.absorb(bundleEssence, 0, bundleEssence.length);
}
var hash = [];
kerl.squeeze(hash, 0, Curl.HASH_LENGTH);
hash = Converter.trytes(hash);
for (var i = 0; i < this.bundle.length; i++) {
this.bundle[i].bundle = hash;
}
var normalizedHash = this.normalizedBundle(hash);
if(normalizedHash.indexOf(13 /* = M */) != -1) {
// Insecure bundle. Increment Tag and recompute bundle hash.
var increasedTag = tritAdd(Converter.trits(this.bundle[0].obsoleteTag), [1]);
this.bundle[0].obsoleteTag = Converter.trytes(increasedTag);
} else {
validBundle = true;
}
}
}
/**
* Normalizes the bundle hash
*
**/
Bundle.prototype.normalizedBundle = function(bundleHash) {
var normalizedBundle = [];
for (var i = 0; i < 3; i++) {
var sum = 0;
for (var j = 0; j < 27; j++) {
sum += (normalizedBundle[i * 27 + j] = Converter.value(Converter.trits(bundleHash.charAt(i * 27 + j))));
}
if (sum >= 0) {
while (sum-- > 0) {
for (var j = 0; j < 27; j++) {
if (normalizedBundle[i * 27 + j] > -13) {
normalizedBundle[i * 27 + j]--;
break;
}
}
}
} else {
while (sum++ < 0) {
for (var j = 0; j < 27; j++) {
if (normalizedBundle[i * 27 + j] < 13) {
normalizedBundle[i * 27 + j]++;
break;
}
}
}
}
}
return normalizedBundle;
}
module.exports = Bundle;