Repository navigation
Expand file tree
/
Copy pathchit.js
More file actions
164 lines (150 loc) · 6.24 KB
/
Copy pathchit.js
File metadata and controls
164 lines (150 loc) · 6.24 KB
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//State machine map for chit transactions
//Copyright MyCHIPs.org; See license in root of this package
// -----------------------------------------------------------------------------
// A positive chit implies credit flowing in the normal direction where the foil
// holder owes value to the stock holder. A negative amount means credit
// flowing in the opposite, or up-hill, direction:
// Stock does a positive chit: stock+ Debit: Request for payment
// Stock does a negative chit: stock- Credit: Grant of refund (or lift)
// Foil does a positive chit: foil+ Credit: Voluntary payment
// Foil Does a negative chit: foil- Debit: Request for refund (or lift)
// -----------------------------------------------------------------------------
//- TODO:
//-
const SubCrypto = require('./subcrypto.js')
const { Log } = require('wyclif')
var log = Log('chit')
var subCrypto = new SubCrypto(log)
module.exports = function(pm) {
this.pm = pm
this.test = pm.test
this.db = pm.db
this.signCheck = function(info, passCB, failCB) {
let chit = info.object
, { pub } = info
, { by, date, memo, ref, tally, type, units, uuid, sign } = chit
, message = {by, date, memo, ref, tally, type, units, uuid} //What gets signed
const doVerify = (pubKey, msg, signature) => { //Validate or pass
if (this.test)
return Promise.resolve()
if (!signature)
return Promise.reject(new Error('Missing signature.'))
return subCrypto.verify(pubKey, msg, signature).then(isValid => {
if (!isValid) {
return Promise.reject(new Error('Invalid chit signature'))
}
})
}
const pubCheck = (pubKey) => { //Need a public key from the DB?
//log.debug("pubCheck:", pubKey)
if (pubKey)
return Promise.resolve(pubKey) //;log.debug("Need pub:", tally, by)
return new Promise((resolve, reject) => {
let sql = "select part_cert->'public' as pub from mychips.tallies_v where tally_uuid = $1 and tally_type != $2"
, parms = [tally, by] //;log.debug('Sql:', sql, parms)
this.db.query(sql, parms, (err, res) => {
let row = res && res.rows ? res.rows[0] : {} //;log.debug('row:', JSON.stringify(row))
if (err) reject(err)
else resolve(row.pub)
})
})
}
pubCheck(pub)
.then(surePub => doVerify(surePub, message, sign))
.then(() => passCB(true))
.catch(error => {
log.error('signCheck: ' + chit.tally + ':' + chit.uuid + '; ' + error.message)
if (typeof failCB === 'function') {
failCB(error)
} else {
passCB(false, error)
}
})
}
this.local_pend = function(msg, pm) { //A draft invoice has been created by the user
log.debug("Local pend:", msg)
let pmsg = Object.assign({}, msg)
, dmsg = {target:msg.target, to: msg.from, object: {tally:msg.object.tally, uuid:msg.object.uuid}}
//log.debug("Chit local pend:", dmsg, dmsg.to.cuid, dmsg.uuid)
pm.peerTransmit(pmsg, ()=>{ //If I can transmit it,
pm.dbProcess(dmsg, { //then mark it as sent
context: ['A.draft.pend', 'A.void.pend'],
update: {status: 'pend'}, clear: true
}, null, ()=>pm.dbError(dmsg))
}, ()=>pm.peerError(pmsg))
}
this.local_void = function(msg, pm) { //Our user has rejected an invoice
log.debug("Local void:", msg)
let pmsg = Object.assign({}, msg)
, dmsg = {target:msg.target, to: msg.from, object: {tally:msg.object.tally, uuid:msg.object.uuid}}
pm.peerTransmit(pmsg, ()=>{ //If I can notify the peer
pm.dbProcess(dmsg, { //then mark it as denied
context: ['L.pend.void'],
update: {status: 'void'}, clear: true
}, null, ()=>pm.dbError(dmsg))
}, ()=>pm.peerError(pmsg))
}
this.local_good = function(msg, pm) { //Our user has approved an invoice
log.debug("Local good:", msg)
let pmsg = Object.assign({}, msg)
, dmsg = {target:msg.target, to: msg.from, object: {tally:msg.object.tally, uuid:msg.object.uuid}}
delete pmsg.pub
this.signCheck(msg, () => { //Is the signature valid?
pm.dbProcess(dmsg, { //mark it good on our end
context: ['L.pend.good', 'L.draft.good'],
update: {status: 'good', chain_msg: {cmd: 'loc'}}, clear: true
}, (chit) => {
let {status, chain} = chit
if (status = 'open' && chain) { //Attempt to notify peer
pmsg.object.chain = Object.assign({cmd: 'new'}, chain)
//log.debug("LG:", JSON.stringify(pmsg))
pm.peerTransmit(pmsg, null, ()=>pm.peerError(pmsg))
}
}, ()=>pm.dbError(dmsg))
}, () => {
pm.dbProcess(dmsg, { //set it back to draft
context: ['L.pend.good', 'L.draft.good'],
update: {status: 'pend'}, clear: true
}, null, e=>pm.dbError(dmsg,e))
})
}
this.local_chain = function(msg, pm) { //Outbound consensus packet
log.debug("Local chain:", msg)
let pmsg = Object.assign({}, msg)
, dmsg = {target:msg.target, to: msg.from, action:msg.action, object: {tally:msg.object.tally, uuid:msg.object.uuid}}
pm.peerTransmit(pmsg, () => {
pm.dbProcess(dmsg, //mark packet as sent in our DB
true, null, ()=>pm.dbError(dmsg))
}, ()=>pm.peerError(pmsg))
}
this.remote_pend = function(msg, pm) { //The partner has sent us a request for payment
log.debug("Remote pend:", msg)
pm.dbProcess(msg, {
context: ['null', 'L.void'],
upsert: {status: 'pend'}
}, null, ()=>pm.dbError(msg))
}
this.remote_void = function(msg, pm) { //The partner will not make payment
log.debug("Remote void:", msg)
pm.dbProcess(msg, {
context: ['A.pend'],
update: {signature: null, status: 'void'}
}, null, ()=>pm.dbError(msg))
}
this.remote_good = function(msg, pm) { //The partner has sent an approved transaction
delete msg.pub
log.debug("Remote good:", msg)
this.signCheck(msg, () => { //Is the signature valid?
pm.dbProcess(msg, {
context: ['null','A.pend'],
upsert: {status: 'good'}
}, null, ()=>pm.dbError(msg))
}, () => { //What to do with invalid chit
log.error("Dropping invalid remote chit:", JSON.stringify(msg))
})
}
this.remote_chain = function(msg, pm) { //Consensus message from partner
log.debug("Remote chain:", msg)
pm.dbProcess(msg, false, null, ()=>pm.dbError(msg))
}
}