def __init__(self): super(Wallet, self).__init__() self.current_height = 0 self.isrunning = True self.isclosed = False self.indexeddb = IndexedDBWallet() self.node = RemoteNode(url='http://10.84.136.112:20332')
def get_last_height(net): assert net in ['testnet', 'mainnet'], 'Wrong Net' netPortDit = {'testnet': '20332', 'mainnet': '10332'} seeds = ['seed' + '%s' % i for i in range(1, 6)] heights = [] for seed in seeds: rn = RemoteNode('http://' + seed + '.neo.org:' + netPortDit[net]) try: height = rn.getBlockCount() except: height = 0 heights.append(height) print 'heights:%s' % heights return max(heights)
def send_transaction_to_node(cls, regtx, tran, net, node=RPC_NODE): try: url = 'http://' + node + (':20332' if 'testnet' == net else ':10332') RN = RemoteNode(url) r = RN.sendRawTransaction(regtx) if r.has_key('error') and r['error']: #print '-'*5,'raw:',regtx return False, r['error']['message'] + 'regtx:%s' % regtx if r['result']: txid = cls.compute_txid(tran) #print '-'*5,'txid:',txid return True, txid else: #print '-'*5,'raw:',regtx return False, 'broadcast falure' except Exception as e: #print '*'*5,'Exception','*'*5,e return False, 'Exception:%s' % e
def pay(payer_id, payees, asset): wallet_db = IndexedDBWallet() # step 1: get payer account payer = wallet_db.queryAccount(work_id=payer_id) if payer == None: print '%s : not exist payer block chain account' % payer_id return 2 payer_acc = Account(payer['pri_key']) contract = Contract() contract.createSignatureContract(payer_acc.publicKey) # step 2: load payer available coins coins = wallet_db.loadCoins(address=payer['address'], asset=asset) # step 3: select coins wallet = Wallet() selected_coins = wallet.selectCoins(coins, payees) if len(selected_coins) == 0: print 'no enough coins' return 5 change = sum([int(c.value) for c in selected_coins]) - sum( [int(p['amount']) for p in payees]) # step 4: construct outputs outputs = [] payee_accs = {} for p in payees: payee = wallet_db.queryAccount(work_id=p['work_id']) if payee == None: print '%s : not exist payee block chain account' % payer_id return 3 acc = Account(payee['pri_key']) output = TransactionOutput(AssetId=asset, Value=p['amount'], ScriptHash=acc.scriptHash) outputs.append(output) payee_accs[acc.scriptHash] = acc # add change output if change > 0: outputs.append( TransactionOutput(AssetId=asset, Value=change, ScriptHash=payer_acc.scriptHash)) payee_accs[payer_acc.scriptHash] = payer_acc # step 5: construct inputs inputs = [ TransactionInput(prevHash=c.txid, prevIndex=c.idx) for c in selected_coins ] # step 6: make transaction tx = Transaction(inputs, outputs) stream = MemoryStream() writer = BinaryWriter(stream) tx.serializeUnsigned(writer) reg_tx = stream.toArray() txid = tx.ensureHash() print 'TX ->', repr(reg_tx) print 'TXID ->', txid # step 7: Signature Redeem_script = contract.redeemScript sk = SigningKey.from_string(binascii.unhexlify(payer_acc.privateKey), curve=NIST256p, hashfunc=hashlib.sha256) signature = binascii.hexlify( sk.sign(binascii.unhexlify(reg_tx), hashfunc=hashlib.sha256)) regtx = reg_tx + '014140' + signature + '23' + Redeem_script # step 8: sendRawTransaction node = RemoteNode(url='http://10.84.136.112:20332') response = node.sendRawTransaction(regtx) # step 9: update coin status if response['result'] == True: incoming = [] for i in range(len(outputs)): coin = Coin(txid=txid, idx=i, value=outputs[i].Value, asset=asset, address=payee_accs[outputs[i].ScriptHash].address, status=CoinState.Unconfirmed) incoming.append(coin) wallet_db.onSendTransaction(spending=selected_coins, incoming=incoming) return 0 else: return 6
try: result = DB.blocks.insert_one({'_id':num},mongo_block) print '->', num, 'at %f seconds' % (time.time() - start_time) except DuplicateKeyError: print 'duplicate block %s' % num def sync(): while True: current_height = RN.getBlockCount() print 'current_height',current_height blocks_num = DB.blocks.count() if blocks_num <= current_height: for i in xrange(blocks_num, current_height+1): sync_block(i) if __name__ == "__main__": try: parser = argparse.ArgumentParser() parser.add_argument("-d", "--db", default='antshares', help="verify database name, default antshares") parser.add_argument("-n", "--node", default='http://127.0.0.1:20332', help="remote node to sync blockchain data,default http://127.0.0.1:20332") parser.add_argument("-m", "--mongodb", default='127.0.0.1:27017', help="mongodb for store data,default 127.0.0.1:27017") args = parser.parse_args() RN = RemoteNode(args.node) MC = MongoClient('mongodb://' + args.mongodb + '/') DB = MC[args.db] sync() except Exception as e: print e sys.exit()
def pay(payer_id, payees, asset): wallet_db = IndexedDBWallet() # step 1: get payer account payer = wallet_db.queryAccount(work_id=payer_id) if payer == None: print '%s : not exist payer block chain account' % payer_id return 2 payer_acc = Account(payer['pri_key']) contract = Contract() contract.createSignatureContract(payer_acc.publicKey) # step 2: load payer available coins coins = wallet_db.loadCoins(address=payer['address'],asset=asset) # step 3: select coins wallet = Wallet() selected_coins = wallet.selectCoins(coins, payees) if len(selected_coins) == 0: print 'no enough coins' return 5 change = sum([int(c.value) for c in selected_coins]) - sum([int(p['amount']) for p in payees]) # step 4: construct outputs outputs = [] payee_accs = {} for p in payees: payee = wallet_db.queryAccount(work_id=p['work_id']) if payee == None: print '%s : not exist payee block chain account' % payer_id return 3 acc = Account(payee['pri_key']) output = TransactionOutput(AssetId=asset, Value=p['amount'], ScriptHash=acc.scriptHash) outputs.append(output) payee_accs[acc.scriptHash] = acc # add change output if change > 0: outputs.append(TransactionOutput(AssetId=asset,Value=change,ScriptHash=payer_acc.scriptHash)) payee_accs[payer_acc.scriptHash] = payer_acc # step 5: construct inputs inputs = [TransactionInput(prevHash=c.txid, prevIndex=c.idx) for c in selected_coins] # step 6: make transaction tx = Transaction(inputs, outputs) stream = MemoryStream() writer = BinaryWriter(stream) tx.serializeUnsigned(writer) reg_tx = stream.toArray() txid = tx.ensureHash() print 'TX ->', repr(reg_tx) print 'TXID ->',txid # step 7: Signature Redeem_script = contract.redeemScript sk = SigningKey.from_string(binascii.unhexlify(payer_acc.privateKey), curve=NIST256p, hashfunc=hashlib.sha256) signature = binascii.hexlify(sk.sign(binascii.unhexlify(reg_tx),hashfunc=hashlib.sha256)) regtx = reg_tx + '014140' + signature + '23' + Redeem_script # step 8: sendRawTransaction node = RemoteNode(url='http://10.84.136.112:20332') response = node.sendRawTransaction(regtx) # step 9: update coin status if response['result'] == True: incoming = [] for i in range(len(outputs)): coin = Coin(txid=txid, idx=i, value=outputs[i].Value, asset=asset, address=payee_accs[outputs[i].ScriptHash].address,status=CoinState.Unconfirmed) incoming.append(coin) wallet_db.onSendTransaction(spending=selected_coins,incoming=incoming) return 0 else: return 6
class Wallet(object): """docstring for Wallet""" def __init__(self): super(Wallet, self).__init__() self.current_height = 0 self.isrunning = True self.isclosed = False self.indexeddb = IndexedDBWallet() self.node = RemoteNode(url='http://10.84.136.112:20332') def getCoinVersion(self): return chr(0x17) def getWalletHeight(self): # Need or Not? return self.current_height def toAddress(self, scripthash): return scripthash_to_address(scripthash) def findUnSpentCoins(self, scriptHash): """ :return: Coin[]""" return self.indexeddb.findCoins(self.toAddress(scriptHash), status=CoinState.Unspent) def makeTransaction(self, tx, account): """Make Transaction""" if tx.outputs == None: raise ValueError, 'Not correct Address, wrong length.' if tx.attributes == None: tx.attributes = [] coins = self.findUnSpentCoins(account.scriptHash) tx.inputs, tx.outputs = self.selectInputs(tx.outputs, coins, account, tx.systemFee) # Make transaction stream = MemoryStream() writer = BinaryWriter(stream) tx.serializeUnsigned(writer) reg_tx = stream.toArray() tx.ensureHash() txid = tx.hash # RedeenScript contract = Contract() contract.createSignatureContract(account.publicKey) Redeem_script = contract.redeemScript # Add Signature sk = SigningKey.from_string(binascii.unhexlify(account.privateKey), curve=NIST256p, hashfunc=hashlib.sha256) signature = binascii.hexlify(sk.sign(binascii.unhexlify(reg_tx),hashfunc=hashlib.sha256)) regtx = reg_tx + '014140' + signature + '23' + Redeem_script # sendRawTransaction print regtx response = self.node.sendRawTransaction(regtx) import json print response return txid def selectInputs(self, outputs, coins, account, fee): scripthash = account.scriptHash if len(outputs) > 1 and len(coins) < 1: raise Exception, 'Not Enought Coins' # Count the total amount of change coin = itertools.groupby(sorted(coins, key=lambda x: x.asset), lambda x: x.asset) coin_total = dict([(k, sum(int(x.value) for x in g)) for k,g in coin]) # Count the pay total pays = itertools.groupby(sorted(outputs, key=lambda x: x.AssetId), lambda x: x.AssetId) pays_total = dict([(k, sum(int(x.Value) for x in g)) for k,g in pays]) if int(fee.f) > 0: if ANTCOIN in pays_total.iterkeys(): pays_total[ANTCOIN] += int(fee.f) else: pays_total[ANTCOIN] = int(fee.f) # Check whether there is enough change for asset, value in pays_total.iteritems(): if not coin_total.has_key(asset): raise Exception, 'Coins does not contain asset {asset}.'.format(asset=asset) if coin_total.get(asset) - value < 0: raise Exception, 'Coins does not have enough asset {asset}, need {amount}.'.format(asset=asset, amount=value) # res: used Coins # change: change in outpus res = [] change = [] # Copy the parms _coins = coins[:] # Find whether have the same value of change for asset, value in pays_total.iteritems(): for _coin in _coins: if asset == _coin.asset and value == int(_coin.value): # Find the coin res.append(TransactionInput(prevHash=_coin.txid, prevIndex=_coin.idx)) _coins.remove(_coin) break else: # Find the affordable change affordable = sorted([i for i in _coins if i.asset == asset and int(i.value) >= value], key=lambda x: int(x.value)) # Use the minimum if exists if len(affordable) > 0: res.append(TransactionInput(prevHash=affordable[0].txid, prevIndex=affordable[0].idx)) _coins.remove(affordable[0]) # If the amout > value, set the change amount = int(affordable[0].value) if amount > value: change.append(TransactionOutput(AssetId=asset, Value=str(amount-value), ScriptHash=scripthash)) else: # Calculate the rest of coins rest = sorted([i for i in _coins if i.asset == asset], key=lambda x: int(x.value), reverse=True) amount = 0 for _coin in rest: amount += int(_coin.value) res.append(TransactionInput(prevHash=_coin.txid, prevIndex=_coin.idx)) _coins.remove(_coin) if amount == value: break elif amount > value: # If the amout > value, set the change change.append(TransactionOutput(AssetId=asset, Value=str(amount-value), ScriptHash=scripthash)) break return res, outputs + change def selectCoins(self, coins, outputs): """the simplest alg of selecting coins""" total = sum([int(out['amount']) for out in outputs]) cs = sorted(coins,key=lambda c:c.value,reverse=True) print total inputs = [] # has no enough coins if sum([int(c.value) for c in coins]) < total: return inputs for i in range(len(cs)): #step 1: find the coin with value==total if cs[i].value == total: inputs = [cs[i],] break #step 2: find the min coin with value>total if cs[0].value > total and cs[i].value<total: inputs = [cs[i-1],] break #step 3: find the min(max coins) with sum(coins)>= total inputs.append(cs[i]) if cs[0].value<total and sum([i.value for i in inputs]) >= total: break return inputs def addressToScriptHash(self, address): data = b58decode(address) if len(data) != 25: raise ValueError, 'Not correct Address, wrong length.' if data[0] != self.getCoinVersion(): raise ValueError, 'Not correct CoivVersion' scriptHash = binascii.hexlify(data[1:21]) if self.toAddress(scriptHash) == address: return scriptHash else: raise ValueError, 'Not correct Address, something wrong in Address[-4:].' def createAccount(self): return Account() def getAccount(self, privKey=None): return Account(privKey)