<commit_before>'use strict';

define(['bitcoinjs-lib', 'util/btc', 'model/historyrow'], function(Bitcoin, BtcUtils, HistoryRow) {

/**
 * User oriented history view.
 * @param {Object} store Store for the object.
 * @param {Object} identity Parent identity for the object
 * @constructor
 */
function History(store, identity) {
    this.history = [];
    this.identity = identity;
    var self = this;
    Object.keys(identity.txdb.transactions).forEach(function(txId) {
        if (identity.txdb.getImpact(txId)) {
            self.history.push(new HistoryRow(txId, identity));
        }
    });
}

/**
 * Add a row into the history.
 * Will make sure it's inserted sorted by its height.
 * @param {Object} newRow row coming from history.buildHistoryRow
 * Will return -1 if row is confirmed, -2 if still not confirmed, -3 if already was confirmed
 * @return {Number} 0 if inserted, 1 confirmed, 2 still not confirmed, 3 was already confirmed
 * @private
 */
History.prototype.addHistoryRow = function(newRow) {
    // Look for repeated element
    for(var idx=this.history.length-1; idx>=0; idx--) {
        var row = this.history[idx];
        if (row.hash == newRow.hash) {
            // replace by new row
            this.history[idx] = newRow;
            // set return code depending on status
            if (!row.height && newRow.height) {
                return 1; // confirmed
            } else if (!row.height && !newRow.height) {
                return 2; // still not confirmed
            } else {
                // keep initial height
                this.history[idx].height = row.height;
                return 3; // already confirmed
            }
        }
    }
    // Not found so insert
    this.history.push(newRow);
    return 0;
};

/**
 * Add impact for input or output to an impact dictionary.
 * @private
 */
History.prototype.addPocketImpact = function(impact, pocketId, outPocketType, amount) {
    if (!impact.hasOwnProperty(pocketId)) {
        impact[pocketId] = {ins: 0, outs: 0, total: 0, type: outPocketType};
    }
    if (amount > 0) {
        impact[pocketId].outs += amount;
    } else {
        impact[pocketId].ins -= amount;
    }
    impact[pocketId].total += amount;
};

/**
 * Build a history row from a transaction.
 * Will find out which inputs and outputs correspond to the identity wallet and calculate impact.
 * @param {String} transaction Transaction in serialized form
 * @param {Number} height Height for the transaction
 * @return {Object} The new row
 */
History.prototype.buildHistoryRow = function(transaction, height) {
    var identity = this.identity,
        btcWallet = identity.wallet.wallet,
        outAddresses = [],
        inMine = 0,
        txAddr = "",
        txObj = Bitcoin.Transaction.fromHex(transaction);
    var txHash = txObj.getId();

    var pocketImpact = {};

    var inAddress;

    // Check inputs
    for(var idx=0; idx<txObj.ins.length; idx++) {
        var anIn = txObj.ins[idx];
        var outIdx = Bitcoin.bufferutils.reverse(anIn.hash).toString('hex')+":"+anIn.index;
        var output = btcWallet.outputs[outIdx];
        if (output) {
            // save in pocket
            var inWalletAddress = identity.wallet.getWalletAddress(output.address);
            var inPocket = identity.wallet.pockets.getAddressPocketId(inWalletAddress);
            var inPocketType = identity.wallet.pockets.getPocketType(inWalletAddress.type);
            // counters
            this.addPocketImpact(pocketImpact, inPocket, inPocketType, -output.value);
            inMine += 1;
        } else {
            try {
                if (!inAddress) {
                    var address = BtcUtils.getInputAddress(anIn, this.identity.wallet.versions);
                    inAddress = address || inAddress;
                }
            } catch (e) {
                console.log("error decoding input", anIn);
            }
        }
    }
    if (!inMine) {
        txAddr = inAddress || 'unknown';
    }
    // Check outputs
    for(var idx=0; idx<txObj.outs.length; idx++) {
        var outAddress = "";
        var anOut = txObj.outs[idx];
        try {
            outAddress = Bitcoin.Address.fromOutputScript(anOut.script, Bitcoin.networks[this.identity.wallet.network]).toString();
        } catch(e) {
            continue;
        }<commit_msg>Properly process outputs whose address is not present.<commit_after>'use strict';

define(['bitcoinjs-lib', 'util/btc', 'model/historyrow'], function(Bitcoin, BtcUtils, HistoryRow) {

/**
 * User oriented history view.
 * @param {Object} store Store for the object.
 * @param {Object} identity Parent identity for the object
 * @constructor
 */
function History(store, identity) {
    this.history = [];
    this.identity = identity;
    var self = this;
    Object.keys(identity.txdb.transactions).forEach(function(txId) {
        if (identity.txdb.getImpact(txId)) {
            self.history.push(new HistoryRow(txId, identity));
        }
    });
}

/**
 * Add a row into the history.
 * Will make sure it's inserted sorted by its height.
 * @param {Object} newRow row coming from history.buildHistoryRow
 * Will return -1 if row is confirmed, -2 if still not confirmed, -3 if already was confirmed
 * @return {Number} 0 if inserted, 1 confirmed, 2 still not confirmed, 3 was already confirmed
 * @private
 */
History.prototype.addHistoryRow = function(newRow) {
    // Look for repeated element
    for(var idx=this.history.length-1; idx>=0; idx--) {
        var row = this.history[idx];
        if (row.hash == newRow.hash) {
            // replace by new row
            this.history[idx] = newRow;
            // set return code depending on status
            if (!row.height && newRow.height) {
                return 1; // confirmed
            } else if (!row.height && !newRow.height) {
                return 2; // still not confirmed
            } else {
                // keep initial height
                this.history[idx].height = row.height;
                return 3; // already confirmed
            }
        }
    }
    // Not found so insert
    this.history.push(newRow);
    return 0;
};

/**
 * Add impact for input or output to an impact dictionary.
 * @private
 */
History.prototype.addPocketImpact = function(impact, pocketId, outPocketType, amount) {
    if (!impact.hasOwnProperty(pocketId)) {
        impact[pocketId] = {ins: 0, outs: 0, total: 0, type: outPocketType};
    }
    if (amount > 0) {
        impact[pocketId].outs += amount;
    } else {
        impact[pocketId].ins -= amount;
    }
    impact[pocketId].total += amount;
};

/**
 * Build a history row from a transaction.
 * Will find out which inputs and outputs correspond to the identity wallet and calculate impact.
 * @param {String} transaction Transaction in serialized form
 * @param {Number} height Height for the transaction
 * @return {Object} The new row
 */
History.prototype.buildHistoryRow = function(transaction, height) {
    var identity = this.identity,
        btcWallet = identity.wallet.wallet,
        outAddresses = [],
        inMine = 0,
        txAddr = "",
        txObj = Bitcoin.Transaction.fromHex(transaction);
    var txHash = txObj.getId();

    var pocketImpact = {};

    var inAddress;

    // Check inputs
    for(var idx=0; idx<txObj.ins.length; idx++) {
        var anIn = txObj.ins[idx];
        var outIdx = Bitcoin.bufferutils.reverse(anIn.hash).toString('hex')+":"+anIn.index;
        var output = btcWallet.outputs[outIdx];
        var inWalletAddress;
        if (output) {
            inWalletAddress = identity.wallet.getWalletAddress(output.address);
            if (!inWalletAddress) {
                console.log("Address not available for output: " + output.address);
            }
        }
        if (inWalletAddress) {
            // save in pocket
            var inPocket = identity.wallet.pockets.getAddressPocketId(inWalletAddress);
            var inPocketType = identity.wallet.pockets.getPocketType(inWalletAddress.type);
            // counters
            this.addPocketImpact(pocketImpact, inPocket, inPocketType, -output.value);
            inMine += 1;
        } else {
            try {
                if (!inAddress) {
                    var address = BtcUtils.getInputAddress(anIn, this.identity.wallet.versions);
                    inAddress = address || inAddress;
                }
            } catch (e) {
                console.log("error decoding input", anIn);
            }
        }
    }
    if (!inMine) {
        txAddr = inAddress || 'unknown';
    }
    // Check outputs
    for(var idx=0; idx<txObj.outs.length; idx++) {
        var outAddress = "";
        var anOut = txObj.outs[idx];
        try {
            outAddress = Bitcoin.Address.fromOutputScript(anOut.script, Bitcoin.networks[this.identity.wallet.network]).toString();
        } catch(e) {
            continue;
        }
{'fraction_non_alphanumeric': 0.11718486923335952, 'fraction_numerical': 0.004714333819732855, 'mean_word_length': 2.2189306358381504, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3914464', 'n_tokens_mistral': 2553, 'n_tokens_neox': 2505, 'n_words': 682}