-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.js
113 lines (97 loc) · 2.83 KB
/
index.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
let { createHash } = require('crypto')
let { addressHash, verify } = require('coins')
// TODO: put contracts in a queue ordered by timelock maturity time,
// automatically pay out to Alice address once timelock is passed
// ?
module.exports = {
// close an existing HTLC
onInput (input, tx, state, ctx) {
// get fields from input
let {
contractAddress,
secret,
pubkey,
signature
} = input
// find existing contract by address
let contract = state[contractAddress]
if (contract == null) {
throw Error(`No HTLC with address "${contractAddress}"`)
}
// must spend exact amount of tokens held in contract
if (input.amount !== contract.amount) {
throw Error('Amount does not match contract')
}
// get fields from contract
let {
hash,
locktime,
aliceAddress,
bobAddress
} = contract
if (ctx.time < locktime) {
// chain has not reached locktime, contract can be
// redeemed by Bob if he has the secret value.
// must have correct secret
if (!sha256(secret).equals(hash)) {
throw Error('Invalid secret')
}
// must have Bob's pubkey
// TODO: address hashing and signature verification from coins
if (addressHash(pubkey) !== bobAddress) {
throw Error('Invalid public key')
}
} else {
// locktime has passed, contract pays back to Alice.
// must have Alice's pubkey
// TODO: address hashing and signature verification from coins
if (addressHash(pubkey) !== aliceAddress) {
throw Error('Invalid public key')
}
}
// must be signed by the pubkey (Alice or Bob)
if (!verify(pubkey, signature, tx.sigHash)) {
throw Error('Invalid signature')
}
// we don't need this contract in the state anymore
delete state[contractAddress]
},
// create a new HTLC
onOutput (output, tx, state, ctx) {
// get fields from output
let {
hash,
locktime,
aliceAddress,
bobAddress,
amount
} = output
if (!Buffer.isBuffer(hash) || hash.length !== 32) {
throw Error('Hash must be a 32-byte Buffer')
}
if (!Number.isInteger(locktime)) {
throw Error('Locktime must be an integer')
}
if (locktime > Number.MAX_SAFE_INT) {
throw Error('Locktime must be < 2^53')
}
if (locktime <= ctx.time) {
throw Error('Locktime must be > current time')
}
// add contract to state
let address = addressHash([ locktime, hash, aliceAddress, bobAddress ].join())
if (state[address] != null) {
throw Error('A contract with this address already exists')
}
state[address] = {
hash,
locktime,
aliceAddress,
bobAddress,
amount
}
}
}
function sha256 (data) {
return createHash('sha256').update(data).digest()
}