Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d832343

Browse files
committed
Merge pull request #1196 from achamely/master
PendingTX support
2 parents aeee7d4 + 5cd1c7b commit d832343

20 files changed

Lines changed: 838 additions & 334 deletions

Gruntfile.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ module.exports = function(grunt) {
2323
directory: 'www/bower_components/bitcoinjs-lib'
2424
}
2525
},
26-
"crypto-js": {
26+
"crypto-js": {
2727
options: {
2828
repository: "https://github.com/scintill/crypto-js.git",
2929
branch: 'master',
3030
directory: 'www/bower_components/bitcoinjs-lib/src/crypto-js'
3131
}
32-
}
32+
}
3333
},
3434
shell: {
3535
html: {
@@ -59,14 +59,14 @@ module.exports = function(grunt) {
5959
},
6060
command: 'npm install ; npm run minify'
6161
},
62-
"omni-websocket": {
63-
options: {
64-
execOptions: {
65-
cwd: "api/websocket"
66-
}
67-
},
68-
command: 'npm install'
69-
},
62+
"omni-websocket": {
63+
options: {
64+
execOptions: {
65+
cwd: "api/websocket"
66+
}
67+
},
68+
command: 'npm install'
69+
},
7070
cryptolib: {
7171
options: {
7272
stdout: true,

api/balancehelper.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import json
2+
from msc_apps import *
3+
4+
def get_balancedata(address):
5+
addr = re.sub(r'\W+', '', address) #check alphanumeric
6+
ROWS=dbSelect("""select
7+
f1.propertyid, sp.propertytype, f1.balanceavailable, f1.pendingpos, f1.pendingneg
8+
from
9+
(select
10+
COALESCE(s1.propertyid,s2.propertyid) as propertyid, COALESCE(s1.balanceavailable,0) as balanceavailable,
11+
COALESCE(s2.pendingpos,0) as pendingpos,COALESCE(s2.pendingneg,0) as pendingneg
12+
from
13+
(select propertyid,balanceavailable
14+
from addressbalances
15+
where address=%s) s1
16+
full join
17+
(SELECT atx.propertyid,
18+
sum(CASE WHEN atx.balanceavailablecreditdebit > 0 THEN atx.balanceavailablecreditdebit ELSE 0 END) AS pendingpos,
19+
sum(CASE WHEN atx.balanceavailablecreditdebit < 0 THEN atx.balanceavailablecreditdebit ELSE 0 END) AS pendingneg
20+
from
21+
addressesintxs atx, transactions tx
22+
where
23+
atx.txdbserialnum=tx.txdbserialnum
24+
and tx.txstate='pending'
25+
and tx.txdbserialnum<-1
26+
and atx.address=%s
27+
group by
28+
atx.propertyid) s2
29+
on s1.propertyid=s2.propertyid) f1
30+
inner join smartproperties sp
31+
on f1.propertyid=sp.propertyid and (sp.protocol='Mastercoin' or sp.protocol='Bitcoin')
32+
order by f1.propertyid""",(addr,addr))
33+
34+
balance_data = { 'balance': [] }
35+
out, err = run_command(TIMEOUT+ 'sx balance -j ' + addr )
36+
for balrow in ROWS:
37+
cID = str(int(balrow[0])) #currency id
38+
sym_t = ('BTC' if cID == '0' else ('MSC' if cID == '1' else ('TMSC' if cID == '2' else 'SP' + cID) ) ) #symbol template
39+
#1 = new indivisible property, 2=new divisible property (per spec)
40+
divi = True if int(balrow[1]) == 2 else False
41+
res = { 'symbol' : sym_t, 'divisible' : divi, 'id' : cID }
42+
res['pendingpos'] = ('%.8f' % float(balrow[3])).rstrip('0').rstrip('.')
43+
res['pendingneg'] = ('%.8f' % float(balrow[4])).rstrip('0').rstrip('.')
44+
if cID == '0':
45+
#get btc balance from sx
46+
if err != None or out == '':
47+
btc_balance[ 'value' ] = int(-555)
48+
else:
49+
try:
50+
if balrow[4] < 0:
51+
res['value'] = int( json.loads( out )[0][ 'paid' ]) + int(balrow[4])
52+
else:
53+
res['value'] = int( json.loads( out )[0][ 'paid' ])
54+
except ValueError:
55+
btc_balance[ 'value' ] = int(-555)
56+
else:
57+
#get regular balance from db
58+
if balrow[4] < 0:
59+
#update the 'available' balance immediately when the sender sent something. prevent double spend
60+
res['value'] = ('%.8f' % float( (balrow[2]+balrow[4]) )).rstrip('0').rstrip('.')
61+
else:
62+
res['value'] = ('%.8f' % float(balrow[2])).rstrip('0').rstrip('.')
63+
64+
#res['reserved_balance'] = ('%.8f' % float(balrow[5])).rstrip('0').rstrip('.')
65+
balance_data['balance'].append(res)
66+
67+
#check if we got BTC data from DB, if not trigger manually add
68+
addbtc=True
69+
for x in balance_data['balance']:
70+
if "BTC" in x['symbol']:
71+
addbtc=False
72+
73+
if addbtc:
74+
btc_balance = { 'symbol': 'BTC', 'divisible': True, 'id' : 0 }
75+
if err != None or out == '':
76+
btc_balance[ 'value' ] = int(-555)
77+
else:
78+
try:
79+
btc_balance[ 'value' ] = int( json.loads( out )[0][ 'paid' ])
80+
except ValueError:
81+
btc_balance[ 'value' ] = int(-555)
82+
btc_balance['pendingpos'] = int(0)
83+
btc_balance['pendingneg'] = int(0)
84+
balance_data['balance'].append(btc_balance)
85+
86+
return balance_data

api/decode.py

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
from flask import Flask, abort, json, jsonify
2+
import hashlib
3+
import pybitcointools
4+
import decimal
5+
from rpcclient import *
6+
7+
app = Flask(__name__)
8+
app.debug = True
9+
10+
@app.route('/<rawhex>')
11+
def decode_handler(rawhex):
12+
return jsonify(decode(rawhex))
13+
14+
15+
def getinputs(rawtx):
16+
retval={'invalid':False, 'inputs':{}}
17+
for input in rawtx['vin']:
18+
prevtx=getrawtransaction(input['txid'])
19+
if prevtx['result']['vout'][input['vout']]['scriptPubKey']['type'] not in ['pubkeyhash','scripthash']:
20+
#Valid MP tx's only have pubkeyhash and scripthash as inputs
21+
retval['invalid']=True
22+
inputamount= int(decimal.Decimal(str( prevtx['result']['vout'][input['vout']]['value']))*decimal.Decimal(1e8))
23+
for addr in prevtx['result']['vout'][input['vout']]['scriptPubKey']['addresses']:
24+
if addr in retval['inputs']:
25+
retval['inputs'][addr] += inputamount
26+
else:
27+
retval['inputs'][addr] = inputamount
28+
return retval
29+
30+
31+
def decode(rawhex):
32+
33+
rawBTC = decoderawtransaction(rawhex)['result']
34+
sia=0
35+
reference=""
36+
inputs=getinputs(rawBTC)
37+
senders=inputs['inputs']
38+
for sender in senders:
39+
if senders[sender] > sia:
40+
reference = sender
41+
sia = senders[sender]
42+
43+
if reference == "":
44+
retval = {"Error":"Can\'t decode MP TX. No valid sending address found."}
45+
return {'Sender':reference,'BTC':rawBTC, 'MP':retval,'inputs':senders}
46+
47+
if inputs['invalid']:
48+
retval = {"Error":"Can\'t decode MP TX. Invalid input type detected"}
49+
return {'Sender':reference,'BTC':rawBTC, 'MP':retval,'inputs':senders}
50+
51+
52+
#senders = rawtx['result']['vout'][rawBTC['vin'][0]['vout']]['scriptPubKey']['addresses']
53+
#reference = senders[0]
54+
55+
#get all multisigs
56+
multisig_output = []
57+
dest=""
58+
for output in rawBTC['vout']:
59+
if output['scriptPubKey']['type'] == 'multisig':
60+
multisig_output.append(output) #grab msigs
61+
elif output['scriptPubKey']['type'] in ['pubkeyhash','scripthash']:
62+
try:
63+
for address in output['scriptPubKey']['addresses']:
64+
if address not in ['1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P','mpexoDuSkGGqvqrkrjiFng38QPkJQVFyqv'] and address not in reference:
65+
dest=address
66+
#return on first successful dest address per spec (highest vout)
67+
break
68+
except KeyError:
69+
pass
70+
71+
#extract compressed keys
72+
scriptkeys = []
73+
for output in multisig_output: #seqnums start at 1, so adjust range
74+
split_script = output['scriptPubKey']['asm'].split(' ')
75+
for val in split_script:
76+
if len(val) == 66:
77+
scriptkeys.append(val)
78+
79+
#filter keys that are ref
80+
nonrefkeys = []
81+
82+
#check for testnet addresses
83+
if reference[:1] in ['2','m','n']:
84+
#testnet address
85+
offset=111
86+
else:
87+
offset=0
88+
89+
for compressedkey in scriptkeys:
90+
if pybitcointools.pubtoaddr(compressedkey,offset) not in senders :
91+
nonrefkeys.append(compressedkey)
92+
93+
max_seqnum = len(nonrefkeys)
94+
sha_keys = [ hashlib.sha256(reference).digest().encode('hex').upper()] #first sha256 of ref addr, see class B for more info
95+
for i in range(max_seqnum):
96+
if i < (max_seqnum-1):
97+
sha_keys.append(hashlib.sha256(sha_keys[i]).digest().encode('hex').upper()) #keep sha'ing to generate more packets
98+
99+
pairs = []
100+
for i in range(len(nonrefkeys)):
101+
pairs.append((nonrefkeys[i], sha_keys[i] ))
102+
103+
packets = []
104+
for pair in pairs:
105+
obpacket = pair[0].upper()[2:-2]
106+
shaaddress = pair[1][:-2]
107+
print 'Obfus/SHA', obpacket, shaaddress
108+
datapacket = ''
109+
for i in range(len(obpacket)):
110+
if obpacket[i] == shaaddress[i]:
111+
datapacket = datapacket + '0'
112+
else:
113+
bin_ob = int('0x' + obpacket[i], 16)
114+
bin_sha = int('0x' + shaaddress[i], 16)
115+
xored = hex(bin_ob ^ bin_sha)[2:].upper()
116+
datapacket = datapacket + xored
117+
packets.append(datapacket)
118+
119+
long_packet = ''
120+
for packet in packets:
121+
print 'Decoded packet #' + str(packet[0:2]) + ' : ' + packet
122+
long_packet += packet[2:]
123+
124+
retval=""
125+
if long_packet[4:8] == '0032':
126+
#Create Fixed Issuance
127+
spare_bytes = ''.join(long_packet[22:])
128+
#DEBUG print spare_bytes.split('00')
129+
len_var_fields = len(''.join(spare_bytes.split('00')[0:5])+'0000000000')
130+
#DEBUG print len_var_fields, spare_bytes[len_var_fields:len_var_fields+16],spare_bytes
131+
132+
retval = { 'TxVersion': int(long_packet[0:4],16),
133+
'TxType': int(long_packet[4:8],16),
134+
'TxTypeString': 'Create Fixed Issuance',
135+
'Ecosystem': int(long_packet[8:10],16),
136+
'Property Type': int(long_packet[10:14],16),
137+
'Previous Property ID': int(long_packet[14:22],16),
138+
'Property Category': spare_bytes.split('00')[0].decode('hex'),
139+
'Property Subcategory': spare_bytes.split('00')[1].decode('hex'),
140+
'Property Name': spare_bytes.split('00')[2].decode('hex'),
141+
'Property URL': spare_bytes.split('00')[3].decode('hex'),
142+
'Property Data': ''.join(spare_bytes.split('00')[4]).decode('hex'),
143+
'Number of Properties: ': int(str(int(spare_bytes[len_var_fields:len_var_fields+16],16)))
144+
}
145+
146+
if long_packet[4:8] == '0033':
147+
#Create Variable issuance (Crowdsale)
148+
spare_bytes = ''.join(long_packet[22:])
149+
#DEBUG print spare_bytes.split('00')
150+
len_var_fields = len(''.join(spare_bytes.split('00')[0:5])+'0000000000')
151+
#DEBUG print len_var_fields, spare_bytes[len_var_fields:len_var_fields+16],spare_bytes
152+
153+
retval = { 'TxVersion': int(long_packet[0:4],16),
154+
'TxType': int(long_packet[4:8],16),
155+
'TxTypeString': 'Create Variable Issuance (Crowdsale)',
156+
'Ecosystem': int(long_packet[8:10],16),
157+
'Property Type': int(long_packet[10:14],16),
158+
'Previous Property ID': int(long_packet[14:22],16),
159+
'Property Category': spare_bytes.split('00')[0].decode('hex'),
160+
'Property Subcategory': spare_bytes.split('00')[1].decode('hex'),
161+
'Property Name': spare_bytes.split('00')[2].decode('hex'),
162+
'Property URL': spare_bytes.split('00')[3].decode('hex'),
163+
'Property Data': ''.join(spare_bytes.split('00')[4]).decode('hex'),
164+
'PropertyID Desired': str(int(spare_bytes[len_var_fields:len_var_fields+8],16)),
165+
'Number of Properties': str(int(spare_bytes[len_var_fields+8:len_var_fields+8+16],16)),
166+
'Deadline': str(int(spare_bytes[len_var_fields+8+16:len_var_fields+8+16+16],16)),
167+
'Earlybird Bonus': str(int(spare_bytes[len_var_fields+8+16+16:len_var_fields+8+16+16+2],16)),
168+
'Percentage for Issuer': str(int(spare_bytes[len_var_fields+8+16+16+2:len_var_fields+8+16+16+2+2],16))
169+
}
170+
171+
if long_packet[4:8] == '0000':
172+
#simple send
173+
retval = { 'TxVersion': int(long_packet[0:4],16),
174+
'TxType': int(long_packet[4:8],16),
175+
'TxTypeString': 'Simple Send',
176+
'PropertyID': int(long_packet[8:16],16),
177+
'Amount': int(long_packet[16:32],16)
178+
}
179+
180+
if long_packet[4:8] == '0003':
181+
#STO
182+
retval = { 'TxVersion': int(long_packet[0:4],16),
183+
'TxType': int(long_packet[4:8],16),
184+
'TxTypeString': 'Send To Owners',
185+
'PropertyID': int(long_packet[8:16],16),
186+
'Amount': int(long_packet[16:32],16)
187+
}
188+
189+
if long_packet[4:8] == '0014':
190+
#DEx Sell Offer
191+
retval = { 'TxVersion': int(long_packet[0:4],16),
192+
'TxType': int(long_packet[4:8],16),
193+
'TxTypeString': 'DEx Sell Offer',
194+
'PropertyID': int(long_packet[8:16],16),
195+
'Amount': int(long_packet[16:32],16),
196+
'BTCDesired': int(long_packet[32:48],16),
197+
'TimePeriod': int(long_packet[48:50],16),
198+
'FeeRequired': int(long_packet[50:66],16),
199+
'Action': int(long_packet[66:68],16)
200+
}
201+
202+
if long_packet[4:8] == '0035':
203+
#Close Crowdsale Manually
204+
retval = { 'TxVersion': int(long_packet[0:4],16),
205+
'TxType': int(long_packet[4:8],16),
206+
'TxTypeString': 'Close Crowdsale Manually',
207+
'PropertyID': int(long_packet[8:16],16)
208+
}
209+
210+
if long_packet[4:8] == '0037':
211+
#grant properties
212+
retval = { 'TxVersion': int(long_packet[0:4],16),
213+
'TxType': int(long_packet[4:8],16),
214+
'TxTypeString': 'Grant Properties',
215+
'PropertyID': int(long_packet[8:16],16),
216+
'Amount': int(long_packet[16:32],16)
217+
}
218+
219+
if long_packet[4:8] == '0038':
220+
#revoke properties
221+
retval = { 'TxVersion': int(long_packet[0:4],16),
222+
'TxType': int(long_packet[4:8],16),
223+
'TxTypeString': 'Revoke Properties',
224+
'PropertyID': int(long_packet[8:16],16),
225+
'Amount': int(long_packet[16:32],16)
226+
}
227+
228+
if retval == "":
229+
retval = {"Error":"Can\'t decode MP TX"}
230+
dest = ""
231+
print retval
232+
return {'Sender':reference,'Receiver':dest,'MP':retval,'BTC':rawBTC, 'inputs':senders}

0 commit comments

Comments
 (0)