forked from taustin/bcl
-
Notifications
You must be signed in to change notification settings - Fork 1
/
client.js
84 lines (69 loc) · 2.44 KB
/
client.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
"use strict";
let EventEmitter = require('events');
let Transaction = require('./transaction.js');
let Wallet = require('./wallet.js');
const POST = "POST_TRANSACTION";
const DEFAULT_TX_FEE = 1;
/**
* A client has a wallet, sends messages, and receives messages
* on the Blockchain network.
*/
module.exports = class Client extends EventEmitter {
/**
* The broadcast function determines how the client communicates
* with other entities in the system. (This approach allows us to
* simplify our testing setup.)
*
* @param {function} broadcast - The function used by the client
* to send messages to all miners and clients.
*/
constructor(broadcast) {
super();
this.broadcast = broadcast;
this.wallet = new Wallet();
// Clients will listen for any funds given to them.
// They will optimistically assume that all transactions
// will be accepted and finalized.
this.on(POST, (tx) => this.receiveOutput(tx));
}
/**
* Broadcasts a transaction from the client giving money to the clients
* specified in 'outputs'. Note that any unused money is sent to a new
* change address. A transaction fee may be specified, which can be more
* or less than the default value.
*
* @param {Array} outputs - The list of outputs of other addresses and
* amounts to pay.
* @param {number} fee - The transaction fee reward to pay the miner.
*/
postTransaction(outputs, fee=DEFAULT_TX_FEE) {
// We calculate the total value of coins needed.
let totalPayments = outputs.reduce((acc, {amount}) => acc + amount, 0) + fee;
// Make sure the client has enough money.
if (totalPayments > this.wallet.balance) {
throw new Error(`Requested ${totalPayments}, but wallet only has ${this.wallet.balance}.`);
}
// Gathering the needed inputs, and specifying an address for change.
let { inputs, changeAmt } = this.wallet.spendUTXOs(totalPayments);
if (changeAmt > 0) {
let changeAddr = this.wallet.makeAddress();
outputs.push({ address: changeAddr, amount: changeAmt });
}
// Broadcasting the new transaction.
let tx = new Transaction({
inputs: inputs,
outputs: outputs,
});
this.broadcast(POST, tx);
}
/**
* Accepts payment and adds it to the client's wallet.
*/
receiveOutput(tx) {
tx.outputs.forEach(output => {
if (this.wallet.hasKey(output.address)) {
this.wallet.addUTXO(output);
}
});
}
}