Code viewer for World: Blockchain Demo
//STYLE
document.write(`
  <style>
    .previous, .hash{
        font-family: monospace;
    }
    .block{
        margin: 8px;
        border: 1px solid #000;
        border-radius: 1px;
    }
  </style>
`);
//TEMPLATE
document.write('<div id="blockchain"></div>');
document.write('<div id="users"></div>');
$('#ab-wrapper').css('height', '0px');
//
	
// Import SHA256 lib
// https://npm.io/package/js-sha256
$.getScript('https://cdnjs.cloudflare.com/ajax/libs/js-sha256/0.9.0/sha256.min.js', 
            () => console.log('SHA256 Support Loaded'));


//hash values must to begin with as much 0 as defined in difficulty
const difficulty = 3;

class Block{
    constructor(id, timestamp, transaction, previous, complexity){
        this.id = id;
        this.timestamp = timestamp;
        this.transaction = transaction;
        this.nonce = 0;
        this.previous = previous;
        this.complexity = complexity;
        this.hash = 0;//this.mine();
    }
    generateHash(){
        return sha256(JSON.stringify(this));
    }
    mine(){
        let h = this.generateHash();
        while (h.substr(0, this.complexity) != new Array(this.complexity).fill(0).join('')) {
            this.nonce += 1;
            h = this.generateHash();
        }
        this.hash = h;
    }
    getHtml() {
        return `
  <table class="block" id="`+this.id+`">
    <tr class="id"><td>id:</td><td>`+this.id+`</td></tr>
    <tr class="previous"><th>Previous: </th><td>`+this.formatHashCode(this.previous)+`</td>
    <tr class="timestamp"><td>timestamp: </td><td>`+this.timestamp+`</td></tr>
    <tr class="transaction"><td>transaction: </td><td>`+this.transaction.getHtml()+`</td></tr>
    <tr class="nonce"><td>nonce: </td><td>`+this.nonce+`</td></tr>
    <tr class="hash"><td>hash: </td><td>`+this.formatHashCode(String(this.hash))+`</td></tr>
    <tr><th>Mine: </th> <td><button onclick="mine(`+this.id+`)">Mine</button></td></tr>
  </table>
`;
    }
    formatHashCode(code) {
        return code.substring(0, 32) + '<br>' + code.substring(32, 64);
    }
}

class Transaction{
    constructor(from, to, amount) {
        this.from = from;
        this.to = to;
        this.amount = amount;
    }
    getHtml() {
        return `
    <div class="from">from: `+this.from+`</div>
    <div class="from">to: `+this.to+`</div>
    <div class="from">amount: `+this.amount+`</div>
`;
    }
}

class BlockChain{
    constructor(complexity){
        this.complexity = complexity;
        this.chain = [this.generateGenesisBlock()];
        this.pendingTransaction = null;
    }
    generateGenesisBlock(){
        return new Block(0, Date.now(), new Transaction('System', 'System', 0), 
                            new Array(64).fill(0).join(''), this.complexity);
    }
    minePendingTransaction(){
        let block = new Block(this.chain[this.chain.length - 1].id + 1, Date.now(), this.pendingTransaction, this.chain[this.chain.length-1].hash, this.complexity);
        this.chain.push(block);
    }
    
    createTransaction(transaction){
        this.pendingTransaction = transaction;
    }
        
    getAddressBalance(address){
        balance = 0;
        for (let block of this.chain) {
            if (address == transaction.from)
                balance -= transaction.amount;
            if (address == transaction.to)
                balance += transaction.amount;
        }
        return balance;
    }
    
    isValid(){
        for (let i = 1; i < this.chain.length; i++) {
            if (!this.isBlockValid(i)) return false;
        }
        return true;
    }
    isBlockValid(i){
        this.calculateHash(i);
        return this.chain[i].hash.substr(0, this.complexity) == new Array(this.complexity).fill(0).join('');
    }
    calculateHash(i) {
        this.chain[i].previous = this.chain[i-1].generateHash();
        this.chain[i].hash = this.chain[i].generateHash();
    }
}

function mine(id) {
    console.log('MINING', id);
    bc.chain[id].mine();
    bc.isValid();
    drawBlockchain(bc);
}

//---- test blockchain --------------------------------------------
let bc = new BlockChain(difficulty);
bc.createTransaction(new Transaction('System', 'Alice', 100));
bc.minePendingTransaction();
//---- draw -------------------------------------------------------

function drawBlockchain(bc) {
    $('#blockchain').html('');
    for(let i = 0; i < bc.chain.length; i++)
        $('#blockchain').html($('#blockchain').html() + bc.chain[i].getHtml());
}

   

function setup()        // "setup" is called once at start of run 
{

}
drawBlockchain(bc);
function draw()             // Optional
{
     
}