PKc,GYAlibcontractvm/__init__.py# Copyright (c) 2015 Davide Gessa # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. PKxeGQ>XXlibcontractvm/Wallet.py# Copyright (c) 2015 Davide Gessa # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. from pycoin.networks import * from pycoin.key import Key from pycoin.key.BIP32Node import BIP32Node from pycoin import encoding from pycoin.ecdsa import is_public_pair_valid, generator_secp256k1, public_pair_for_x, secp256k1 from pycoin.serialize import b2h, h2b from pycoin.tx import * from pycoin.tx.tx_utils import sign_tx, create_tx from pycoin.tx.Spendable import Spendable from pycoin.tx.TxOut import TxOut from pycoin.tx.script import tools from pycoin.encoding import bitcoin_address_to_hash160_sec, is_sec_compressed, public_pair_to_sec, secret_exponent_to_wif, public_pair_to_bitcoin_address, wif_to_tuple_of_secret_exponent_compressed, sec_to_public_pair, public_pair_to_hash160_sec, wif_to_secret_exponent from pycoin.tx.pay_to import address_for_pay_to_script, build_hash160_lookup import logging import json import requests import binascii from . import Log logger = logging.getLogger('libcontractvm') class Wallet: def __init__ (self, chain = 'XTN', address = None, wif = None, wallet_file = None): self.address = address self.wif = wif self.wallet_file = wallet_file self.chain = chain if self.address == None or self.wif == None: if self.wallet_file != None: try: # Try to load f = open (self.wallet_file, 'r') d = f.read () f.close () d = d.split (',') self.address = d[0] self.wif = d[1].replace ('\n', '') logger.info ('Loaded wallet from %s', self.wallet_file) except: self.address = None self.wif = None logger.info ('Failed to load wallet from %s', self.wallet_file) # Generate new wallet if self.wif == None: logger.info ('Generating new key pair') (self.address, self.wif) = self._gen () if self.wallet_file != None: # Try to save f = open (self.wallet_file, 'w') f.write (self.address+','+self.wif) f.close () logger.info ('Saved wallet to %s', self.wallet_file) else: if self.wallet_file != None: f = open (self.wallet_file, 'w') f.write (self.address+','+self.wif) f.close () logger.info ('Setting up player %s', self.address) def _gen (self): logger.debug ('Generating entropy for new wallet...') # Generate entropy entropy = bytearray() try: entropy.extend(open("/dev/random", "rb").read(64)) except Exception: print("warning: can't use /dev/random as entropy source") entropy = bytes(entropy) if len(entropy) < 64: raise OSError("can't find sources of entropy") secret_exponent = int(binascii.hexlify (entropy)[0:32], 16) wif = secret_exponent_to_wif(secret_exponent, compressed=True, wif_prefix=wif_prefix_for_netcode (self.chain)) key = Key (secret_exponent=secret_exponent, netcode=self.chain) return (str (key.address ()), str (key.wif ())) def createTransaction (self, outs, fee): # Create the signed transaction spendables = self._spendables (int (fee)) #print (spendables) if len (spendables) == 0: logger.error ('No spendables available') return None t = create_tx(spendables, [self.address], fee=int (fee)) for o in outs: t.txs_out.append (TxOut (0.0, tools.compile (o))) secret_exponent = wif_to_secret_exponent(self.wif, allowable_wif_prefixes=[wif_prefix_for_netcode (self.chain)]) d = {} d.update (build_hash160_lookup([secret_exponent])) t.sign (d) txhash = (t.as_hex ()) return txhash def getAddress (self): return self.address def getBalance (self): return None def getPair (self): return (self.address, self.wif) PKzX{G ? ? libcontractvm/WalletChainSo.py# Copyright (c) 2015 Davide Gessa # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. from pycoin.networks import * from pycoin.key import Key from pycoin.key.BIP32Node import BIP32Node from pycoin import encoding from pycoin.ecdsa import is_public_pair_valid, generator_secp256k1, public_pair_for_x, secp256k1 from pycoin.serialize import b2h, h2b from pycoin.tx import * from pycoin.tx.tx_utils import sign_tx, create_tx from pycoin.tx.Spendable import Spendable from pycoin.tx.TxOut import TxOut from pycoin.tx.script import tools from pycoin.encoding import bitcoin_address_to_hash160_sec, is_sec_compressed, public_pair_to_sec, secret_exponent_to_wif, public_pair_to_bitcoin_address, wif_to_tuple_of_secret_exponent_compressed, sec_to_public_pair, public_pair_to_hash160_sec, wif_to_secret_exponent from pycoin.tx.pay_to import address_for_pay_to_script, build_hash160_lookup import logging import json import requests import binascii import random from libcontractvm import Wallet from . import Log logger = logging.getLogger('libcontractvm') class WalletChainSo (Wallet.Wallet): def __init__ (self, chain = 'XLT', address = None, wif = None, wallet_file = None): super (WalletChainSo, self).__init__ (chain, address, wif, wallet_file) def _chaincodeToChainSoName (self, code): if self.chain == 'XTN': code = 'BTCTEST' elif self.chain == 'XDT': code = 'DOGETEST' elif self.chain == 'XLT': code = 'LTCTEST' else: code = self.chain return code def _spendables (self, value): code = self._chaincodeToChainSoName (self.chain) u = 'https://chain.so/api/v2/get_tx_unspent/'+code+'/'+self.address #print (u) d = requests.get (u, headers={'content-type': 'application/json'}).json() sps = [] tot = 0 random.shuffle (d['data']['txs']) for s in d['data']['txs']: #if int (s['confirmations']) > 0: txid = '' for x in range (len (s['txid']), -2, -2): txid += s['txid'][x:x+2] tot += int (float (s['value']) * 100000000) sps.append (Spendable.from_dict ({'coin_value': int (float (s['value']) * 100000000), 'script_hex': s['script_hex'], 'tx_hash_hex': txid, 'tx_out_index': int (s['output_no'])})) if tot >= value: return sps return sps def getBalance (self): code = self._chaincodeToChainSoName (self.chain) u = 'https://chain.so/api/v2/get_address_balance/'+code+'/'+self.address d = requests.get (u, headers={'content-type': 'application/json'}).json() return float (d['data']['confirmed_balance']) + float (d['data']['unconfirmed_balance']) PK~G>~!libcontractvm/ConsensusManager.py# Copyright (c) 2015 Davide Gessa # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. import sys import signal import logging import json import requests import time import threading import copy from threading import Thread, Timer, Lock from queue import Queue from random import shuffle from . import Log logger = logging.getLogger('libcontractvm') POLICY_ONLY_NEGATIVE = 0 POLICY_BOTH = 1 POLICY_NONE = 2 BOOTSTRAP_TIMER = 20 class ConsensusManager: def __init__ (self, chain = 'XTN', policy = POLICY_BOTH): self.chain = chain self.nodes = {} self.policy = policy self.bootmer = Timer (BOOTSTRAP_TIMER, self.bootstrapSched) self.bootmer.start () self.nodeslock = Lock () # Return a list def getNodes (self): return self.nodes # Return the used chain def getChain (self): return self.chain # Bootstrap from a node def bootstrap (self, node): self.addNode (node, bootstrap=False) logger.debug ('Bootstrap from ' + node + '...') c = self.jsonCall (node, 'net.peers') if c != None: #print (c) for nn in c: if nn['info'] != None: self.addNode ('http://'+nn['host']+':'+str(nn['info'])) def bootstrapSched (self): self.nodeslock.acquire () nodes = copy.deepcopy (self.nodes) self.nodeslock.release () for node in nodes: self.bootstrap (node) self.bootmer = Timer (BOOTSTRAP_TIMER, self.bootstrapSched) self.bootmer.start () # Add a new node def addNode (self, node, bootstrap=True): self.nodeslock.acquire () #print (self.nodes) if node in self.nodes: # logger.warning ('Duplicated node') self.nodeslock.release () return False c = self.jsonCall (node, 'info') if c == None: #logger.error ('Unreachable node ' + node) self.nodeslock.release () return False if c['chain']['code'] != self.chain: logger.error ('Different chain between node and client ' + node) self.nodeslock.release () return False self.nodes[node] = { 'reputation': 1.0, 'calls': 0 } logger.info ('New node found: ' + node) self.nodeslock.release () self.bootstrap (node) return True def getBestNode (self): #print (self.nodes.items()) dictlist = [] for key, value in self.nodes.items(): temp = [key,value] dictlist.append(temp) shuffle (dictlist) ordered_nodes = sorted (dictlist, key=lambda node: node[1]['reputation']) return ordered_nodes [0][0] # Perform a call with consensus algorithm def jsonConsensusCall (self, command, args = []): res = self.jsonCallFromAll (command, args) #print (res) # Group by result resgroups = {} for x in res: resst = json.dumps (x['result'], sort_keys=True, separators=(',',':')) if resst in resgroups: resgroups[resst]['score'] += self.nodes[x['node']]['reputation'] resgroups[resst]['nodes'].append(x['node']) else: resgroups[resst] = {'result': x['result'], 'score': self.nodes[x['node']]['reputation'], 'nodes': [x['node']]} # Select best score max = None for x in resgroups: if max == None: max = x elif resgroups[max]['score'] < resgroups[x]['score']: max = x for x in resgroups: # Increase reputation for good results (Positive Feedback) if self.policy == POLICY_BOTH and resgroups[x]['score'] >= resgroups[max]['score']: for node in resgroups[x]['nodes']: self.nodes[node]['reputation'] *= 1.2 if self.nodes[node]['reputation'] > 1.0: self.nodes[node]['reputation'] = 1.0 # Decrease reputation for wrong results (Negative Feedback) if self.policy != POLICY_NONE and resgroups[x]['score'] < resgroups[max]['score']: for node in resgroups[x]['nodes']: self.nodes[node]['reputation'] /= 1.2 if self.nodes[node]['reputation'] < 0.1: logger.debug ("Removing node %s because of low reputation", node) del self.nodes[node] logger.debug ("Found consensus majority with score %f of %d nodes", resgroups[max]['score'], len (resgroups[max]['nodes'])) if len (resgroups) == None: return None return resgroups[max] def jsonCallFromAll (self, command, args = []): # Perform the call in parallel q = Queue () threads = [] for node in self.nodes: self.nodes[node]['calls'] += 1 t = Thread(target=self.jsonCall, args=(node, command, args, q)) t.start() threads.append(t) for t in threads: t.join(4.0) res = [] while not q.empty (): res.append (q.get ()) return res # Perform a call with a node def jsonCall (self, node, command, args = [], queue = None): try: payload = { "method": command, "params": args, "jsonrpc": "2.0", "id": 0, } d = requests.post(node, data=json.dumps(payload), headers={'content-type': 'application/json'}).json() #print (command, args, d) if queue != None: queue.put ({'node': node, 'result': d['result']}) else: return d['result'] except: #logger.error ('Failed to contact the node '+node) if queue == None: return None PKc,G(AUUlibcontractvm/Log.py# Copyright (c) 2015 Davide Gessa # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. import logging from colorlog import ColoredFormatter formatter = ColoredFormatter ( '%(log_color)s[%(asctime)s] %(module)s: %(message_log_color)s%(message)s', datefmt=None, reset=True, log_colors={ 'DEBUG': 'blue', 'INFO': 'green', 'WARNING': 'yellow', 'ERROR': 'red', 'CRITICAL': 'red', }, secondary_log_colors={ 'message': { 'DEBUG': 'purple', 'INFO': 'yellow', 'WARNING': 'green', 'ERROR': 'yellow', 'CRITICAL': 'red', } }, style='%' ) stream = logging.StreamHandler() stream.setFormatter(formatter) logger = logging.getLogger('libcontractvm') logger.addHandler(stream) logger.setLevel (10) logger.propagate = False PKH~G<@@libcontractvm/DappManager.py# Copyright (c) 2015 Davide Gessa # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. import requests import binascii import json import sys import logging import time import signal from threading import Thread from threading import Lock from colorlog import ColoredFormatter from libcontractvm import Wallet from libcontractvm import ConsensusManager from . import Log logger = logging.getLogger('libcontractvm') class DappManager: def __init__ (self, consensusmgr, wallet): self.consensusManager = consensusmgr self.wallet = wallet def produceTransaction (self, method, arguments, bmethod = 'broadcast'): logger.info ('Producing transaction: %s %s', method, str (arguments)) while True: #print ('search for best') best = self.consensusManager.getBestNode() #print (best) # Create the transaction res = self.consensusManager.jsonCall (best, method, arguments) #print (res, best) txhash = self.wallet.createTransaction ([res['outscript']], res['fee']) if txhash == None: logger.error ('Failed to create transaction') time.sleep (10) continue # Broadcast the transaction cid = self.consensusManager.jsonCall (best, bmethod, [txhash, res['tempid']]) if cid == None: logger.error ('Broadcast failed') time.sleep (10) continue cid = cid['txid'] if cid != None: logger.info ('Broadcasting transaction: %s', cid) return cid else: logger.error ('Failed to produce transaction, retrying in 10 seconds') time.sleep (10) PKGE>_ _ libcontractvm/WalletExplorer.py# Copyright (c) 2015 Davide Gessa # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. from pycoin.networks import * from pycoin.key import Key from pycoin.key.BIP32Node import BIP32Node from pycoin import encoding from pycoin.ecdsa import is_public_pair_valid, generator_secp256k1, public_pair_for_x, secp256k1 from pycoin.serialize import b2h, h2b from pycoin.tx import * from pycoin.tx.tx_utils import sign_tx, create_tx from pycoin.tx.Spendable import Spendable from pycoin.tx.TxOut import TxOut from pycoin.tx.script import tools from pycoin.encoding import bitcoin_address_to_hash160_sec, is_sec_compressed, public_pair_to_sec, secret_exponent_to_wif, public_pair_to_bitcoin_address, wif_to_tuple_of_secret_exponent_compressed, sec_to_public_pair, public_pair_to_hash160_sec, wif_to_secret_exponent from pycoin.tx.pay_to import address_for_pay_to_script, build_hash160_lookup import logging import json import requests import binascii import random from libcontractvm import Wallet from . import Log logger = logging.getLogger('libcontractvm') class WalletExplorer (Wallet.Wallet): def __init__ (self, chain = 'XTN', address = None, wif = None, wallet_file = None): super (WalletExplorer, self).__init__ (chain, address, wif, wallet_file) def _chaincodeToChainSoName (self, code): if self.chain == 'XTN': code = 'BTCTEST' elif self.chain == 'XDT': code = 'DOGETEST' elif self.chain == 'XLT': code = 'LTCTEST' else: code = self.chain return code def _spendables (self, value): code = self._chaincodeToChainSoName (self.chain) u = 'https://chain.so/api/v2/get_tx_unspent/'+code+'/'+self.address #print (u) d = requests.get (u, headers={'content-type': 'application/json'}).json() sps = [] tot = 0 random.shuffle (d['data']['txs']) for s in d['data']['txs']: #if int (s['confirmations']) > 0: txid = s['txid'] #'' #for x in range (len (s['txid']), -2, -2): # txid += s['txid'][x:x+2] tot += int (float (s['value']) * 100000000) sps.append (Spendable.from_dict ({'coin_value': int (float (s['value']) * 100000000), 'script_hex': s['script_hex'], 'tx_hash_hex': txid, 'tx_out_index': int (s['output_no'])})) if tot >= value: #print (sps) return sps return sps def getBalance (self): code = self._chaincodeToChainSoName (self.chain) u = 'https://chain.so/api/v2/get_address_balance/'+code+'/'+self.address d = requests.get (u, headers={'content-type': 'application/json'}).json() return float (d['data']['confirmed_balance']) + float (d['data']['unconfirmed_balance']) PK1~Gݨ3 3 libcontractvm/WalletNode.py# Copyright (c) 2015 Davide Gessa # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. from pycoin.networks import * from pycoin.key import Key from pycoin.key.BIP32Node import BIP32Node from pycoin import encoding from pycoin.ecdsa import is_public_pair_valid, generator_secp256k1, public_pair_for_x, secp256k1 from pycoin.serialize import b2h, h2b from pycoin.tx import * from pycoin.tx.tx_utils import sign_tx, create_tx from pycoin.tx.Spendable import Spendable from pycoin.tx.TxOut import TxOut from pycoin.tx.script import tools from pycoin.encoding import bitcoin_address_to_hash160_sec, is_sec_compressed, public_pair_to_sec, secret_exponent_to_wif, public_pair_to_bitcoin_address, wif_to_tuple_of_secret_exponent_compressed, sec_to_public_pair, public_pair_to_hash160_sec, wif_to_secret_exponent from pycoin.tx.pay_to import address_for_pay_to_script, build_hash160_lookup import logging import json import requests import binascii import requests import random from . import Log from libcontractvm import Wallet logger = logging.getLogger('libcontractvm') class WalletNode (Wallet.Wallet): def __init__ (self, chain = 'XTN', address = None, wif = None, wallet_file = None, url = None): self.url = url super (WalletNode, self).__init__ (chain, address, wif, wallet_file) def _do_request (self, command, args = []): payload = { "method": command, "params": args, "jsonrpc": "2.0", "id": 0, } return requests.post(self.url, data=json.dumps(payload), headers={'content-type': 'application/json'}).json() def _spendables (self, value): r = self._do_request ('listunspent')['result'] random.shuffle (r) sps = [] tot = 0 for s in r: if s['address'] != self.address: continue txid = '' for x in range (len (s['txid']), -2, -2): txid += s['txid'][x:x+2] tot += int (float (s['amount']) * 100000000) sps.append (Spendable.from_dict ({'coin_value': int (float (s['amount']) * 100000000), 'script_hex': s['scriptPubKey'], 'tx_hash_hex': txid, 'tx_out_index': int (s['vout'])})) if tot >= value: return sps return sps def getBalance (self): r = self._do_request ('getaccount', [self.address])['result'] r = self._do_request ('getbalance', [r])['result'] return float (r) PKG^- /libcontractvm-0.6.9.1.dist-info/DESCRIPTION.rstUNKNOWN PKG;+-libcontractvm-0.6.9.1.dist-info/metadata.json{"extensions": {"python.details": {"contacts": [{"email": "gessadavide@gmail.com", "name": "Davide Gessa", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}}}, "extras": [], "generator": "bdist_wheel (0.26.0)", "metadata_version": "2.0", "name": "libcontractvm", "run_requires": [{"requires": ["base58", "colorlog", "json-rpc", "kad.py", "lxml", "pycoin", "requests", "werkzeug"]}], "summary": "Contractvm client library", "version": "0.6.9.1"}PKG-libcontractvm-0.6.9.1.dist-info/top_level.txtlibcontractvm PKG}\\%libcontractvm-0.6.9.1.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.26.0) Root-Is-Purelib: true Tag: py3-none-any PKGU(libcontractvm-0.6.9.1.dist-info/METADATAMetadata-Version: 2.0 Name: libcontractvm Version: 0.6.9.1 Summary: Contractvm client library Home-page: UNKNOWN Author: Davide Gessa Author-email: gessadavide@gmail.com License: UNKNOWN Platform: UNKNOWN Requires-Dist: base58 Requires-Dist: colorlog Requires-Dist: json-rpc Requires-Dist: kad.py Requires-Dist: lxml Requires-Dist: pycoin Requires-Dist: requests Requires-Dist: werkzeug UNKNOWN PKGW&libcontractvm-0.6.9.1.dist-info/RECORDlibcontractvm/ConsensusManager.py,sha256=w-SH8VLa7PQFxiOiSVNCPh9qjLfTGhfUPrAR9bhR-xU,5014 libcontractvm/DappManager.py,sha256=N4zC0SHV3vJ5lgqqgG3BPabm5rbVcW_csdJKFCvA-zc,1600 libcontractvm/Log.py,sha256=NhJs3EPMsobEUrexTeY9IZBiIQz-jf75cq5o9nqjdB0,853 libcontractvm/Wallet.py,sha256=PlM_-43aGLkteWuyBYwH5XzWRgbIBbH5yZu8HrvQUq4,3672 libcontractvm/WalletChainSo.py,sha256=QFPlxLzhIfKRQbArSxFvkSlkqMqxwqDQFdEfJpH09_k,2623 libcontractvm/WalletExplorer.py,sha256=aSjWbFckBTl3u1lPBflD1JHYH0PxyQjERRkqqRx93YM,2655 libcontractvm/WalletNode.py,sha256=XR5H7aPscje9fd_TFyqecstgzEVpbvyMkZ1tuHlCGkQ,2355 libcontractvm/__init__.py,sha256=u0j-nvb-nJd4FU0Gz6iUanTZv3C-Vy7Cxpa3ocGJCMM,172 libcontractvm-0.6.9.1.dist-info/DESCRIPTION.rst,sha256=OCTuuN6LcWulhHS3d5rfjdsQtW22n7HENFRh6jC6ego,10 libcontractvm-0.6.9.1.dist-info/METADATA,sha256=MoeK1NalwcDgi3vWyd8vV-HEv9ARBDNI0LBhmG3D1qY,398 libcontractvm-0.6.9.1.dist-info/RECORD,, libcontractvm-0.6.9.1.dist-info/WHEEL,sha256=zX7PHtH_7K-lEzyK75et0UBa3Bj8egCBMXe1M4gc6SU,92 libcontractvm-0.6.9.1.dist-info/metadata.json,sha256=a9MzegC_oyEET65lBGdD-O8KjONy3heMZjnF-gjWNgU,467 libcontractvm-0.6.9.1.dist-info/top_level.txt,sha256=tNmPKnxvSphU_LQz8qNLLNbUCACSGsb22RcCS58wg8Q,14 PKc,GYAlibcontractvm/__init__.pyPKxeGQ>XXlibcontractvm/Wallet.pyPKzX{G ? ? plibcontractvm/WalletChainSo.pyPK~G>~!libcontractvm/ConsensusManager.pyPKc,G(AUU-libcontractvm/Log.pyPKH~G<@@G1libcontractvm/DappManager.pyPKGE>_ _ 7libcontractvm/WalletExplorer.pyPK1~Gݨ3 3 ]Blibcontractvm/WalletNode.pyPKG^- /Klibcontractvm-0.6.9.1.dist-info/DESCRIPTION.rstPKG;+- Llibcontractvm-0.6.9.1.dist-info/metadata.jsonPKG->Nlibcontractvm-0.6.9.1.dist-info/top_level.txtPKG}\\%Nlibcontractvm-0.6.9.1.dist-info/WHEELPKGU(6Olibcontractvm-0.6.9.1.dist-info/METADATAPKGW& Qlibcontractvm-0.6.9.1.dist-info/RECORDPKYV