@leofcoin/lib 0.4.12 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,205 +0,0 @@
1
- import Errors from './errors.js'
2
- import Hash from './hash.js'
3
- import { randomBytes } from 'crypto'
4
- import MultiWallet from '@leofcoin/multi-wallet'
5
- import { network, reward } from './params.js';
6
- import * as ipldLfcTx from 'ipld-lfc-tx';
7
-
8
- const { LFCTx, util } = ipldLfcTx
9
-
10
- /**
11
- * @extends {Hash}
12
- * @example
13
- * const transaction = new Transaction()
14
- */
15
- export default class Transaction extends Hash {
16
- constructor() {
17
- super()
18
- }
19
-
20
-
21
- /**
22
- * Create transaction
23
- *
24
- * @param inputs
25
- * @param outputs
26
- * @param reward
27
- * @return {{id: string, reward: boolean, inputs: *, outputs: *, hash: string}}
28
- */
29
- async newTransaction(inputs, outputs, reward = null) {
30
- try {
31
- const tx = new LFCTx({
32
- id: randomBytes(32).toString('hex'),
33
- time: Math.floor(new Date().getTime() / 1000),
34
- reward,
35
- outputs,
36
- inputs
37
- });
38
- // const cid = await util.cid(tx.serialize())
39
- // await global.ipfs.dag.put(tx, {format: util.codec, hashAlg: util.defaultHashAlg, version: 1, baseFormat: 'base58btc'})
40
- return tx
41
- } catch (e) {
42
- throw e
43
- }
44
- }
45
-
46
- /**
47
- * Create reward transaction for block mining
48
- *
49
- * @param {string} address
50
- * @param {number} height
51
- * @return {id: string, reward: boolean, inputs: *, outputs: *, hash: string}
52
- */
53
- async createRewardTransaction(address, amount) {
54
- return this.newTransaction([], [{index: 0, amount, address}], 'mined');
55
- }
56
-
57
- /**
58
- * validate transaction
59
- *
60
- * @param multihash
61
- * @param transaction
62
- * @param unspent
63
- */
64
- async validateTransaction(multihash, transaction, unspent) {
65
- if (!transaction.reward) delete transaction.reward
66
- const outputs = transaction.outputs.map(o => {
67
- // TODO: fix script
68
- if (!o.script) delete o.script
69
- return o
70
- })
71
- console.log(transaction);
72
- transaction.outputs = outputs
73
- if (!transaction.script) delete transaction.script
74
- if (!ipldLfcTx.util.isValid(transaction)) return await ipldLfcTx.util.validate(transaction)
75
- if (multihash !== await this.transactionHash(transaction)) throw this.TransactionError('Invalid transaction hash');
76
- // TODO: versions should be handled here...
77
- // Verify each input signature
78
-
79
- if (transaction.inputs) {
80
- transaction.inputs.forEach(input => {
81
- const { signature, address } = input;
82
- const hash = this.transactionInputHash(input);
83
-
84
- let wallet = new MultiWallet(network);
85
- wallet.fromAddress(address, null, network);
86
-
87
- if (!wallet.verify(Buffer.from(signature, 'hex'), Buffer.from(hash, 'hex')))
88
- throw this.TransactionError('Invalid input signature');
89
- });
90
-
91
- // Check if inputs are in unspent list
92
- transaction.inputs.forEach((input) => {
93
- if (!unspent.find(out => out.tx === input.tx && out.index === input.index)) { throw this.TransactionError('Input has been already spent: ' + input.tx); }
94
- });
95
- }
96
-
97
- if (transaction.reward === 'mined') {
98
- // For reward transaction: check if reward output is correct
99
- if (transaction.outputs.length !== 1) throw this.TransactionError('Reward transaction must have exactly one output');
100
- if (transaction.outputs[0].amount !== reward) throw this.TransactionError(`Mining reward must be exactly: ${reward}`);
101
- } else if (transaction.inputs) {
102
- // For normal transaction: check if total output amount equals input amount
103
- if (transaction.inputs.reduce((acc, input) => acc + input.amount, 0) !==
104
- transaction.outputs.reduce((acc, output) => acc + output.amount, 0)) { throw this.TransactionError('Input and output amounts do not match'); }
105
- }
106
-
107
- return true;
108
- }
109
-
110
- /**
111
- * validate transactions list for current block
112
- *
113
- * @param {array} transactions
114
- * @param unspent
115
- */
116
- async validateTransactions(transactions, unspent) {
117
- const _transactions = []
118
- for (let tx of transactions) {
119
- let multihash = tx.multihash
120
-
121
- if (multihash) tx = await leofcoin.api.transaction.get(multihash);
122
- else {
123
- tx = await new LFCTx({...tx})
124
- multihash = await util.cid(await tx.serialize())
125
- multihash = multihash.toBaseEncodedString()
126
- }
127
-
128
- _transactions.push({multihash, value: tx.toJSON()})
129
- }
130
-
131
- try {
132
- for (const {value, multihash} of _transactions) {
133
- // TODO: fix value.scrip
134
- await this.validateTransaction(multihash, value, unspent)
135
- }
136
- } catch (e) {
137
- throw e
138
- }
139
-
140
- if (_transactions.filter(({value}) => value.reward === 'mined').length !== 1)
141
- throw this.TransactionError('Transactions cannot have more than one reward');
142
-
143
- return true
144
- }
145
-
146
- /**
147
- * Verify signature
148
- *
149
- * @param {string} address - signer address
150
- * @param {string} signature - signature to verify
151
- * @param {string} hash - transaction hash
152
- */
153
- verifySignature(address, signature, hash) {
154
- const wallet = new MultiWallet(network);
155
- return wallet.verify(signature, hash, address);
156
- }
157
-
158
- /**
159
- * Create and sign input
160
- *
161
- * @param transaction Based on transaction id
162
- * @param index Based on transaction output index
163
- * @param amount
164
- * @param wallet
165
- * @return {Object} {transaction, index, amount, address}
166
- */
167
- createInput(transaction, index, amount, wallet) {
168
- const input = {
169
- tx: transaction,
170
- index,
171
- amount,
172
- address: wallet.address,
173
- };
174
- input.signature = wallet.sign(Buffer.from(this.transactionInputHash(input), 'hex')).toString('hex');
175
- return input;
176
- }
177
-
178
- /**
179
- * Create a transaction
180
- *
181
- * @param wallet
182
- * @param toAddress
183
- * @param amount
184
- * @return {Object} {id, reward, inputs, outputs, hash,}
185
- */
186
- async buildTransaction(wallet, toAddress, amount, unspent) {
187
- let inputsAmount = 0;
188
- // const unspent = await this.getUnspentForAddress(wallet.address);
189
- const inputsRaw = unspent.filter(i => {
190
- const more = inputsAmount < amount;
191
- if (more) inputsAmount += i.amount;
192
- return more;
193
- });
194
- if (inputsAmount < amount) throw this.TransactionError('Not enough funds');
195
- // TODO: Add multiSigning
196
- const inputs = inputsRaw.map(i => this.createInput(i.tx, i.index, i.amount, wallet));
197
- // Send amount to destination address
198
- const outputs = [{index: 0, amount, address: toAddress}];
199
- // Send back change to my wallet
200
- if (inputsAmount - amount > 0) {
201
- outputs.push({index: 1, amount: inputsAmount - amount, address: wallet.address});
202
- }
203
- return this.newTransaction(inputs, outputs);
204
- }
205
- }
package/test/index.js DELETED
@@ -1,106 +0,0 @@
1
- const test = require('tape');
2
- const Peernet = require('@leofcoin/peernet');
3
- const Chain = require('./../index');
4
-
5
- const address = '8HFTVVfRMeL1sASrsdp6mvqDW9pvSD4AKySPEq3So16Wo1mpgY';
6
-
7
-
8
- (async () => {
9
- await new Peernet()
10
-
11
- const chain = new Chain()
12
-
13
- chain.chain.push({
14
- hash: 'zsNS6waLSmzg9BFR5CwJxJWpmT1ygXpXHuJ8Y4hTeqq8HRAVEcDfUnsMxEeFb7DLmaF3kPiUyEAfdX3dgPdTNLPHqCfvY6',
15
- index: 1,
16
- nonce: 263991677,
17
- prevHash: 'zsNS6wZiHSc2QPHmjV8TMNn798b4Kp9jpjsBNeUkPhaJTza3GosWUgE72Jy3X9jKMrFCcDni7Pq4yXogQN4TcAfrPmTXFt',
18
- time: 1590242832,
19
- transactions: [{
20
- id: 'f83349fbde4098c9be72be87468265d7ae43de8137fec514e3b81adbd8ff1c9d',
21
- inputs: [],
22
- outputs: [{
23
- address: '8HFTVVfRMeL1sASrsdp6mvqDW9pvSD4AKySPEq3So16Wo1mpgY',
24
- amount: 150,
25
- index: 0
26
- }],
27
- reward: 'mined',
28
- script: 'mined',
29
- time: 1590242832
30
- }]
31
- })
32
-
33
- // test('block', tape => {
34
- // tape.plan(1)
35
- //
36
- // tape.equals('block')
37
- // })
38
- const testChain = () => new Promise((resolve, reject) => {
39
- test('chain', async tape => {
40
- tape.plan(15)
41
-
42
- let value = await chain.getTransactions()
43
- tape.equals(value.length, 1, 'getTransactions')
44
-
45
- value = await chain.getTransactions(false, 1)
46
- tape.equals(value.length, 0, 'getTransactions after block 1')
47
-
48
- value = await chain.getTransactionsForAddress(address)
49
- tape.equals(value.length, 1, 'getTransactionsForAddress')
50
-
51
- value = await chain.getTransactionsForAddress(address, 1)
52
- tape.equals(value.length, 0, 'getTransactionsForAddress after block 1')
53
-
54
- value = await chain.getUnspent(address)
55
- tape.equals(value.length, 1, 'getUnspent')
56
-
57
- value = await chain.getUnspentForAddress(address)
58
- tape.equals(value.length, 1, 'getUnspentForAddress')
59
-
60
- value = await chain.getBalanceForAddress(address)
61
- tape.equals(value, 150, 'getBalanceForAddress')
62
-
63
- value = await chain.getBalanceForAddress(address, 1)
64
- tape.equals(value, 0, 'getBalanceForAddress after block 1')
65
-
66
- value = await chain.nextBlockTransactions()
67
- tape.equals(value.length, 0, 'nextBlockTransactions')
68
-
69
- value = await chain.longestChain()
70
- tape.equals(value.index, 0, 'longestChain')
71
-
72
- value = await chain.lastBlock()
73
- tape.equals(value.index, 0, 'lastBlock')
74
-
75
- value = await chain.nextBlock('8HFTVVfRMeL1sASrsdp6mvqDW9pvSD4AKySPEq3So16Wo1mpgY')
76
- tape.equals(value.transactions[0].reward, 'mined', 'nextBlock')
77
-
78
- const hash = value.hash
79
-
80
- value = await chain.blockHash(value)
81
- tape.equals(value, hash, 'blockHash')
82
-
83
- value = await chain.transactionHash(chain.chain[1].transactions[0])
84
- tape.equals(value, 'z3vzxp8k4VbTshwYpcaQQwrD9h9AZLzQjo3Dvx8sLRUdziUfmnB', 'transactionHash')
85
-
86
-
87
- try {
88
- value = await chain.validateBlock(chain.chain[0], chain.chain[1], await chain.difficulty(), await chain.getUnspentForAddress('8HFTVVfRMeL1sASrsdp6mvqDW9pvSD4AKySPEq3So16Wo1mpgY'))
89
- tape.equals(value, true, 'validateBlock')
90
-
91
- } catch (e) {
92
- console.warn({e});
93
- } finally {
94
-
95
- }
96
-
97
- setTimeout(function () {
98
- resolve()
99
- }, 200);
100
- })
101
- });
102
- await testChain()
103
- process.exit(0)
104
-
105
-
106
- })()