├── __init__.py ├── .gitignore ├── pc ├── __init__.py ├── ConsensusMechanism_test.py ├── CustomMath_test.py ├── CustomMath.py ├── ConsensusMechanism.py └── svd.py ├── pt ├── __init__.py ├── bci.py ├── deterministic.py ├── transaction.py └── main.py ├── log ├── scoreboard.txt ├── scalars_tests.py ├── todo ├── ConsensusMechanism.py ├── kaldor_hicks.txt ├── README.md ├── scalars.py ├── custom.py ├── peer_recieve.py ├── target.py ├── errors ├── database.py ├── threads.py ├── networking.py ├── transactions.py ├── miner.py ├── peers_check.py ├── truth_cli.py ├── tools.py ├── blockchain.py ├── txs_tools.py ├── demo ├── truthcoin_api.py └── txs_truthcoin.py /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod~] 2 | *.db 3 | log.py 4 | -------------------------------------------------------------------------------- /pc/__init__.py: -------------------------------------------------------------------------------- 1 | #from pyconsensus import * 2 | from ConsensusMechanism import Factory 3 | -------------------------------------------------------------------------------- /pt/__init__.py: -------------------------------------------------------------------------------- 1 | from main import * 2 | from transaction import * 3 | from deterministic import * 4 | from bci import * 5 | -------------------------------------------------------------------------------- /log: -------------------------------------------------------------------------------- 1 | INFO:root:custom.current_loc: /home/zack/Hacking/test 2 | INFO:root:starting database 3 | INFO:root:stop: False 4 | INFO:root:starting blockchain 5 | INFO:root:starting truthcoin_api 6 | INFO:root:starting peers_check 7 | INFO:root:starting miner 8 | INFO:root:starting peer_recieve 9 | INFO:root:stop: False 10 | INFO:root:not ready 11 | INFO:root:not ready 12 | INFO:root:not ready 13 | INFO:root:not ready 14 | INFO:root:not ready 15 | INFO:root:not ready 16 | INFO:root:not ready 17 | INFO:root:not ready 18 | INFO:root:not ready 19 | INFO:root:not ready 20 | INFO:root:not ready 21 | INFO:root:not ready 22 | -------------------------------------------------------------------------------- /scoreboard.txt: -------------------------------------------------------------------------------- 1 | The bottleneck in developement for this project is currently the lack of beta testers. The people on this page are more important for truthcoin than anyone else. If you attempt to run truthcoin, and show zack a bug that he can reproduce, then you can be on this page too. These heros are listed in chronological order. 2 | 3 | Xpsztorc installation instructions misspelled 4 | Xpsztorc it is now possible to replace the R code with python 5 | Xkoeppelmann the installation instructions were in the wrong order 6 | Xkoeppelmann wrong port for other server 7 | Xkoeppelmann if txs is non-empty, then we cannot run my_balance at the bash api 8 | Xkoeppelmann no reason for the node to hold the private key 9 | Xkoeppelmann it is possible to make the balance go negative 10 | Xkoeppelmann it is too complex to boot up truthcoin 11 | psztorc buy_shares needs a POW component, or else it is too easy to front-run trades. 12 | -------------------------------------------------------------------------------- /scalars_tests.py: -------------------------------------------------------------------------------- 1 | from scalars import * 2 | def trig_test(): 3 | print(cos(Decimal('0.5'))) 4 | print(sin(Decimal('0.5'))) 5 | import math 6 | print(math.cos(0.5)) 7 | print(math.sin(0.5)) 8 | def cos_test(): 9 | graph(lambda x: cos(pi*2*x)) 10 | #cos_test() 11 | def v2f_test(): 12 | print(graph(v2f([1,1,1,1,1])))#should be dirac delta at 0 13 | def integrate_test(): 14 | def f(x): return x*one 15 | print(integrate(f)) 16 | print(integrate(f, 1000)) 17 | #integrate_test() 18 | def DFT_test(): 19 | def c(x): 20 | if x>one/7 and xone/2-one/20 and x0.5: return 100 34 | return 0 35 | def h(f): 36 | v=DCT(f, 10) 37 | a=v2f(v) 38 | print(v) 39 | print('\n\n') 40 | graph(a, 100) 41 | print('\n\n') 42 | #print(integrate(a)) 43 | n=1000 44 | b=cost_to_buy_shares([0]*len(v), v, n) 45 | print(b) 46 | import math 47 | print(math.e**(float((a(0)-b)/n))) 48 | h(f) 49 | DFT_test() 50 | 51 | -------------------------------------------------------------------------------- /todo: -------------------------------------------------------------------------------- 1 | store peers and blacklist this way: {'134.213.60.92':{'port':8900, 'difficulty':"f0661702aac612293e699c17bccb9d862ce8e180f19a14571c5df29dd7ef896f3dff2e4123", 'connection_lag':100, 'blocklength':17783, 'blacklisted':True}, 2 | } 3 | 4 | minimum amount of money per address (maybe a new tx type for deleting addresses would be useful?) 5 | 6 | truthcoin assurance contract 7 | 8 | launch a test-chain, and try adding tons and tons of IPs to see how it withstands the attack. 9 | 10 | we need trading fees to reward the reputation holders and prediction-market creators. 11 | 12 | conditional markets are supported, but in a limited way. We need to encode an entire matrix to do it correctly, I think. 13 | 14 | ???Allow users to send shares to each other, but charge double trading fees. 15 | 16 | make sure that trading fees are rewarded to authors and voters correctly. Also, reputation should rescale after every SVD. (probably need a un-vote transaction) 17 | 18 | Let users use liquidity-sensitive LMSR if they want. 19 | http://www.eecs.harvard.edu/cs286r/courses/fall12/papers/bmm-ec.pdf 20 | 21 | Let users use Paul's scalar LMSR for prediction markets if they want. in an excel demo on his github. 22 | 23 | Let users use Zack's scalar LMSR for prediction markets if they want. in pc/scalars.py it has cosine transforms. 24 | 25 | update verbage 26 | cashcoin/credit->cash 27 | votecoin->reputation 28 | jury/branch->topic 29 | decision->prediction 30 | 31 | any vote must block the coins from being sent until svd is over 32 | 33 | proof of stake 34 | 35 | mini blockchain 36 | -------------------------------------------------------------------------------- /ConsensusMechanism.py: -------------------------------------------------------------------------------- 1 | """a python version of the R program at https://github.com/psztorc/Truthcoin 2 | """ 3 | #import python_ConsensusMechanism as consensus 4 | import tools, pc 5 | #import python_CustomMath as custommath 6 | 7 | def keep_nums(t): 8 | if type(t)==list: 9 | out=[] 10 | for i in t: 11 | out.append(keep_nums(i)) 12 | return out 13 | if type(t)==int: 14 | return False 15 | else: 16 | return True 17 | def GetWeight(Vec, AddMean=0): 18 | """Takes an array (vector in practice), and returns proportional 19 | distance from zero.""" 20 | New = abs(Vec) #Absolute Value 21 | if AddMean == 1: #Add the mean to each element of the vector 22 | New = New + mean(New) 23 | if sum(New) == 0: #Catch an error here 24 | New = New + 1 25 | New = New/sum(New) #Normalize 26 | return(New) 27 | 28 | def main(m, weights): 29 | a=pc.Factory(m, weights) 30 | return {'outcome':a['Decisions']['DecisionOutcome_Final'], 31 | 'author_bonus':a['Decisions']['Author Bonus'], 32 | 'participation':a['Participation'], 33 | 'certainty':a['Decisions']['Certainty'], 34 | 'votecoin_bonus_for_voters':a['Agents']['SmoothRep'], 35 | 'truthcoin_bonus_for_voters':a['Agents']['RowBonus']} 36 | if __name__ == "__main__": 37 | m=[[1, 1, 1, 1, 1], ['NA', 'NA', 'NA', 'NA', 'NA'], ['NA', 'NA', 'NA', 'NA', 'NA']] 38 | m=[[1, 1, 1, 1, 0], [0, 0, 0, 0, 1], [0, 0, 0, 0, 0]] 39 | m=[[1, 1, 0, 'NA'], 40 | [1, 0, 0, 0], 41 | [1, 1, 0, 0], 42 | [1, 1, 1, 0], 43 | [0, 0, 1, 1], 44 | [0, 0, 1, 1]] 45 | #w=[[1294], [1], [1294]] 46 | w=[[1],[1],[1],[1],[1],[1]] 47 | #w=[[1],[2],[3],[4]] 48 | #m=[[0,0,0],[0,1,0],[0,0,1]] 49 | #print(dem_main(m)) 50 | print(main(m, w)) 51 | 52 | -------------------------------------------------------------------------------- /kaldor_hicks.txt: -------------------------------------------------------------------------------- 1 | Given an initial allocation of goods among a set of individuals, a change to a different allocation that makes at least one individual better off without making any other individual worse off is called a Pareto improvement. An allocation is defined as "Pareto efficient" or "Pareto optimal" when no further Pareto improvements can be made. 2 | 3 | Under "Kaldor–Hicks efficiency", an outcome is more efficient if those that are made better off could in theory compensate those that are made worse off and lead to a Pareto optimal outcome. The compensation does not actually have to occur (there's no presumption in favor of status-quo) and thus, a more efficient outcome can in fact leave some people worse off. 4 | 5 | A "Kaldor-Hicks improvement" increases Kaldor-Hicks efficiency. 6 | 7 | 8 | 9 | Is POW mining a block a Kaldor-Hicks improvement? 10 | Sometimes. It depends on how big the mining reward is. If the mining reward is less than or equal to the security needs of users, then it is Kaldor-Hicks efficient because the people who benefit from security have benefits which exceed the cost to pay the miners. 11 | If the mining reward is greater than security needs of users, then it is not Kaldor-Hicks efficient. The benefits to security are not enough to afford to pay the miners. 12 | There is no known way to make mining reward size dependent upon security needs. So, there is no known way to make a POW blockchain be Kaldor-Hicks. In practice, the mining reward is a constant choosen at the genesis block. 13 | 14 | 15 | 16 | Is Slasher POS buying a block a Kaldor-Hicks improvement? 17 | Always. Coins are only destroyed, never created. The act of creating the next block destroys some coins. Only one person's coins are destroyed, and many other people gain because they can spend transactions in the block. 18 | The block-buyer voluntarily agrees to sign the block. In practice, people send transaction fees to the block-buyer, so the block-buyer makes a profit. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This blockchain is no longer maintained. It was a rough draft for Flying Fox. https://github.com/BumblebeeBat/FlyingFox 2 | 3 | Truthcoin-POW 4 | ============= 5 | 6 | If you are not a programmer, then you are lost, and should click this link: http://www.augur.net/prototype/ 7 | 8 | adding abilities from the truthcoin project to basiccoin. https://github.com/psztorc/Truthcoin 9 | 10 | Donations: 1GbpRPE83Vjg73KFvTVZ4EnS2qNkiLY5TT 11 | 12 | =====INSTALL 13 | for Mac 14 | 15 | sudo pip install m3-cdecimal 16 | git clone https://github.com/zack-bitcoin/Truthcoin-POW.git 17 | cd Truthcoin-POW 18 | 19 | for Ubuntu 20 | 21 | sudo apt-get update 22 | sudo apt-get install libpython-dev 23 | sudo pip2 install m3-cdecimal 24 | sudo pip install six 25 | git clone https://github.com/zack-bitcoin/Truthcoin-POW.git 26 | cd Truthcoin-POW 27 | 28 | ====RUN A NODE 29 | 30 | python2.7 truth_cli.py start 31 | 32 | It will take time to download the blockchain. 33 | 34 | ====TALK TO THE NODE 35 | 36 | python2.7 truth_cli.py 37 | 38 | ====About this software 39 | 40 | For now, there is a week-long cycle. 41 | for the first 7/8ths of the cycle: votecoin-holders may give encrypted votes on decisions. (in the final version of truthcoin, this step will take 1000+ blocks) 42 | for the next 1/10th of the cycle: votecoin-holders may decrypt their votes 43 | for the final 1/40th of the cycle: if there are at least 3 votecoin-holders, and at least 5 decisions they have voted on, then we can do SVD to come to consensus about these decisions. 44 | 45 | Security assumption for truthcoin-pow is a lot weaker than bitcoin. It is only 46 | secure if there is always at least one person mining for blocks. 47 | If more than 2 hours pass where no-one is mining, then it becomes far easier to attack. 48 | 49 | This blockchain currently has a bad retargetting algorithm. Because of this, it is not 50 | suitable for holding real value. It is still good for testing and developing a truthcoin 51 | system. 52 | Long term goal is to use proof-of-stake anyway. 53 | -------------------------------------------------------------------------------- /pc/ConsensusMechanism_test.py: -------------------------------------------------------------------------------- 1 | from ConsensusMechanism import * 2 | def test_GetRewardWeights(): 3 | M = [[1, 1, 0, 0], 4 | [1, 0, 0, 0], 5 | [1, 1, 0, 0], 6 | [1, 1, 1, 0], 7 | [0, 0, 1, 1], 8 | [0, 0, 1, 1]] 9 | ''' 10 | {u'ThisRep': array([[ 0.2823757, 0.2176243, 0.2823757, 0.2176243, 0. , 0. ]]), u'FirstL': array([-0.5395366 , -0.45705607, 0.45705607, 0.5395366 ]), u'SmoothRep': array([[ 0.17823757, 0.17176243, 0.17823757, 0.17176243, 0.15 , 11 | 0.15 ]]), u'OldRep': array([[ 0.16666667, 0.16666667, 0.16666667, 0.16666667, 0.16666667, 12 | 0.16666667]])} 13 | ''' 14 | import pprint 15 | pprint.pprint(GetRewardWeights(M)) 16 | def test_getdecisionoutcomes(): 17 | M=[[1, 1, 0, 0], 18 | [1, 0, 0, 0], 19 | [1, 1, 0, 0], 20 | [1, 1, 1, 0], 21 | [0, 0, 1, 1], 22 | [0, 0, 1, 1]] 23 | print(GetDecisionOutcomes(M, [1]*6)) 24 | #[[Decimal('0.6666666666666666666666666668'), Decimal('0.5000000000000000000000000001'), Decimal('0.5000000000000000000000000001'), Decimal('0.3333333333333333333333333334')]] 25 | def FillNa_test(): 26 | M=[[1, 1, 0, 0], 27 | [1, 0, 'NA', 'NA'], 28 | [1, 'NA', 0, 'NA'], 29 | [1, 1, 1, 'NA'], 30 | [0, 'NA', 1, 'NA'], 31 | [0, 0, 1, 1]] 32 | print(FillNa(M, [1,1,1,1,1,1])) 33 | #[[Decimal('1'), Decimal('1'), Decimal('0'), Decimal('0')], [Decimal('1'), Decimal('0'), Decimal('1'), Decimal('0.5')], [Decimal('1'), Decimal('0.5'), Decimal('0'), Decimal('0.5')], [Decimal('1'), Decimal('1'), Decimal('1'), Decimal('0.5')], [Decimal('0'), Decimal('0.5'), Decimal('1'), Decimal('0.5')], [Decimal('0'), Decimal('0'), Decimal('1'), Decimal('1')]] 34 | def Factory_test(): 35 | import pprint 36 | M1=[[1, 1, 0, 'NA'], 37 | [1, 0, 0, 0], 38 | [1, 1, 0, 0], 39 | [1, 1, 1, 0], 40 | [0, 0, 1, 1], 41 | [0, 0, 1, 1]] 42 | pprint.pprint(Factory(M1, [1,1,1,1,1,1])) 43 | #Factory_test() 44 | -------------------------------------------------------------------------------- /scalars.py: -------------------------------------------------------------------------------- 1 | # v is used for fourier series. f(x) is used for functions between 0 and 1. 2 | #http://en.wikipedia.org/wiki/Discrete_cosine_transform 3 | from cdecimal import Decimal 4 | zero=Decimal('0') 5 | one=Decimal('1') 6 | pi=Decimal('3.141592653589793') 7 | E=Decimal('2.718281828459045') 8 | def graph(f, m=100): 9 | for i in range(m): 10 | print(f(Decimal(i)/m)) 11 | def dec_greater_than(a, b): return float(a)>float(b) 12 | def factorial(n): 13 | if not dec_greater_than(n, 1): return one 14 | return n*factorial(n-1) 15 | def alternate_sum(v, positive=1, s=0): 16 | if len(v)==0: return s 17 | return alternate_sum(v[1:], -positive, s+v[0]*positive) 18 | Taylor_series_depth=13 19 | def trig(x, t): 20 | if not dec_greater_than(x, Decimal('0.0000001')) and dec_greater_than(x, Decimal('-0.0000001')): return 1-t 21 | if not dec_greater_than(x, -pi): return trig(x+2*pi, t) 22 | if dec_greater_than(x, 10*pi): return trig(x-11*pi, t) 23 | if dec_greater_than(x, pi): return trig(x-2*pi, t) 24 | a=filter(lambda y: y%2==t, range(Taylor_series_depth)) 25 | a=map(lambda y: (x**y)/factorial(y), a) 26 | return alternate_sum(a) 27 | def cos(x): return trig(x, 0) 28 | def sin(x): return trig(x, 1) 29 | def mul(a, b): return a*b 30 | def add(a, b): return a+b 31 | def plug_in(x, v):#use the cosine series to draw a graph, and see what the value of x is on that graph. 32 | #wikipedia: DCT III 33 | c=map(lambda y: 2*cos((y+(one/2))*pi*x), range(len(v))) 34 | #c[0]=c[0]/2 35 | return sum(map(mul, v, c)) 36 | def v2f(v): return lambda x: plug_in(x, v) 37 | def integrate(f, m=5): return sum(map(lambda x: f(Decimal(x)/m), range(m)))/m#this m determines initial liquidity=B*ln(m) 38 | def C(v, B): return B*integrate(lambda x: E**(v2f(v)(x)/B)).ln() 39 | def cost_to_buy_shares(current_state, shares, B): 40 | f=lambda x: C(x, B) 41 | return f(map(add, current_state, shares))-f(current_state) 42 | def DCT(f, s=5): 43 | #wikipedia: DCT II 44 | def g(f, n): return (lambda x: f(x)*cos(pi*(n+(one/2))*x)) 45 | return map(lambda n: integrate(g(f, n), s), range(s)) 46 | 47 | #print(cost_to_buy_shares([Decimal('10'),Decimal('50'),0,0,0], [Decimal('10'),0,0,0,0], 1000)) 48 | #print(cost_to_buy_shares([Decimal('10'),Decimal('50'),0,0,0], [Decimal('5'),0,0,0,0], 1000)) 49 | #print(cost_to_buy_shares([Decimal('10'),Decimal('50'),0,0,0], [Decimal('5'),Decimal('5'),0,0,0], 1000)) 50 | -------------------------------------------------------------------------------- /custom.py: -------------------------------------------------------------------------------- 1 | """This is to make magic numbers easier to deal with.""" 2 | import multiprocessing, os 3 | import cdecimal 4 | peers = { 5 | '192.241.212.114:8900': { 6 | 'port': 8900, 7 | 'blacklist': 0, 8 | 'lag': 40.0, 9 | 'diffLength': '0', 10 | 'length': 0, 11 | }, 12 | '69.164.196.239:8900': { 13 | 'port': 8900, 14 | 'blacklist': 0, 15 | 'lag': 0.15, 16 | 'diffLength': '0', 17 | 'length': 0, 18 | }, 19 | } 20 | 21 | #peers={'192.241.212.114:8900':{'port':8900, 'blacklist':0, 'lag':40.0, 'diffLength':"0", 'length':0}, 22 | # '127.0.0.1:8900':{'port': 8900, 'blacklist':0, 'lag':40.0, 'diffLength':"0", 'length':0}} 23 | #'69.164.196.239:8900':{'port': 8900, 'blacklist':0, 'lag':0.15, 'diffLength':"0", 'length':0}} 24 | current_loc=os.path.dirname(os.path.abspath(__file__)) 25 | database_name = os.path.join(current_loc, 'DB') 26 | log_file=os.path.join(current_loc, 'log') 27 | port=8900 28 | api_port=8899 29 | database_port=8898 30 | version = "0.0012" 31 | max_key_length=6**4 32 | total_votecoins=6**4 33 | block_reward = 10 ** 5 34 | premine = 5 * 10 ** 6 35 | fee = 10 ** 3 36 | propose_decision_fee = 10 ** 5 37 | create_jury_fee=10**4 38 | jury_vote_fee=500 39 | reveal_jury_vote_fee=500 40 | SVD_consensus_fee=0 41 | buy_shares_fee=10**5 42 | collect_winnings_reward=5*10**4 43 | # Lower limits on what the "time" tag in a block can say. 44 | mmm = 100 45 | # Take the median of this many of the blocks. 46 | # How far back in history do we look when we use statistics to guess at 47 | # the current blocktime and difficulty. 48 | history_length = 400 49 | # This constant is selected such that the 50 most recent blocks count for 1/2 the 50 | # total weight. 51 | inflection = cdecimal.Decimal('0.985') 52 | download_many = 50 # Max number of blocks to request from a peer at the same time. 53 | max_download = 58000 54 | #buy_shares_target='0'*4+'1'+'9'*59 55 | buy_shares_target='0'*3+'1'+'9'*60 56 | blocktime=60 57 | DB = { 58 | 'reward_peers_queue':multiprocessing.Queue(), 59 | 'suggested_blocks': multiprocessing.Queue(), 60 | 'suggested_txs': multiprocessing.Queue(), 61 | 'heart_queue': multiprocessing.Queue(), 62 | } 63 | #seconds_per_week=604800 64 | #cycle_length=seconds_per_week/blocktime#cycle_length 65 | cycle_length=40 66 | vote_reveal_length=cycle_length/10 67 | SVD_length=cycle_length/40 68 | voting_length=cycle_length-vote_reveal_length-SVD_length 69 | -------------------------------------------------------------------------------- /peer_recieve.py: -------------------------------------------------------------------------------- 1 | """When a peer talks to us, this is how we generate a response. This is the external API. 2 | """ 3 | import networking, custom, tools, blockchain, time 4 | def security_check(dic): 5 | if 'version' not in dic or dic['version'] != custom.version: 6 | return {'bool': False, 'error': 'version'} 7 | else: 8 | #we could add security features here. 9 | return {'bool': True, 'newdic': dic} 10 | def recieve_peer(dic, DB): 11 | if 'peers' in dic: 12 | map(tools.add_peer, dic['peers']) 13 | else: 14 | tools.add_peer(dic['peer']) 15 | def blockCount(dic, DB): 16 | length = tools.db_get('length') 17 | d='0' 18 | if length >= 0: d=tools.db_get('diffLength') 19 | return {'length': length, 'diffLength': d} 20 | def rangeRequest(dic, DB): 21 | ran = dic['range'] 22 | out = [] 23 | counter = 0 24 | while (len(tools.package(out)) < custom.max_download 25 | and ran[0] + counter <= ran[1]): 26 | block = tools.db_get(ran[0] + counter, DB) 27 | if 'length' in block: 28 | out.append(block) 29 | counter += 1 30 | return out 31 | def txs(dic, DB): 32 | return tools.db_get('txs') 33 | def pushtx(dic, DB): 34 | DB['suggested_txs'].put(dic['tx']) 35 | return 'success' 36 | def pushblock(dic, DB): 37 | length=tools.db_get('length') 38 | block = tools.db_get(length, DB) 39 | if 'peer' in dic: peer=dic['peer'] 40 | else: peer=False 41 | if 'blocks' in dic: 42 | if peer!=False: 43 | a=tools.package(peer) not in blacklist 44 | if a not in blacklist or blacklist[a]<500: 45 | for i in range(20): 46 | if tools.fork_check(dic['blocks'], DB, length, block): 47 | blockchain.delete_block(DB) 48 | length-=1 49 | for block in dic['blocks']: 50 | DB['suggested_blocks'].put([block, peer]) 51 | else: 52 | DB['suggested_blocks'].put([dic['block'], peer]) 53 | return 'success' 54 | def peers(dic, DB): return tools.db_get('peers') 55 | def main(dic, DB): 56 | #tools.log(dic) 57 | funcs = {'recieve_peer':recieve_peer, 'blockCount': blockCount, 'rangeRequest': rangeRequest,'txs': txs, 'pushtx': pushtx, 'pushblock': pushblock, 'peers':peers} 58 | if 'type' not in dic: 59 | return 'oops: ' +str(dic) 60 | if dic['type'] not in funcs: 61 | return ' '.join([dic['type'], 'is not in the api']) 62 | check = security_check(dic) 63 | if not check['bool']: 64 | return check 65 | try: 66 | return funcs[dic['type']](check['newdic'], DB) 67 | except Exception as exc: 68 | tools.log(exc) 69 | 70 | -------------------------------------------------------------------------------- /target.py: -------------------------------------------------------------------------------- 1 | import blockchain, custom, tools 2 | try: 3 | import cdecimal 4 | except: 5 | import decimal as cdecimal 6 | tools.log('This would run much faster if you installed cdecimal.') 7 | memoized_weights=[custom.inflection**i for i in range(1000)] 8 | def target(length=0): 9 | """ Returns the target difficulty at a paticular blocklength. """ 10 | db_length=tools.db_get('length') 11 | if length == 0: length = db_length 12 | if length < 4: return '0' * 4 + 'f' * 60 # Use same difficulty for first few blocks. 13 | trgs=tools.db_get('targets') 14 | if length <= db_length and str(length) in trgs: 15 | return trgs[str(length)] 16 | def targetTimesFloat(target, number): 17 | a = int(str(target), 16) 18 | b = int(a * number)#this should be rational multiplication followed by integer estimation 19 | return tools.buffer_(str(hex(b))[2: -1], 64) 20 | def multiply_things(things): 21 | out=1 22 | while len(things)>0: 23 | out=out*things[0] 24 | things=things[1:] 25 | return out 26 | def weights(length):#uses float 27 | #returns from small to big 28 | out=memoized_weights[:length] 29 | out.reverse() 30 | return out 31 | def estimate_target(): 32 | """ 33 | We are actually interested in the average number of hashes required to 34 | mine a block. number of hashes required is inversely proportional 35 | to target. So we average over inverse-targets, and inverse the final 36 | answer. """ 37 | def sumTargets(l): 38 | if len(l) < 1: 39 | return 0 40 | while len(l) > 1: 41 | l = [blockchain.hexSum(l[0], l[1])] + l[2:] 42 | return l[0] 43 | targets = blockchain.recent_blockthings('targets', custom.history_length) 44 | w = weights(len(targets))#should be rat instead of float 45 | tw = sum(w) 46 | targets = map(blockchain.hexInvert, targets) 47 | def weighted_multiply(i): 48 | return targetTimesFloat(targets[i], w[i]/tw)#this should use rat division instead 49 | weighted_targets = [weighted_multiply(i) for i in range(len(targets))] 50 | return blockchain.hexInvert(sumTargets(weighted_targets)) 51 | def estimate_time(): 52 | times = blockchain.recent_blockthings('times', custom.history_length)#should be deterministally turned into rats 53 | times=map(cdecimal.Decimal, times) 54 | blocklengths = [times[i] - times[i - 1] for i in range(1, len(times))] 55 | w = weights(len(blocklengths)) # Geometric weighting 56 | tw = sum(w) 57 | return sum([w[i] * blocklengths[i] / tw for i in range(len(blocklengths))]) 58 | retarget = estimate_time() / custom.blocktime 59 | return targetTimesFloat(estimate_target(), retarget) 60 | 61 | 62 | -------------------------------------------------------------------------------- /errors: -------------------------------------------------------------------------------- 1 | INFO:root:starting peer_recieve 2 | INFO:root:stop: False 3 | ERROR:root:'int' object has no attribute 'items' 4 | Traceback (most recent call last): 5 | File "/home/zack/Hacking/test/peers_check.py", line 91, in main 6 | main_once(DB) 7 | File "/home/zack/Hacking/test/peers_check.py", line 111, in main_once 8 | r=peer_check(i, pr, DB) 9 | File "/home/zack/Hacking/test/peers_check.py", line 62, in peer_check 10 | download_blocks(peer, DB, block_count, length) 11 | File "/home/zack/Hacking/test/peers_check.py", line 15, in download_blocks 12 | blockchain.delete_block(DB) 13 | File "/home/zack/Hacking/test/blockchain.py", line 205, in delete_block 14 | transactions.update[tx['type']](tx, DB, False) 15 | File "/home/zack/Hacking/test/transactions.py", line 95, in spend 16 | txs_tools.memory_leak_votecoin(tx['vote_id'], tx['to'], DB, add_block)#this should get rid of any zeros in the jury so we don't leak memory. 17 | File "/home/zack/Hacking/test/txs_tools.py", line 232, in memory_leak_votecoin 18 | bool_=memory_leak_helper(['votecoin', vote_id], address, DB, add_block) 19 | File "/home/zack/Hacking/test/txs_tools.py", line 229, in memory_leak_helper 20 | adjust_dict(loc, address, True, {loc[-1]: 0}, DB, add_block) 21 | File "/home/zack/Hacking/test/txs_tools.py", line 200, in adjust_dict 22 | adjust(pubkey, DB, f) 23 | File "/home/zack/Hacking/test/txs_tools.py", line 178, in adjust 24 | f(acc) 25 | File "/home/zack/Hacking/test/txs_tools.py", line 196, in f 26 | current=dict(dic.items() + current.items()) 27 | AttributeError: 'int' object has no attribute 'items' 28 | zack@iloSona:~/Hacking/test$ ./truth_cli.py blockcount 29 | 1432 30 | zack@iloSona:~/Hacking/test$ ./truth_cli.py stop 31 | 32 | 33 | 34 | 35 | Traceback (most recent call last): 36 | File "/root/Truthcoin-POW/blockchain.py", line 225, in ff 37 | g(queue.get(False)) 38 | File "/root/Truthcoin-POW/blockchain.py", line 176, in add_block 39 | transactions.update[tx['type']](tx, DB, True) 40 | File "/root/Truthcoin-POW/transactions.py", line 95, in spend 41 | txs_tools.memory_leak_votecoin(tx['vote_id'], tx['to'], DB, add_block)#this should get rid of any zeros in the jury so we don't leak memory. 42 | File "/root/Truthcoin-POW/txs_tools.py", line 232, in memory_leak_votecoin 43 | bool_=memory_leak_helper(['votecoin', vote_id], address, DB, add_block) 44 | File "/root/Truthcoin-POW/txs_tools.py", line 229, in memory_leak_helper 45 | adjust_dict(loc, address, True, {loc[-1]: 0}, DB, add_block) 46 | File "/root/Truthcoin-POW/txs_tools.py", line 200, in adjust_dict 47 | adjust(pubkey, DB, f) 48 | File "/root/Truthcoin-POW/txs_tools.py", line 178, in adjust 49 | f(acc) 50 | File "/root/Truthcoin-POW/txs_tools.py", line 198, in f 51 | current.pop(dic.keys()[0]) 52 | AttributeError: 'int' object has no attribute 'pop' 53 | root@NEWS1:~/Truthcoin-POW# -------------------------------------------------------------------------------- /database.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Process 2 | import os 3 | import json 4 | 5 | def _default_entry(): 6 | return dict(count=0, amount=0, votecoin={}, votes={}, shares={}) 7 | 8 | def _noop(): 9 | return None 10 | 11 | class DatabaseProcess(Process): 12 | ''' 13 | Manages operations on the database. 14 | ''' 15 | def __init__(self, heart_queue, database_name, logf, port): 16 | super(DatabaseProcess, self).__init__(name='database') 17 | self.heart_queue = heart_queue 18 | self.database_name = database_name 19 | self.logf = logf 20 | self.port = port 21 | 22 | def get(self, args): 23 | '''Gets the key in args[0] using the salt''' 24 | try: 25 | return json.loads(self._get(self.salt + str(args[0]))) 26 | except KeyError: 27 | return _default_entry() 28 | 29 | def put(self, args): 30 | ''' 31 | Puts the val in args[1] under the key in args[0] with the salt 32 | prepended to the key. 33 | ''' 34 | self._put(self.salt + str(args[0]), json.dumps(args[1])) 35 | 36 | def existence(self, args): 37 | ''' 38 | Checks if the key in args[0] with the salt prepended is 39 | in the database. 40 | ''' 41 | try: 42 | self._get(self.salt + str(args[0])) 43 | except KeyError: 44 | return False 45 | else: 46 | return True 47 | 48 | def delete(self, args): 49 | ''' 50 | Removes the entry in the database under the the key in args[0] 51 | with the salt prepended. 52 | ''' 53 | # It isn't an error to try to delete something that isn't there. 54 | try: 55 | self._del(self.salt + str(args[0])) 56 | except: 57 | pass 58 | 59 | def run(self): 60 | import networking 61 | import sys 62 | if sys.platform == 'win32': 63 | import bsddb 64 | self.DB = bsddb.hashopen(self.database_name) 65 | self._get = self.DB.__getitem__ 66 | self._put = self.DB.__setitem__ 67 | self._del = self.DB.__delitem__ 68 | self._close = self.DB.close 69 | else: 70 | import leveldb 71 | self.DB = leveldb.LevelDB(self.database_name) 72 | self._get = self.DB.Get 73 | self._put = self.DB.Put 74 | self._del = self.DB.Delete 75 | self._close = _noop # leveldb doesn't have a close func 76 | try: 77 | self.salt = self._get('salt') 78 | except KeyError: 79 | self.salt = os.urandom(5) 80 | self._put('salt', self.salt) 81 | def command_handler(command): 82 | try: 83 | name = command['type'] 84 | assert (name not in ['__init__', 'run']) 85 | return getattr(self, name)(command['args']) 86 | except Exception as exc: 87 | self.logf(exc) 88 | self.logf('command: ' + str(command)) 89 | self.logf('command type: ' + str(type(command))) 90 | return {'error':'bad data'} 91 | networking.serve_forever(command_handler, self.port, self.heart_queue) 92 | self._close() -------------------------------------------------------------------------------- /pt/bci.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import urllib2, json, re, random, sys 3 | 4 | # Makes a request to a given URL (first argument) and optional params (second argument) 5 | def make_request(*args): 6 | opener = urllib2.build_opener() 7 | opener.addheaders = [('User-agent', 'Mozilla/5.0'+str(random.randrange(1000000)))] 8 | try: 9 | return opener.open(*args).read().strip() 10 | except Exception,e: 11 | try: p = e.read().strip() 12 | except: p = e 13 | raise Exception(p) 14 | 15 | # Gets the transaction output history of a given set of addresses, 16 | # including whether or not they have been spent 17 | def history(*args): 18 | # Valid input formats: history([addr1, addr2,addr3]) 19 | # history(addr1, addr2, addr3) 20 | if len(args) == 0: return [] 21 | elif isinstance(args[0],list): addrs = args[0] 22 | else: addrs = args 23 | 24 | txs = [] 25 | for addr in addrs: 26 | offset = 0 27 | while 1: 28 | data = make_request('http://blockchain.info/address/%s?format=json&offset=%s' % (addr,offset)) 29 | try: 30 | jsonobj = json.loads(data) 31 | except: 32 | raise Exception("Failed to decode data: "+data) 33 | txs.extend(jsonobj["txs"]) 34 | if len(jsonobj["txs"]) < 50: break 35 | offset += 50 36 | sys.stderr.write("Fetching more transactions... "+str(offset)+'\n') 37 | outs = {} 38 | for tx in txs: 39 | for o in tx["out"]: 40 | if o['addr'] in addrs: 41 | key = str(tx["tx_index"])+':'+str(o["n"]) 42 | outs[key] = { 43 | "address" : o["addr"], 44 | "value" : o["value"], 45 | "output" : tx["hash"]+':'+str(o["n"]), 46 | "block_height" : tx.get("block_height",None) 47 | } 48 | for tx in txs: 49 | for i, inp in enumerate(tx["inputs"]): 50 | if inp["prev_out"]["addr"] in addrs: 51 | key = str(inp["prev_out"]["tx_index"])+':'+str(inp["prev_out"]["n"]) 52 | if outs.get(key): outs[key]["spend"] = tx["hash"]+':'+str(i) 53 | return [outs[k] for k in outs] 54 | 55 | # Pushes a transaction to the network using http://blockchain.info/pushtx 56 | def pushtx(tx): 57 | if not re.match('^[0-9a-fA-F]*$',tx): tx = tx.encode('hex') 58 | return make_request('http://blockchain.info/pushtx','tx='+tx) 59 | 60 | def eligius_pushtx(tx): 61 | if not re.match('^[0-9a-fA-F]*$',tx): tx = tx.encode('hex') 62 | s = make_request('http://eligius.st/~wizkid057/newstats/pushtxn.php','transaction='+tx+'&send=Push') 63 | strings = re.findall('string[^"]*"[^"]*"',s) 64 | for string in strings: 65 | quote = re.findall('"[^"]*"',string)[0] 66 | if len(quote) >= 5: return quote[1:-1] 67 | 68 | def last_block_height(): 69 | data = make_request('http://blockchain.info/latestblock') 70 | jsonobj = json.loads(data) 71 | return jsonobj["height"] 72 | 73 | # Gets a specific transaction 74 | def fetchtx(txhash): 75 | if not re.match('^[0-9a-fA-F]*$',txhash): txhash = txhash.encode('hex') 76 | data = make_request('http://blockchain.info/rawtx/'+txhash+'?format=hex') 77 | return data 78 | 79 | def firstbits(address): 80 | if len(address) >= 25: 81 | return make_request('https://blockchain.info/q/getfirstbits/'+address) 82 | else: 83 | return make_request('https://blockchain.info/q/resolvefirstbits/'+address) 84 | -------------------------------------------------------------------------------- /threads.py: -------------------------------------------------------------------------------- 1 | """This program starts all the threads going. When it hears a kill signal, it kills all the threads. 2 | """ 3 | import miner, peer_recieve, time, threading, tools, custom, networking, sys, truthcoin_api, blockchain, peers_check, multiprocessing, database, threads 4 | #windows was complaining about lambda 5 | def peer_recieve_func(d, DB=custom.DB): 6 | return peer_recieve.main(d, DB) 7 | 8 | def main(brainwallet, pubkey_flag=False): 9 | DB=custom.DB 10 | tools.log('custom.current_loc: ' +str(custom.current_loc)) 11 | print('starting truthcoin') 12 | if not pubkey_flag: 13 | privkey=tools.det_hash(brainwallet) 14 | pubkey=tools.privtopub(privkey) 15 | else: 16 | pubkey=brainwallet 17 | a=tools.empty_peer() 18 | a['port']=custom.port 19 | b=custom.peers 20 | my_ip=tools.getPublicIp() 21 | b[my_ip+':'+str(custom.port)]=a 22 | processes= [ 23 | {'target': blockchain.main, 24 | 'args': (DB,), 25 | 'name': 'blockchain'}, 26 | {'target': truthcoin_api.main, 27 | 'args': (DB, DB['heart_queue']), 28 | 'name': 'truthcoin_api'}, 29 | {'target': peers_check.main, 30 | 'args': (b, DB), 31 | 'name': 'peers_check'}, 32 | {'target': miner.main, 33 | 'args': (pubkey, DB), 34 | 'name': 'miner'}, 35 | {'target': networking.serve_forever, 36 | 'args': (peer_recieve_func, custom.port, DB['heart_queue'], True), 37 | 'name': 'peer_recieve'} 38 | ] 39 | cmds=[database.DatabaseProcess( 40 | DB['heart_queue'], 41 | custom.database_name, 42 | tools.log, 43 | custom.database_port)] 44 | try: 45 | cmds[0].start() 46 | except Exception as exc: 47 | tools.log(exc) 48 | tools.log('starting ' + cmds[0].name) 49 | time.sleep(4) 50 | tools.db_put('test', 'TEST') 51 | tools.db_get('test') 52 | tools.db_put('test', 'undefined') 53 | b=tools.db_existence(0) 54 | if not b: 55 | tools.db_put('ip', my_ip) 56 | tools.db_put('length', -1) 57 | tools.db_put('memoized_votes', {}) 58 | tools.db_put('txs', []) 59 | tools.db_put('peers', {}) 60 | tools.db_put('targets', {}) 61 | tools.db_put('times', {}) 62 | tools.db_put('mine', False) 63 | tools.db_put('diffLength', '0') 64 | tools.db_put('stop', False) 65 | tools.log('stop: ' +str(tools.db_get('stop'))) 66 | for process in processes: 67 | cmd=multiprocessing.Process(**process) 68 | cmd.start() 69 | cmds.append(cmd) 70 | tools.log('starting '+cmd.name) 71 | if not pubkey_flag: 72 | tools.db_put('privkey', privkey) 73 | else: 74 | tools.db_put('privkey', 'Default') 75 | tools.db_put('address', tools.make_address([pubkey], 1)) 76 | tools.log('stop: ' +str(tools.db_get('stop'))) 77 | while not tools.db_get('stop'): 78 | time.sleep(0.5) 79 | tools.log('about to stop threads') 80 | DB['heart_queue'].put('stop') 81 | for p in [[custom.port, '127.0.0.1'], 82 | [custom.api_port, '127.0.0.1']]: 83 | networking.connect('stop', p[0], p[1]) 84 | cmds.reverse() 85 | for cmd in cmds[:-1]: 86 | cmd.join() 87 | tools.log('stopped a thread: '+str(cmd)) 88 | time.sleep(2) 89 | networking.connect('stop', custom.database_port, '127.0.0.1') 90 | cmds[-1].join() 91 | tools.log('stopped a thread: '+str(cmds[-1])) 92 | tools.log('all threads stopped') 93 | sys.exit(0) 94 | if __name__=='__main__': #for windows 95 | try: 96 | main(sys.argv[1]) 97 | except Exception as exc: 98 | tools.log(exc) 99 | -------------------------------------------------------------------------------- /networking.py: -------------------------------------------------------------------------------- 1 | import socket, tools, custom, time, sys, select 2 | from json import dumps as package, loads as unpackage 3 | MAX_MESSAGE_SIZE = 60000 4 | def serve_forever(handler, port, heart_queue='default', external=False): 5 | if heart_queue=='default': 6 | import Queue 7 | heart_queue=Queue.Queue() 8 | if external: 9 | host='0.0.0.0' 10 | else: 11 | host = 'localhost' 12 | backlog = 5 13 | time.sleep(1) 14 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 15 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 16 | try: 17 | s.bind((host,port)) 18 | except: 19 | tools.kill_processes_using_ports([str(port)]) 20 | tools.kill_processes_using_ports([str(port)]) 21 | time.sleep(2) 22 | return serve_forever(handler, port, heart_queue) 23 | s.listen(backlog) 24 | while True: 25 | try: 26 | a=serve_once(s, MAX_MESSAGE_SIZE, handler) 27 | if a=='stop': 28 | s.close() 29 | tools.log('shutting off server: ' +str(port)) 30 | return 31 | except Exception as exc: 32 | tools.log('networking error: ' +str(port)) 33 | tools.log(exc) 34 | def recvall(client, data=''): 35 | try: 36 | data+=client.recv(MAX_MESSAGE_SIZE) 37 | except: 38 | time.sleep(0.0004) 39 | tools.log('not ready') 40 | recvall(client, data) 41 | if not data: 42 | return 'broken connection' 43 | if len(data)<5: return recvall(client, data) 44 | try: 45 | length=int(data[0:5]) 46 | except: 47 | return 'no length' 48 | tries=0 49 | data=data[5:] 50 | while len(data)10: 80 | tools.log('networking connect error') 81 | error() 82 | return(connect(msg, port, host, counter+1)) 83 | def send_msg(data, sock): 84 | data=tools.package(data) 85 | data=tools.buffer_(str(len(data)), 5)+data 86 | while data: 87 | time.sleep(0.0001) 88 | try: 89 | sent = sock.send(data) 90 | except: 91 | return 'peer died' 92 | data = data[sent:] 93 | return 0 94 | def connect(msg, port, host='localhost', counter=0): 95 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 96 | #s.setblocking(5) 97 | s.settimeout(5) 98 | try: 99 | s.connect((host,port)) 100 | except: 101 | return({'error': 'cannot connect host:'+str(host) + ' port:' +str(port)}) 102 | try: 103 | msg['version'] = custom.version 104 | except: 105 | pass 106 | r=send_msg(msg, s) 107 | if r=='peer died': 108 | return connect_error(msg, port, host, counter)#return('peer died: ' +str(msg)) 109 | data= recvall(s) 110 | if data=='broken connection': 111 | tools.log('broken connection: ')# +str(msg)) 112 | return(connect_error(msg, port, host, counter)) 113 | if data=='no length': 114 | tools.log('no length: ' +str(msg)) 115 | return(connect_error(msg, port, host, counter)) 116 | return(data) 117 | def send_command(peer, msg, response_time=1): 118 | #tools.log('send command peer: ' +str(peer)) 119 | return connect(msg, peer[1], peer[0]) 120 | if __name__ == "__main__": 121 | serve_forever(lambda x: x, 8000) 122 | -------------------------------------------------------------------------------- /transactions.py: -------------------------------------------------------------------------------- 1 | """This file explains how we tell if a transaction is valid or not, it explains 2 | how we update the database when new transactions are added to the blockchain.""" 3 | import blockchain, custom, copy, tools, txs_tools 4 | import txs_truthcoin as tt 5 | E_check=tools.E_check 6 | def sigs_match(Sigs, Pubs, msg): 7 | pubs=copy.deepcopy(Pubs) 8 | sigs=copy.deepcopy(Sigs) 9 | def match(sig, pubs, msg): 10 | for p in pubs: 11 | if tools.verify(msg, sig, p): 12 | return {'bool':True, 'pub':p} 13 | return {'bool':False} 14 | for sig in sigs: 15 | a=match(sig, pubs, msg) 16 | if not a['bool']: 17 | return False 18 | sigs.remove(sig) 19 | pubs.remove(a['pub']) 20 | return True 21 | def signature_check(tx): 22 | tx_copy = copy.deepcopy(tx) 23 | if not E_check(tx, 'signatures', list): 24 | tools.log('no signautres') 25 | return False 26 | if not E_check(tx, 'pubkeys', list): 27 | tools.log('no pubkeys') 28 | return False 29 | tx_copy.pop('signatures') 30 | if len(tx['pubkeys']) == 0: 31 | tools.log('pubkey error') 32 | return False 33 | if len(tx['signatures']) > len(tx['pubkeys']): 34 | tools.log('sigs too long') 35 | return False 36 | msg = tools.det_hash(tx_copy) 37 | if not sigs_match(copy.deepcopy(tx['signatures']), 38 | copy.deepcopy(tx['pubkeys']), msg): 39 | tools.log('sigs do not match') 40 | return False 41 | return True 42 | 43 | def spend_verify(tx, txs, out, DB): 44 | if not E_check(tx, 'to', [str, unicode]): 45 | out[0]+='no to' 46 | return False 47 | if not signature_check(tx): 48 | out[0]+='signature check' 49 | return False 50 | if len(tx['to'])<=30: 51 | out[0]+='that address is too short' 52 | out[0]+='tx: ' +str(tx) 53 | return False 54 | if not E_check(tx, 'amount', int): 55 | out[0]+='no amount' 56 | return False 57 | if not txs_tools.fee_check(tx, txs, DB): 58 | out[0]+='fee check error' 59 | return False 60 | if 'vote_id' in tx: 61 | if not tx['to'][:-29]=='11': 62 | out[0]+='cannot hold votecoins in a multisig address' 63 | return False 64 | return True 65 | def mint_verify(tx, txs, out, DB): 66 | return 0 == len(filter(lambda t: t['type'] == 'mint', txs)) 67 | tx_check = {'spend':spend_verify, 68 | 'mint':mint_verify, 69 | 'create_jury':tt.create_jury_check, 70 | 'propose_decision':tt.propose_decision_check, 71 | 'jury_vote':tt.jury_vote_check, 72 | 'slasher_jury_vote':tt.slasher_jury_vote_check, 73 | 'reveal_jury_vote':tt.reveal_jury_vote_check, 74 | 'SVD_consensus':tt.SVD_consensus_check, 75 | 'prediction_market':tt.prediction_market_check, 76 | 'buy_shares':tt.buy_shares_check, 77 | 'collect_winnings':tt.collect_winnings_check} 78 | #------------------------------------------------------ 79 | adjust_int=txs_tools.adjust_int 80 | adjust_dict=txs_tools.adjust_dict 81 | adjust_list=txs_tools.adjust_list 82 | symmetric_put=txs_tools.symmetric_put 83 | def mint(tx, DB, add_block): 84 | address = tools.addr(tx) 85 | adjust_int(['amount'], address, custom.block_reward, DB, add_block) 86 | adjust_int(['count'], address, 1, DB, add_block) 87 | def spend(tx, DB, add_block): 88 | address = tools.addr(tx) 89 | if 'vote_id' in tx: 90 | txs_tools.initialize_to_zero_votecoin(tx['vote_id'], address, DB, add_block) 91 | txs_tools.initialize_to_zero_votecoin(tx['vote_id'], tx['to'], DB, add_block) 92 | adjust_int(['votecoin', tx['vote_id']], address, -tx['amount'], DB, add_block) 93 | adjust_int(['votecoin', tx['vote_id']], tx['to'], tx['amount'], DB, add_block) 94 | txs_tools.memory_leak_votecoin(tx['vote_id'], address, DB, add_block)#this should get rid of any zeros in the jury so we don't leak memory. 95 | txs_tools.memory_leak_votecoin(tx['vote_id'], tx['to'], DB, add_block)#this should get rid of any zeros in the jury so we don't leak memory. 96 | else: 97 | adjust_int(['amount'], address, -tx['amount'], DB, add_block) 98 | adjust_int(['amount'], tx['to'], tx['amount'], DB, add_block) 99 | adjust_int(['amount'], address, -custom.fee, DB, add_block) 100 | adjust_int(['count'], address, 1, DB, add_block) 101 | update = {'mint':mint, 102 | 'spend':spend, 103 | 'create_jury':tt.create_jury, 104 | 'propose_decision':tt.propose_decision, 105 | 'jury_vote':tt.jury_vote, 106 | 'reveal_jury_vote':tt.reveal_jury_vote, 107 | 'slasher_jury_vote':tt.slasher_jury_vote, 108 | 'SVD_consensus':tt.SVD_consensus, 109 | 'prediction_market':tt.prediction_market, 110 | 'buy_shares':tt.buy_shares, 111 | 'collect_winnings':tt.collect_winnings} 112 | -------------------------------------------------------------------------------- /pc/CustomMath_test.py: -------------------------------------------------------------------------------- 1 | def test_GetWeight(): 2 | print(GetWeight([1,1,1,1])) 3 | # [1] 0.25 0.25 0.25 0.25 4 | print(GetWeight([10,10,10,10])) 5 | # [1] 0.25 0.25 0.25 0.25 6 | print(GetWeight([4,5,6,7])) 7 | # [1] 0.1818182 0.2272727 0.2727273 0.3181818 8 | print(GetWeight([4,5,6,7], True)) 9 | # [1] 0.2159091 0.2386364 0.2613636 0.2840909 10 | def catch_test(): 11 | print(Catch(Decimal('.4')))#0 12 | print(Catch(Decimal('.5')))#0.5 13 | print(Catch(Decimal('.6')))#1 14 | print(Catch(Decimal('.6'), Tolerance=Decimal('0.1')))#1 15 | print(Catch(Decimal('.6'), Tolerance=Decimal('0.2')))#0.5 16 | def MeanNATest(): 17 | v=[3,4,6,7,8] 18 | print(MeanNA(v)) 19 | # [1] 3 4 6 7 8 20 | v=[3,'NA',6,7,8] 21 | print(MeanNA(v)) 22 | # [1] 3 6 6 7 8 23 | v=[0,0,0,1,'NA'] 24 | print(MeanNA(v)) 25 | # [1] 0.00 0.00 0.00 1.00 0.25 26 | v=[0,0,'NA',1,'NA'] 27 | print(MeanNA(v)) 28 | # [1] 0.0000000 0.0000000 0.3333333 1.0000000 0.3333333 29 | def rescale_test(): 30 | m=[[1, 1, 0, 0],#, 233, Decimal(16027.59)], 31 | [1, 0, 0, 0],# 199, 'NA'], 32 | [1, 1, 0, 0],# 233, 16027.59], 33 | [1, 1, 1, 0],# 250, 'NA'], 34 | [0, 0, 1, 1],# 435, 8001.00], 35 | [0, 0, 1, 1]]#, 435, 19999.00]] 36 | print(Rescale(m)) 37 | def influence_test(): 38 | print(Influence([Decimal('0.25')]*4))#[1,1,1,1] 39 | print(Influence([Decimal('0.3')]*2+[Decimal('0.4')]))#[0.9,0.9,1.2] 40 | print(Influence([Decimal('0.99')]+[Decimal('0.0025')]*4)) 41 | ## [1] 4.9500 0.0125 0.0125 0.0125 0.0125 42 | def reweight_test(): 43 | print(ReWeight([1,1,1,1]))#[.25, .25, .25, .25] 44 | print(ReWeight(['NA',1,'NA',1]))#[0, .5, 0, .5] 45 | print(ReWeight([2,4,6,12]))## [1] 0.08333333 0.16666667 0.25000000 0.50000000 46 | print(ReWeight([2,4,'NA',12]))# [1] 0.1111111 0.2222222 0.0000000 0.6666667 47 | def test_weighted_sample_mean(): 48 | m=[[1,0,1],[1,1,1],[1,0,1]] 49 | c=[1,1,1] 50 | Mat=numpy.ma.masked_array(m) 51 | Coins=numpy.array(map(lambda x: [x], c)) 52 | print(weighted_sample_mean(m, c)) 53 | print(numpy.ma.average(Mat, axis=0, weights=numpy.hstack(Coins))) # Computing the weighted sample mean (fast, efficient and precise) 54 | def test_subtract_vector(): 55 | m=[[1,0,1],[1,1,1],[1,0,1]] 56 | Mat=numpy.ma.masked_array(m) 57 | v=[.5, .5, 0] 58 | #print(Mat) 59 | print(numpy.matrix(Mat-numpy.array(v))) 60 | print(subtract_vector(m, v)) 61 | def test_matrix_multiply(): 62 | m=[[1,0,1],[1,1,1],[1,0,1]] 63 | Mat=numpy.ma.masked_array(m) 64 | coins=numpy.ma.masked_array([[1],[1],[2]]) 65 | print(matrix_multiply(Mat, coins)) 66 | print(numpy.ma.multiply(Mat, coins)) 67 | def dot_test(): 68 | m=[[1,2,3],[1,0,0],[0,4,0]] 69 | m2=[[1],[1],[0]] 70 | Mat=numpy.ma.masked_array(m) 71 | Mat2=numpy.ma.masked_array(m2) 72 | a=numpy.dot(Mat, Mat2) 73 | b=dot(m, m2) 74 | print(a) 75 | print(b) 76 | def v_average_test(): 77 | import numpy.ma as ma 78 | M=[[1,1,0],[0,0,1],[0,1,0]] 79 | Coins=[100000,200000,300000] 80 | Mat=numpy.matrix(M) 81 | Mean = ma.average(Mat, axis=0, weights=numpy.hstack(Coins)) 82 | print(Mean) 83 | print(v_average(M, ReWeight(Coins))) 84 | def b_test(): 85 | from numpy import ma as ma 86 | td=0.33333333333333333 87 | XM=[[-td, -td, 2*td], 88 | [2*td, 2*td, -td], 89 | [-td, -td, -td]] 90 | Coins=[1000000]*3 91 | print(ma.multiply(XM, Coins).T.dot(XM)) 92 | print(dot(switch_row_cols(matrix_multiply(XM, Coins)), XM)) 93 | def weighted_cov_test(): 94 | Mat=[[0,0,1],[1,1,0],[0,0,0]] 95 | print(WeightedCov(Mat, [1,1,1])) 96 | def weighted_median_test(): 97 | print(weighted_median([3,4,5],[Decimal('.2'),Decimal('.2'),Decimal('.6')])) 98 | print(weighted_median([3,4,5],[Decimal('.2'),Decimal('.2'),Decimal('.5')])) 99 | print(weighted_median([3,4,5],[Decimal('.2'),Decimal('.2'),Decimal('.4')])) 100 | def dot_test(): 101 | a=[[1,0], 102 | [0,1]] 103 | n=[[2,0], 104 | [0,1]] 105 | c=[[-33333.33333333, 66666.66666667, -33333.33333333], 106 | [-33333.33333333, 66666.66666667, -33333.33333333], 107 | [ 66666.66666667, -33333.33333333, -33333.33333333]] 108 | XM=[[-0.33333333, -0.33333333, 0.66666667], 109 | [ 0.66666667, 0.66666667, -0.33333333], 110 | [-0.33333333, -0.33333333, -0.33333333]] 111 | print(dot(c, XM)) 112 | import numpy 113 | print(numpy.dot(c, XM)) 114 | def ma_multiply_test(): 115 | XM=[[1,0,1,0],[0,1,0,0],[0,0,100, 0]] 116 | Coins=[[1],[2],[3]] 117 | from numpy import ma 118 | print(ma.multiply(XM, Coins)) 119 | print(ma_multiply(XM, Coins)) 120 | Coins=[1,2,3,4] 121 | print(ma.multiply(XM, Coins)) 122 | print(ma_multiply(XM, Coins)) 123 | def weightedprincomp_test(): 124 | import pprint 125 | M=[[0,0,1],[1,1,0],[0,0,0]] 126 | V=[Decimal('.1')]*3#]#, [Decimal('.1')], [Decimal('.8')], [Decimal('.1')]] 127 | a=WeightedPrinComp(M,V) 128 | pprint.pprint(WeightedPrinComp(M,V)) 129 | -------------------------------------------------------------------------------- /pc/CustomMath.py: -------------------------------------------------------------------------------- 1 | from cdecimal import Decimal 2 | import copy, svd 3 | def AsMatrix(v): return map(lambda i: [i], v) 4 | def matrix_p(v): return type(v[0])==list 5 | def mean(v): return sum(v)*Decimal('1.0')/len(v) 6 | def replace_na(x, m): 7 | if type(x) in [int, float]: 8 | return x 9 | return m 10 | def GetWeight(Vec, AddMean=False): 11 | new=map(abs, Vec) 12 | m=mean(new) 13 | tot=sum(new) 14 | if AddMean: new=map(lambda x: x+m, new) 15 | if(tot==0): new=map(lambda x: x+1, new) 16 | s=Decimal(sum(new)) 17 | new=map(lambda x: Decimal(x)/s, new) 18 | return new 19 | def dec_greater_than(a, b): return float(a)>float(b) 20 | def Catch(X, Tolerance=0): 21 | h=Decimal('0.5') 22 | t=Tolerance/2 23 | if dec_greater_than(X,h+t): 24 | return Decimal('1') 25 | if dec_greater_than(h-t, X): 26 | return Decimal('0') 27 | return Decimal('0.5') 28 | def median_walker(so_far_w, limit, x, w, prev_x): 29 | if so_far_w>limit: return prev_x 30 | if so_far_w==limit: return mean([Decimal('1.0')*prev_x, x[0]]) 31 | return median_walker(so_far_w+w[0], limit, x[1:], w[1:], x[0]) 32 | def weighted_median(x, w): 33 | x, w=zip(*sorted(zip(x, w))) 34 | return median_walker(0, sum(w)*Decimal('1.0')/2, x, w, x[0]) 35 | def switch_row_cols(m): 36 | if not matrix_p(m): 37 | m=AsMatrix(m) 38 | out=[] 39 | for i in range(len(m[0])): 40 | newrow=[] 41 | for row in m: 42 | newrow.append(row[i]) 43 | out.append(newrow) 44 | return out 45 | def MeanNA(v): 46 | vf=filter(lambda x: type(x) in [int, float], v) 47 | m=mean(vf) 48 | return map(lambda x: replace_na(x, m), v) 49 | def Rescale(UnscaledMatrix): 50 | flipped_m=switch_row_cols(UnscaledMatrix) 51 | out=[] 52 | for row in flipped_m: 53 | mrow=MeanNA(copy.deepcopy(row)) 54 | ma=max(mrow) 55 | mi=min(mrow) 56 | out.append(map(lambda x: 'NA' if type(x)==str else (x-mi)/(ma-mi), row)) 57 | return switch_row_cols(out) 58 | def Influence(Weight): 59 | l=len(Weight) 60 | return map(lambda x: x*l, Weight) 61 | def ReWeight(v): 62 | if type(v[0])==list: v=map(lambda x: x[0], v) 63 | w=map(lambda x: 0 if type(x)==str else x, v) 64 | s=sum(w) 65 | return map(lambda x: x*Decimal('1.0')/s, w) 66 | def v2m(v): 67 | if not matrix_p(v): 68 | v=AsMatrix(v) 69 | return v 70 | def dot(m, n): 71 | m=v2m(m) 72 | n=v2m(n) 73 | out=[] 74 | for i in range(len(m)): 75 | row=[] 76 | for j in range(len(n[0])): 77 | row.append(sum( m[i][k] * map(lambda x: x[j], n)[k] for k in range(len(m[0])))) 78 | out.append(row) 79 | return out 80 | def weighted_sample_mean(matrix, weighting): 81 | weighting=ReWeight(weighting) 82 | matrix=dot(matrix, weighting) 83 | out=[] 84 | for i in range(len(matrix[0])): 85 | n=0 86 | for m in matrix: 87 | n+=m[i] 88 | out.append(n) 89 | return out 90 | def subtract_vector(m, v): 91 | if type(v[0])==list and len(v[0])>1: v=v[0] 92 | if not matrix_p(v): 93 | v=AsMatrix(v) 94 | out=[] 95 | for row in range(len(m)): 96 | n=[] 97 | for column in range(len(v)): 98 | n.append(m[row][column]-v[column][0]) 99 | out.append(n) 100 | return out 101 | def v_average(M, W): 102 | M=copy.deepcopy(M) 103 | for row in range(len(M)): 104 | M[row]=map(lambda x: x*W[row], M[row]) 105 | out=[] 106 | for i in range(len(M[0])): 107 | n=0 108 | for j in range(len(M)): 109 | n+=M[j][i] 110 | out.append(n) 111 | return out 112 | def ma_multiply(m, v): 113 | out=[] 114 | if type(v[0])==list and len(v)>0:#if v is vertical 115 | for row in range(len(m)): 116 | out.append(map(lambda x: x*v[row][0], m[row])) 117 | else: 118 | if type(v[0])==list: v=v[0] 119 | for row in range(len(m)): 120 | out.append(map(lambda i: m[row][i]*v[i], range(len(m[0])))) 121 | return out 122 | def WeightedCov(Mat, Rep=-1):#should only output square matrices. 123 | if type(Rep) is int: Rep=map(lambda x: x/Decimal(len(Mat)), [1]*len(Mat)) 124 | Coins=copy.deepcopy(Rep) 125 | #if type(Coins[0])==list: Coins=map(lambda x: x[0], Coins) 126 | Coins=map(lambda y: [y[0]*1000000], Coins) 127 | Mean=v_average(Mat, ReWeight(Coins)) 128 | XM=subtract_vector(Mat, Mean) 129 | a=Decimal('1')/(sum(map(lambda x: x[0], Coins))-1) 130 | c=switch_row_cols(ma_multiply(XM,Coins)) 131 | b=dot(c,XM) 132 | sigma2=map(lambda row: map(lambda x: x*a, row), b) 133 | return({'Cov':sigma2, 'Center':XM}) 134 | def WeightedPrinComp(M, Weights): 135 | if len(Weights)!=len(M): 136 | print('Weights must be equal in length to rows') 137 | return 'error' 138 | if type(Weights[0])!=list: Weights=map(lambda x: [x], Weights) 139 | wCVM=WeightedCov(M, Weights) 140 | SVD=svd.svd(wCVM['Cov']) 141 | L=switch_row_cols(SVD[0])[0] 142 | S=switch_row_cols(dot(wCVM['Center'], L))[0] 143 | return{'Scores':S, 'Loadings':L} 144 | -------------------------------------------------------------------------------- /miner.py: -------------------------------------------------------------------------------- 1 | """ This file mines blocks and talks to peers. It maintains consensus of the 2 | blockchain. 3 | """ 4 | from Queue import Empty 5 | import blockchain 6 | import copy 7 | import custom 8 | import tools 9 | import networking 10 | import multiprocessing 11 | import random 12 | import time 13 | import copy 14 | import target 15 | def make_mint(pubkey, DB): 16 | address = tools.make_address([pubkey], 1) 17 | return {'type': 'mint', 18 | 'pubkeys': [pubkey], 19 | 'signatures': ['first_sig'], 20 | 'count': tools.count(address, DB)} 21 | def longest_peer(): 22 | if not tools.db_existence('peers'): 23 | return 1000000 24 | peers=tools.db_get('peers') 25 | peers=map(lambda p: peers[p], peers.keys()) 26 | peers=filter(lambda x: x['blacklist']<500, peers) 27 | peers=sorted(peers, key=lambda x: x['diffLength']) 28 | return peers[-1]['length'] 29 | def genesis(pubkey, DB): 30 | target_ = target.target() 31 | out = {'version': custom.version, 32 | 'length': 0, 33 | 'time': time.time(), 34 | 'target': target_, 35 | 'diffLength': blockchain.hexInvert(target_), 36 | 'txs': [make_mint(pubkey, DB)]} 37 | out = tools.unpackage(tools.package(out)) 38 | return out 39 | def make_block(prev_block, txs, pubkey, DB): 40 | leng = int(prev_block['length']) + 1 41 | target_ = target.target(leng) 42 | diffLength = blockchain.hexSum(prev_block['diffLength'], 43 | blockchain.hexInvert(target_)) 44 | out = {'version': custom.version, 45 | 'txs': txs + [make_mint(pubkey, DB)], 46 | 'length': leng, 47 | 'time': time.time(), 48 | 'diffLength': diffLength, 49 | 'target': target_, 50 | 'prevHash': tools.det_hash(prev_block)} 51 | out = tools.unpackage(tools.package(out)) 52 | return out 53 | def POW(block, restart_signal): 54 | halfHash = tools.det_hash(block) 55 | block[u'nonce'] = random.randint(0, 10000000000000000000000000000000000000000) 56 | count = 0 57 | while tools.det_hash({u'nonce': block['nonce'], 58 | u'halfHash': halfHash}) > block['target']: 59 | count += 1 60 | block[u'nonce'] += 1 61 | if restart_signal.is_set(): 62 | restart_signal.clear() 63 | return {'solution_found': True} 64 | return block 65 | def new_worker(solution_queue): 66 | in_queue=multiprocessing.Queue() 67 | restart=multiprocessing.Event() 68 | proc = multiprocessing.Process(target=miner, args=(restart, solution_queue, in_queue)) 69 | proc.daemon=True 70 | proc.start() 71 | return({'in_queue':in_queue, 'restart':restart, 'solution_queue':solution_queue, 'proc':proc}) 72 | def restart_workers(workers): 73 | for worker in workers: 74 | tools.dump_out(worker['in_queue']) 75 | worker['restart'].set() 76 | def main(pubkey, DB): 77 | num_cores = multiprocessing.cpu_count() 78 | solution_queue = multiprocessing.Queue() 79 | workers = [new_worker(solution_queue) for _ in range(num_cores)] 80 | try: 81 | while True: 82 | length=tools.db_get('length') 83 | l=longest_peer() 84 | if tools.db_get('stop'): 85 | tools.dump_out(solution_queue) 86 | tools.log('shutting off miner') 87 | restart_workers(workers) 88 | return 89 | elif tools.db_get('mine') and (l<=length or l<3): 90 | main_once(pubkey, DB, num_cores, solution_queue, workers) 91 | else: 92 | time.sleep(1) 93 | except Exception as exc: 94 | tools.log('miner main: ') 95 | tools.log(exc) 96 | def main_once(pubkey, DB, num_cores, solution_queue, workers): 97 | length=tools.db_get('length') 98 | if length==-1: 99 | candidate_block = genesis(pubkey, DB) 100 | else: 101 | prev_block = tools.db_get(length, DB) 102 | try: 103 | candidate_block = make_block(prev_block, tools.db_get('txs'), pubkey, DB) 104 | except Exception as exc:#sometimes a block gets deleted after we grab length and before we call make_block. 105 | tools.log(exc) 106 | return main_once(pubkey, DB, num_cores, solution_queue, workers) 107 | work = candidate_block 108 | for worker in workers: 109 | worker['in_queue'].put(work) 110 | worker['in_queue'].put(work) 111 | start=time.time() 112 | while solution_queue.empty() and time.time()')) 15 | if len(pubkey)>40: 16 | out=tools.make_address([pubkey], 1) 17 | else: 18 | out=pubkey 19 | return tx 20 | def common_buy_shares(tx, num_states, brainwallet): 21 | privkey=tools.det_hash(brainwallet) 22 | pubkey=tools.privtopub(privkey) 23 | address=tools.make_address([pubkey], 1) 24 | tx['pubkeys']=[pubkey] 25 | tx['count'] = tools.count(address, {}) 26 | cost=txs_tools.cost_to_buy_shares(tx) 27 | tx['price_limit']=int(cost*1.01)+1 28 | print('now for a little proof of work. This may take several minutes. The purpose of this pow is to make it more difficult for a front runner to steal your trade.') 29 | tx=tools.unpackage(tools.package(tx)) 30 | tx=tools.POW(tx) 31 | tx['signatures']=[tools.sign(tools.det_hash(tx), privkey)] 32 | print('tx for copy/pasting into pushtx: '+tools.package(tx).encode('base64')) 33 | return tx 34 | def build_buy_shares(): 35 | tx={'type':'buy_shares', 'PM_id':str(raw_input('What is the unique name for this prediction market?\n>'))} 36 | num_states=int(raw_input('how many states does this pm have?\n>')) 37 | tx['buy']=[] 38 | for i in range(num_states): 39 | tx['buy'].append(int(raw_input('how many shares do you want to buy of state '+str(i)+'? To sell states, use negative numbers.\n>'))) 40 | brainwallet=str(raw_input('What is your brainwallet\n>')) 41 | return common_buy_shares(tx, num_states, brainwallet) 42 | def build_pm(): 43 | tx={'type':'prediction_market', 'fees':0} 44 | pubkey=str(raw_input('What is the address or pubkey of the owner of the PM?\n>')) 45 | if len(pubkey)>40: 46 | tx['owner']=tools.make_address([pubkey], 1) 47 | else: 48 | tx['owner']=pubkey 49 | tx['PM_id']=str(raw_input('What is the unique name for this new prediction market?\n>')) 50 | tx['B']=int(raw_input('how big should B be? Initial investment is B*ln(n) where n is the number of states\n>')) 51 | num_decisions=int(raw_input('how many decisions is this prediction market to be based upon?\n>')) 52 | tx['decisions']=[] 53 | for i in range(num_decisions): 54 | tx['decisions'].append(str(raw_input('What is the unique name of the '+str(i)+' decision?\n>'))) 55 | num_states=int(raw_input('how many states can this PM result in?\n>')) 56 | if num_states>2**num_decisions: 57 | print('too many states') 58 | return False 59 | tx['states_combinatory']=[] 60 | tx['states']=[] 61 | for i in range(num_states): 62 | tx['states'].append(str(raw_input('what is the text title of the '+str(i)+' state?\n>'))) 63 | if i!=num_states-1: 64 | next_comb=(str(raw_input('how does the '+str(i)+' state depend upon the outcome of the decisions? For example: if there are 2 decisions, and this market only comes true when the first is "yes" and the second is "no", then you would put: "1 0" here.\n>'))) 65 | tx['states_combinatory'].append(map(int, next_comb.split(' '))) 66 | print('tx for copy/pasting into pushtx: '+tools.package(tx).encode('base64')) 67 | return tx 68 | def main(c=0): 69 | if type(c)==int: 70 | p={'command':sys.argv[1:]} 71 | else: 72 | p={'command':c} 73 | if len(p['command'])==0: 74 | p['command'].append(' ') 75 | c=p['command'] 76 | if c[0]=='make_PM': 77 | tx=build_pm() 78 | return run_command({'command':['pushtx', tools.package(tx).encode('base64')]}) 79 | elif c[0]=='buy_shares': 80 | tx=build_buy_shares() 81 | return run_command({'command':['pushtx', tools.package(tx).encode('base64')]}) 82 | elif c[0]=='start': 83 | r=connect({'command':'blockcount'}) 84 | if is_truthcoin_off(r): 85 | p=raw_input('what is your password?\n') 86 | daemonize(lambda: threads.main(p)) 87 | else: 88 | print('truthcoin is already running') 89 | elif c[0]=='new_address': 90 | if len(c)<2: 91 | print('what is your brain wallet? not enough inputs.') 92 | else: 93 | privkey=tools.det_hash(c[1]) 94 | pubkey=tools.privtopub(privkey) 95 | address=tools.make_address([pubkey], 1) 96 | return({'brain':str(c[1]), 97 | 'privkey':str(privkey), 98 | 'pubkey':str(pubkey), 99 | 'address':str(address)}) 100 | else: 101 | return run_command(p) 102 | def connect(p): 103 | peer=['localhost', custom.api_port] 104 | response=networking.send_command(peer, p, 5) 105 | if tools.can_unpack(response): 106 | response=tools.unpackage(response) 107 | return response 108 | def is_truthcoin_off(response): return type(response)==type({'a':1}) and 'error' in response 109 | def run_command(p): 110 | response=connect(p) 111 | if is_truthcoin_off(response): 112 | print('truthcoin is probably off. Use command: "./truth_cli.py start" to turn it on.') 113 | return json.dumps(response, indent=3, sort_keys=True) 114 | 115 | if __name__=='__main__': #for windows 116 | print(main()) 117 | 118 | -------------------------------------------------------------------------------- /pt/deterministic.py: -------------------------------------------------------------------------------- 1 | from main import * 2 | import hmac, hashlib 3 | 4 | ### Electrum wallets 5 | 6 | def electrum_stretch(seed): return slowsha(seed) 7 | 8 | # Accepts seed or stretched seed, returns master public key 9 | def electrum_mpk(seed): 10 | if len(seed) == 32: seed = electrum_stretch(seed) 11 | return privkey_to_pubkey(seed)[2:] 12 | 13 | # Accepts (seed or stretched seed), index and secondary index 14 | # (conventionally 0 for ordinary addresses, 1 for change) , returns privkey 15 | def electrum_privkey(seed,n,for_change=0): 16 | if len(seed) == 32: seed = electrum_stretch(seed) 17 | mpk = electrum_mpk(seed) 18 | offset = dbl_sha256(str(n)+':'+str(for_change)+':'+mpk.decode('hex')) 19 | return add_privkeys(seed, offset) 20 | 21 | # Accepts (seed or stretched seed or master public key), index and secondary index 22 | # (conventionally 0 for ordinary addresses, 1 for change) , returns pubkey 23 | def electrum_pubkey(masterkey,n,for_change=0): 24 | if len(masterkey) == 32: mpk = electrum_mpk(electrum_stretch(masterkey)) 25 | elif len(masterkey) == 64: mpk = electrum_mpk(masterkey) 26 | else: mpk = masterkey 27 | bin_mpk = encode_pubkey(mpk,'bin_electrum') 28 | offset = bin_dbl_sha256(str(n)+':'+str(for_change)+':'+bin_mpk) 29 | return add_pubkeys('04'+mpk,privtopub(offset)) 30 | 31 | # seed/stretched seed/pubkey -> address (convenience method) 32 | def electrum_address(masterkey,n,for_change=0,version=0): 33 | return pubkey_to_address(electrum_pubkey(masterkey,n,for_change),version) 34 | 35 | # Given a master public key, a private key from that wallet and its index, 36 | # cracks the secret exponent which can be used to generate all other private 37 | # keys in the wallet 38 | def crack_electrum_wallet(mpk,pk,n,for_change=0): 39 | bin_mpk = encode_pubkey(mpk,'bin_electrum') 40 | offset = dbl_sha256(str(n)+':'+str(for_change)+':'+bin_mpk) 41 | return subtract_privkeys(pk, offset) 42 | 43 | # Below code ASSUMES binary inputs and compressed pubkeys 44 | PRIVATE = '\x04\x88\xAD\xE4' 45 | PUBLIC = '\x04\x88\xB2\x1E' 46 | 47 | # BIP32 child key derivation 48 | def raw_bip32_ckd(rawtuple, i): 49 | vbytes, depth, fingerprint, oldi, chaincode, key = rawtuple 50 | i = int(i) 51 | 52 | if vbytes == PRIVATE: 53 | priv = key 54 | pub = privtopub(key) 55 | else: 56 | pub = key 57 | 58 | if i >= 2**31: 59 | if vbytes == PUBLIC: 60 | raise Exception("Can't do private derivation on public key!") 61 | I = hmac.new(chaincode,'\x00'+priv[:32]+encode(i,256,4),hashlib.sha512).digest() 62 | else: 63 | I = hmac.new(chaincode,pub+encode(i,256,4),hashlib.sha512).digest() 64 | 65 | if vbytes == PRIVATE: 66 | newkey = add_privkeys(I[:32]+'\x01',priv) 67 | fingerprint = bin_hash160(privtopub(key))[:4] 68 | if vbytes == PUBLIC: 69 | newkey = add_pubkeys(compress(privtopub(I[:32])),key) 70 | fingerprint = bin_hash160(key)[:4] 71 | 72 | return (vbytes, depth + 1, fingerprint, i, I[32:], newkey) 73 | 74 | def bip32_serialize(rawtuple): 75 | vbytes, depth, fingerprint, i, chaincode, key = rawtuple 76 | depth = chr(depth % 256) 77 | i = encode(i,256,4) 78 | chaincode = encode(hash_to_int(chaincode),256,32) 79 | keydata = '\x00'+key[:-1] if vbytes == PRIVATE else key 80 | bindata = vbytes + depth + fingerprint + i + chaincode + keydata 81 | return changebase(bindata+bin_dbl_sha256(bindata)[:4],256,58) 82 | 83 | def bip32_deserialize(data): 84 | dbin = changebase(data,58,256) 85 | if bin_dbl_sha256(dbin[:-4])[:4] != dbin[-4:]: 86 | raise Exception("Invalid checksum") 87 | vbytes = dbin[0:4] 88 | depth = ord(dbin[4]) 89 | fingerprint = dbin[5:9] 90 | i = decode(dbin[9:13],256) 91 | chaincode = dbin[13:45] 92 | key = dbin[46:78]+'\x01' if vbytes == PRIVATE else dbin[45:78] 93 | return (vbytes, depth, fingerprint, i, chaincode, key) 94 | 95 | def raw_bip32_privtopub(rawtuple): 96 | vbytes, depth, fingerprint, i, chaincode, key = rawtuple 97 | return (PUBLIC, depth, fingerprint, i, chaincode, privtopub(key)) 98 | 99 | def bip32_privtopub(data): 100 | return bip32_serialize(raw_bip32_privtopub(bip32_deserialize(data))) 101 | 102 | def bip32_ckd(data,i): 103 | return bip32_serialize(raw_bip32_ckd(bip32_deserialize(data),i)) 104 | 105 | def bip32_master_key(seed): 106 | I = hmac.new("Bitcoin seed",seed,hashlib.sha512).digest() 107 | return bip32_serialize((PRIVATE, 0, '\x00'*4, 0, I[32:], I[:32]+'\x01')) 108 | 109 | def bip32_bin_extract_key(data): 110 | return bip32_deserialize(data)[-1] 111 | 112 | def bip32_extract_key(data): 113 | return bip32_deserialize(data)[-1].encode('hex') 114 | 115 | # Exploits the same vulnerability as above in Electrum wallets 116 | # Takes a BIP32 pubkey and one of the child privkeys of its corresponding privkey 117 | # and returns the BIP32 privkey associated with that pubkey 118 | def raw_crack_bip32_privkey(parent_pub,priv): 119 | vbytes, depth, fingerprint, i, chaincode, key = priv 120 | pvbytes, pdepth, pfingerprint, pi, pchaincode, pkey = parent_pub 121 | i = int(i) 122 | 123 | if i >= 2**31: raise Exception("Can't crack private derivation!") 124 | 125 | I = hmac.new(pchaincode,pkey+encode(i,256,4),hashlib.sha512).digest() 126 | 127 | pprivkey = subtract_privkeys(key,I[:32]+'\x01') 128 | 129 | return (PRIVATE, pdepth, pfingerprint, pi, pchaincode, pprivkey) 130 | 131 | def crack_bip32_privkey(parent_pub,priv): 132 | dsppub = bip32_deserialize(parent_pub) 133 | dspriv = bip32_deserialize(priv) 134 | return bip32_serialize(raw_crack_bip32_privkey(dsppub,dspriv)) 135 | -------------------------------------------------------------------------------- /pc/ConsensusMechanism.py: -------------------------------------------------------------------------------- 1 | from cdecimal import Decimal 2 | import CustomMath as custommath 3 | def DemocracyRep(x): 4 | v=[] 5 | for i in range(len(x)): 6 | v.append(1) 7 | return(custommath.ReWeight(v)) 8 | def GetRewardWeights(M, Rep=-1, alpha=Decimal('0.1')): 9 | if Rep==-1: 10 | Rep=DemocracyRep(M) 11 | if type(Rep[0])==list: 12 | Rep=map(lambda x: x[0], Rep) 13 | Results=custommath.WeightedPrinComp(M, Rep) 14 | FirstLoading=Results['Loadings'] 15 | FirstScore=Results['Scores'] 16 | a=min(map(abs,FirstScore)) 17 | b=max(FirstScore) 18 | Set1=map(lambda x: x+a, FirstScore) 19 | Set2=map(lambda x: x-b, FirstScore) 20 | Old=custommath.dot([Rep], M) 21 | New1=custommath.dot([custommath.GetWeight(Set1)], M) 22 | New2=custommath.dot([custommath.GetWeight(Set2)], M) 23 | def sub_f(a, b): return a-b 24 | def f(n): return sum(map(lambda x: x**2, map(sub_f, n[0], Old[0]))) 25 | RefInd=f(New1)-f(New2) 26 | if(RefInd<=0): AdjPrinComp = Set1 27 | else: AdjPrinComp = Set2 28 | RowRewardWeighted=Rep 29 | if max(map(abs,AdjPrinComp))!=0: 30 | m=custommath.mean(Rep) 31 | RRW=[] 32 | for i in range(len(Rep)): 33 | RRW.append(AdjPrinComp[i]*Rep[i]/m) 34 | RowRewardWeighted=custommath.GetWeight(RRW) 35 | SmoothedR=[] 36 | for i in range(len(Rep)): 37 | SmoothedR.append(alpha*RowRewardWeighted[i]+(1-alpha)*Rep[i]) 38 | Out = {"FirstL":FirstLoading, "OldRep":Rep, "ThisRep":RowRewardWeighted, "SmoothRep":SmoothedR} 39 | return(Out) 40 | def v_dot(a, b): 41 | def mul(c, d): return c*d 42 | return sum(map(mul, a, b)) 43 | def GetDecisionOutcomes(Mtemp, Rep): 44 | # Determines the Outcomes of Decisions based on the provided reputation (weighted vote) 45 | #For each column 46 | out=[] 47 | for i in range(len(Mtemp[0])): 48 | Row=[] 49 | Col=[] 50 | c=map(lambda x: x[i], Mtemp) 51 | for j in range(len(c)): 52 | if type(c[j]) not in [str, unicode]: 53 | Row.append(Rep[j]) 54 | Col.append(c[j]) 55 | Row=custommath.ReWeight(Row) 56 | out.append(v_dot(Col, Row)) 57 | return custommath.switch_row_cols(out) 58 | def any_NA(M): 59 | for row in M: 60 | for i in row: 61 | if i=='NA': return True 62 | return False 63 | def diag(v): 64 | if type(v[0])==list: v=v[0] 65 | out=[] 66 | l=len(v) 67 | for i in range(l): 68 | row=[0]*l 69 | row[i]=v[i] 70 | out.append(row) 71 | return out 72 | def FillNa(Mna, Rep, Catchp=Decimal('0.1')): 73 | Mnew = Mna 74 | MnewC=Mna 75 | if any_NA(Mna): 76 | DecisionOutcomesRaw=GetDecisionOutcomes(Mna, Rep) 77 | NAmat=map(lambda row: map(lambda x: 1 if x=='NA' else 0, row), Mna) 78 | Mnew=map(lambda row: map(lambda x: 0 if x=='NA' else x, row), Mna) 79 | NAsToFill=custommath.dot(NAmat, diag(DecisionOutcomesRaw)) 80 | for row in range(len(Mnew)): 81 | for i in range(len(Mnew[row])): 82 | Mnew[row][i]=Mnew[row][i]+NAsToFill[row][i] 83 | return(map(lambda row: map(lambda x: custommath.Catch(x, Catchp), row), Mnew)) 84 | return(Mna) 85 | def Factory(M0, Rep, CatchP=Decimal('0.1'), MaxRow=5000): 86 | Rep=custommath.ReWeight(Rep) 87 | Filled=FillNa(M0, Rep, CatchP) 88 | PlayerInfo=GetRewardWeights(Filled, Rep, Decimal('0.1')) 89 | AdjLoadings=PlayerInfo['FirstL'] 90 | #print('smoothrep: ' +str(PlayerInfo['SmoothRep']))#way wrong 91 | #print('Filled: ' +str(Filled)) 92 | DecisionOutcomesRaw=custommath.dot([PlayerInfo['SmoothRep']], Filled)[0] 93 | #print('raw outcomes: ' +str(DecisionOutcomesRaw)) 94 | DecisionOutcomeAdj=map(lambda x: custommath.Catch(x, CatchP), DecisionOutcomesRaw) 95 | Certainty=map(lambda x: 2*(x-Decimal('0.5')), DecisionOutcomesRaw) 96 | Certainty=map(abs, Certainty) 97 | ConReward=custommath.GetWeight(Certainty) 98 | Avg_Certainty=custommath.mean(Certainty) 99 | DecisionOutcomeAdj=[] 100 | for i, raw in enumerate(DecisionOutcomesRaw): 101 | DecisionOutcomeAdj.append(custommath.Catch(raw, CatchP)) 102 | DecisionOutcomeFinal=DecisionOutcomeAdj 103 | NAmat=map(lambda row: map(lambda x: 1 if type(x) in [str, unicode] else 0, row), M0) 104 | a=custommath.dot([PlayerInfo['SmoothRep']], NAmat)[0] 105 | ParticipationC=map(lambda x: 1-x, a) 106 | v=map(sum, NAmat) 107 | ParticipationR=map(lambda x: 1-x/Decimal(len(NAmat[0])), v) 108 | PercentNA=1-custommath.mean(ParticipationC) 109 | NAbonusR = custommath.GetWeight(ParticipationR) 110 | def plus(a, b): return a+b 111 | RowBonus = map(plus, map(lambda x: x*PercentNA, NAbonusR), map(lambda x: x*(1-PercentNA), PlayerInfo['SmoothRep'])) 112 | NAbonusC=custommath.GetWeight(ParticipationC) 113 | ColBonus=map(plus, map(lambda x: x*PercentNA, NAbonusC), map(lambda x: x*(1-PercentNA), ConReward)) 114 | namatsum=[] 115 | for i in range(len(NAmat[0])): 116 | namatsum.append(sum(map(lambda x: x[i], NAmat))) 117 | Output = { 118 | 'Original': M0, 119 | 'Filled': Filled, 120 | 'Agents': { 121 | 'OldRep': PlayerInfo['OldRep'],#[0], 122 | 'ThisRep': PlayerInfo['ThisRep'], 123 | 'SmoothRep': PlayerInfo['SmoothRep'], 124 | 'NArow': map(sum, NAmat),#.sum(axis=1).base, 125 | 'ParticipationR': ParticipationR,#.base, 126 | 'RelativePart': NAbonusR,#.base, 127 | 'RowBonus': RowBonus,#.base, 128 | }, 129 | 'Decisions': { 130 | 'First Loading': AdjLoadings, 131 | 'DecisionOutcomes_Raw': DecisionOutcomesRaw, 132 | 'Consensus Reward': ConReward, 133 | 'Certainty': Certainty, 134 | 'NAs Filled': namatsum,#NAmat.sum(axis=0), 135 | 'ParticipationC': ParticipationC, 136 | 'Author Bonus': ColBonus, 137 | 'DecisionOutcome_Final': DecisionOutcomeFinal, 138 | }, 139 | 'Participation': 1 - PercentNA, 140 | 'Certainty': Avg_Certainty, 141 | } 142 | return Output 143 | 144 | -------------------------------------------------------------------------------- /tools.py: -------------------------------------------------------------------------------- 1 | """A bunch of functions that are used by multiple threads. 2 | """ 3 | import pt, hashlib, re, subprocess, time, copy, networking, custom, logging, random 4 | from json import dumps as package, loads as unpackage 5 | from urllib import urlopen 6 | import re 7 | def getPublicIp(): 8 | data = str(urlopen('http://checkip.dyndns.com/').read()) 9 | # data = 'Current IP CheckCurrent IP Address: 65.96.168.198\r\n' 10 | return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1) 11 | def empty_peer(): return {'blacklist':0, 'lag':40.0, 'diffLength':"0", 'length':0} 12 | def peer_split(peer): 13 | a=peer.split(':') 14 | a[1]=int(a[1]) 15 | return a 16 | def port_grab(peer): return peer_split(peer)[1] 17 | def add_peer(peer, current_peers=0): 18 | if current_peers==0: 19 | current_peers=db_get('peers') 20 | if peer in current_peers.keys(): 21 | return False 22 | a=empty_peer() 23 | a['port']=port_grab(peer) 24 | current_peers[peer]=a 25 | db_put('peers',current_peers) 26 | def dump_out(queue): 27 | while not queue.empty(): 28 | try: 29 | queue.get(False) 30 | except: 31 | pass 32 | logging.basicConfig(filename=custom.log_file, level=logging.INFO) 33 | def log(junk): 34 | if isinstance(junk, Exception): 35 | logging.exception(junk) 36 | else: 37 | logging.info(str(junk)) 38 | def can_unpack(o): 39 | try: 40 | unpackage(o) 41 | return True 42 | except: 43 | return False 44 | def addr(tx): return make_address(tx['pubkeys'], len(tx['signatures'])) 45 | def sign(msg, privkey): return pt.ecdsa_sign(msg, privkey) 46 | def verify(msg, sig, pubkey): return pt.ecdsa_verify(msg, sig, pubkey) 47 | def privtopub(privkey): return pt.privtopub(privkey) 48 | def hash_(x): return hashlib.sha384(x).hexdigest()[0:64] 49 | def det_hash(x): 50 | """Deterministically takes sha256 of dict, list, int, or string.""" 51 | return hash_(package(x, sort_keys=True)) 52 | def POW(block): 53 | h=det_hash(block) 54 | block[u'nonce'] = random.randint(0, 10000000000000000000000000000000000000000) 55 | a='F'*64 56 | while det_hash(a) > custom.buy_shares_target: 57 | block[u'nonce'] += 1 58 | a={u'nonce': block['nonce'], u'halfHash': h} 59 | return block 60 | def make_half_way(block): 61 | a = copy.deepcopy(block) 62 | a.pop('nonce') 63 | return({u'nonce': block['nonce'], u'halfHash': det_hash(a)}) 64 | def base58_encode(num): 65 | num = int(num, 16) 66 | alphabet = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ' 67 | base_count = len(alphabet) 68 | encode = '' 69 | if num < 0: 70 | return '' 71 | while (num >= base_count): 72 | mod = num % base_count 73 | encode = alphabet[mod] + encode 74 | num = num / base_count 75 | if num: 76 | encode = alphabet[num] + encode 77 | return encode 78 | def make_address(pubkeys, n): 79 | """n is the number of pubkeys required to spend from this address.""" 80 | return (str(len(pubkeys)) + str(n) + 81 | base58_encode(det_hash({str(n): pubkeys}))[0:29]) 82 | def buffer_(str_to_pad, size): 83 | return str_to_pad.rjust(size, '0') 84 | def E_check(dic, key, type_): 85 | if not isinstance(type_, list): type_=[type_] 86 | if len(type_)==0: return False#to end the recursion. 87 | if not key in dic: return False 88 | if isinstance(type_[0], type): 89 | if not isinstance(dic[key], type_[0]): return E_check(dic, key, type_[1:]) 90 | else: 91 | if not dic[key] == type_[0]: return E_check(dic, key, type_[1:]) 92 | return True 93 | def reveal_time_p(DB={}, n=custom.vote_reveal_length+custom.SVD_length): 94 | r=custom.cycle_length 95 | return db_get('length')%r>=(r-n) 96 | #return db_get('length')%20>=(20-n) 97 | def is_number(s): 98 | try: 99 | int(s) 100 | return True 101 | except: 102 | return False 103 | def kill_processes_using_ports(ports): 104 | popen = subprocess.Popen(['netstat', '-lpn'], 105 | shell=False, 106 | stdout=subprocess.PIPE) 107 | (data, err) = popen.communicate() 108 | pattern = "^tcp.*((?:{0})).* (?P[0-9]*)/.*$" 109 | pattern = pattern.format(')|(?:'.join(ports)) 110 | prog = re.compile(pattern) 111 | for line in data.split('\n'): 112 | match = re.match(prog, line) 113 | if match: 114 | pid = match.group('pid') 115 | subprocess.Popen(['kill', '-9', pid]) 116 | def s_to_db(c): 117 | response=networking.send_command(['localhost', custom.database_port], c) 118 | if (type(response)==dict and 'error' in response): 119 | time.sleep(0.001) 120 | log('s to db failed at '+str(c)) 121 | return s_to_db(c) 122 | else: 123 | return response 124 | default_entry={'count': 0, 'amount': 0, 'votecoin':{}, 'votes':{}, 'shares':{}} 125 | def db_get(n, DB={}): return s_to_db({'type':'get', 'args':[str(n)]}) 126 | def db_put(key, dic, DB={}): return s_to_db({'type':'put', 'args':[str(key), dic]}) 127 | def db_delete(key, DB={}): return s_to_db({'type':'delete', 'args':[str(key)]})#db_put(key, 'undefined', DB) 128 | def db_existence(key, DB={}): return s_to_db({'type':'existence', 'args':[str(key)]}) 129 | def count(address, DB): 130 | # Returns the number of transactions that pubkey has broadcast. 131 | def zeroth_confirmation_txs(address, DB): 132 | def is_zero_conf(t): 133 | other_address=make_address(t['pubkeys'], len(t['signatures'])) 134 | return address == other_address 135 | return len(filter(is_zero_conf, db_get('txs'))) 136 | current = db_get(address, DB)['count'] 137 | zeroth=zeroth_confirmation_txs(address, DB) 138 | return current+zeroth 139 | def fork_check(newblocks, DB, length, block): 140 | recent_hash = det_hash(block) 141 | their_hashes = map(lambda x: x['prevHash'] if x['length']>0 else 0, newblocks)+[det_hash(newblocks[-1])] 142 | b=(recent_hash not in their_hashes) and length>newblocks[0]['length']-1 and length networking.MAX_MESSAGE_SIZE - 5000 33 | def verify_tx(tx, txs, out): 34 | if not type_check(tx, txs): 35 | out[0]+='type error' 36 | return False 37 | if tx in txs: 38 | out[0]+='no duplicates' 39 | return False 40 | if verify_count(tx, txs): 41 | out[0]+='count error' 42 | return False 43 | if too_big_block(tx, txs): 44 | out[0]+='too many txs' 45 | return False 46 | try: 47 | if not transactions.tx_check[tx['type']](tx, txs, out, DB): 48 | out[0]+= 'tx: ' + str(tx) 49 | return False 50 | except Exception as exc: 51 | out[0]+='badly formatted tx caused error: ' +str(tx) 52 | return False 53 | return True 54 | #tools.log('attempt to add tx: ' +str(tx)) 55 | T=tools.db_get('txs') 56 | if verify_tx(tx, T, out): 57 | T.append(tx) 58 | tools.db_put('txs', T) 59 | return(tx) 60 | else: 61 | return('failed to add tx because: '+out[0]) 62 | def recent_blockthings(key, size, length=0): 63 | storage = tools.db_get(key) 64 | def get_val(length): 65 | leng = str(length) 66 | if not leng in storage: 67 | block=tools.db_get(leng) 68 | if block==tools.default_entry: 69 | if leng==tools.db_get('length'): 70 | tools.db_put('length', int(leng)-1) 71 | block=tools.db_get(leng) 72 | else: 73 | error() 74 | #try: 75 | storage[leng] = tools.db_get(leng)[key[:-1]] 76 | tools.db_put(key, storage) 77 | return storage[leng] 78 | def clean_up(storage, end): 79 | if end<0: return 80 | if not str(end) in storage: return 81 | else: 82 | storage.pop(str(end)) 83 | return clean_up(storage, end-1) 84 | if length == 0: 85 | length = tools.db_get('length') 86 | start = max((length-size), 0) 87 | clean_up(storage, length-max(custom.mmm, custom.history_length)-100) 88 | return map(get_val, range(start, length)) 89 | def hexSum(a, b): 90 | # Sum of numbers expressed as hexidecimal strings 91 | return tools.buffer_(str(hex(int(a, 16)+int(b, 16)))[2: -1], 64) 92 | def hexInvert(n): 93 | # Use double-size for division, to reduce information leakage. 94 | return tools.buffer_(str(hex(int('f' * 128, 16) / int(n, 16)))[2: -1], 64) 95 | def add_block(block_pair, recent_hashes, DB={}): 96 | """Attempts adding a new block to the blockchain. 97 | Median is good for weeding out liars, so long as the liars don't have 51% 98 | hashpower. """ 99 | def median(mylist): 100 | if len(mylist) < 1: 101 | return 0 102 | return sorted(mylist)[len(mylist) / 2] 103 | 104 | def block_check(block, DB): 105 | def log_(txt): pass #return tools.log(txt) 106 | def tx_check(txs): 107 | start = copy.deepcopy(txs) 108 | start.reverse() 109 | out = [] 110 | start_copy = [] 111 | error_msg=[''] 112 | while True: 113 | if start == []: return False # Block passes this test 114 | if transactions.tx_check[start[-1]['type']](start[-1], out, error_msg, DB): 115 | out.append(start.pop()) 116 | else: 117 | log_('bad block: ' +str(txs)) 118 | log_('error message: ' +str(error_msg)) 119 | return True # Block is invalid 120 | return True 121 | if not isinstance(block, dict): return False 122 | if 'error' in block: return False 123 | if not tools.E_check(block, 'length', [int]): 124 | log_('no length') 125 | return False 126 | length =tools.db_get('length') 127 | if type(block['length'])!=type(1): 128 | log_('wrong length type') 129 | return False 130 | if int(block['length']) != int(length) + 1: 131 | log_('wrong longth') 132 | return False 133 | if block['diffLength'] != hexSum(tools.db_get('diffLength'), 134 | hexInvert(block['target'])): 135 | log_('diflength error') 136 | return False 137 | if length >= 0: 138 | if tools.det_hash(tools.db_get(length, DB)) != block['prevHash']: 139 | log_('det hash error') 140 | return False 141 | if u'target' not in block.keys(): 142 | log_('target error') 143 | return False 144 | half_way=tools.make_half_way(block) 145 | if tools.det_hash(half_way) > block['target']: 146 | log_('det hash error 2') 147 | 148 | return False 149 | if block['target'] != target.target(block['length']): 150 | log_('block: ' +str(block)) 151 | log_('target: ' +str(target.target(block['length']))) 152 | log_('wrong target') 153 | return False 154 | earliest = median(recent_blockthings('times', custom.mmm)) 155 | if 'time' not in block: 156 | log_('no time') 157 | return False 158 | if block['time'] > time.time()+60*6: 159 | log_('too late') 160 | return False 161 | if block['time'] < earliest: 162 | log_('too early') 163 | return False 164 | if tx_check(block['txs']): 165 | log_('tx check') 166 | return False 167 | return True 168 | if type(block_pair)==type([1,2,3]): 169 | block=block_pair[0] 170 | peer=block_pair[1] 171 | else: 172 | block=block_pair 173 | peer=False 174 | if 'prevHash' in block and block['prevHash'] in recent_hashes: 175 | #tools.log('we have seen this block already') 176 | return 0 177 | #tools.log('attempt to add block: ' +str(block)) 178 | if block_check(block, DB): 179 | #tools.log('add_block: ' + str(block)) 180 | tools.db_put(block['length'], block, DB) 181 | tools.db_put('length', block['length']) 182 | tools.db_put('diffLength', block['diffLength']) 183 | orphans = tools.db_get('txs') 184 | tools.db_put('txs', []) 185 | for tx in block['txs']: 186 | transactions.update[tx['type']](tx, DB, True) 187 | for tx in orphans: 188 | add_tx(tx, DB) 189 | if not peer==False: 190 | peers=tools.db_get('peers') 191 | if peers[peer]['blacklist']>0: 192 | peers[peer]['blacklist']-=1 193 | tools.db_put('peers', peers) 194 | elif not peer==False: 195 | peers=tools.db_get('peers') 196 | if peer not in peers: 197 | peers[peer]=tools.empty_peer() 198 | peers[peer]['blacklist']+=1 199 | def delete_block(DB): 200 | """ Removes the most recent block from the blockchain. """ 201 | length=tools.db_get('length') 202 | if length < 0: 203 | return 204 | try: 205 | ts=tools.db_get('targets') 206 | ts.pop(str(length)) 207 | tools.db_put('targets', ts) 208 | except: 209 | pass 210 | try: 211 | ts=tools.db_get('times') 212 | ts.pop(str(length)) 213 | tools.db_put('times', ts) 214 | except: 215 | pass 216 | block = tools.db_get(length, DB) 217 | orphans = tools.db_get('txs') 218 | tools.db_put('txs', []) 219 | for tx in block['txs']: 220 | orphans.append(tx) 221 | tools.db_put('add_block', False) 222 | transactions.update[tx['type']](tx, DB, False) 223 | tools.db_delete(length, DB) 224 | length-=1 225 | tools.db_put('length', length) 226 | if length == -1: 227 | tools.db_put('diffLength', '0') 228 | else: 229 | block = tools.db_get(length, DB) 230 | tools.db_put('diffLength', block['diffLength']) 231 | for orphan in sorted(orphans, key=lambda x: x['count']): 232 | add_tx(orphan, DB) 233 | #while tools.db_get('length')!=length: 234 | # time.sleep(0.0001) 235 | def f(blocks_queue, txs_queue): 236 | def bb(): return blocks_queue.empty() 237 | def tb(): return txs_queue.empty() 238 | def ff(queue, g, b, s): 239 | while not b(): 240 | #time.sleep(0.0001) 241 | try: 242 | g(queue.get(False)) 243 | except Exception as exc: 244 | tools.log('suggestions ' + s) 245 | tools.log(exc) 246 | def f(): 247 | time.sleep(0.1) 248 | l=tools.db_get('length')+1 249 | v=range(l-10, l) 250 | v=filter(lambda x: x>0, v) 251 | v=map(lambda x: tools.db_get(x), v) 252 | try: 253 | v=map(lambda x: x['prevHash'], v) 254 | except: 255 | #tools.log('v: ' +str(v)) 256 | return 257 | if tools.db_get('stop'): 258 | tools.dump_out(blocks_queue) 259 | tools.dump_out(txs_queue) 260 | return 261 | while not bb() or not tb(): 262 | ff(blocks_queue, lambda x: add_block(x, v), bb, 'block') 263 | ff(txs_queue, add_tx, tb, 'tx') 264 | while True: 265 | f() 266 | import cProfile 267 | def main(DB): return f(DB["suggested_blocks"], DB["suggested_txs"]) 268 | def profile(DB): 269 | import pprint 270 | p=cProfile.Profile() 271 | p.run('blockchain.main(custom.DB)') 272 | g=p.getstats() 273 | #g=g.sorted(lambda x: x.inlinetime) 274 | g=sorted(g, key=lambda x: x.totaltime) 275 | g.reverse() 276 | pprint.pprint(g) 277 | #return f(DB['suggested_blocks'], DB['suggested_txs']) 278 | 279 | -------------------------------------------------------------------------------- /txs_tools.py: -------------------------------------------------------------------------------- 1 | """These are functions that are exclusively used for the truthcoin aspects of the blockchain. 2 | tools.py contains functions that are used everywhere. 3 | """ 4 | import blockchain, custom, tools 5 | from cdecimal import Decimal 6 | 7 | addr=tools.addr 8 | 9 | def weights(vote_id, DB, jury='default'): 10 | out=[] 11 | if jury=='default': 12 | jury=tools.db_get(jury, DB) 13 | if 'members' not in jury: 14 | return 'error' 15 | for member in jury['members']: 16 | acc=tools.db_get(member, DB) 17 | out.append([acc['votecoin'][vote_id]]) 18 | return out 19 | def decision_matrix(jury, decisions, DB): 20 | matrix=[] 21 | if 'members' not in jury: 22 | tools.log('DECISION MATRIX ERROR UNINITIALIZED JURY') 23 | for member in jury['members']:#empty 24 | acc=tools.db_get(member, DB) 25 | row=[] 26 | for decision in decisions: 27 | vote='unsure' 28 | try: 29 | vote=acc['votes'][decision] 30 | except: pass 31 | if vote=='yes': 32 | row.append(1) 33 | elif vote=='no': 34 | row.append(0) 35 | elif vote=='half': 36 | row.append(0.5) 37 | else: 38 | row.append('NA') 39 | matrix.append(row) 40 | return matrix 41 | def decisions_keepers(vote_id, jury, DB): 42 | #this is returning something of length voters. 43 | 44 | wt=map(lambda x: x[0], weights(vote_id, DB, jury)) 45 | if wt=='error': return 'error' 46 | total_weight=sum(wt) 47 | matrix=decision_matrix(jury, jury['decisions'], DB) 48 | #exclude decisions with insufficient participation*certainty 49 | decisions=[] 50 | if len(matrix)<3: 51 | return [] 52 | if len(matrix[0])<5: 53 | return [] 54 | attendance=[] 55 | certainty=[] 56 | for decision in range(len(matrix[0])): 57 | a=0 58 | c=0 59 | for juror in range(len(matrix)): 60 | if not matrix[juror][decision]=='NA': 61 | a+=wt[juror] 62 | if matrix[juror][decision]==1: 63 | c+=wt[juror] 64 | else: 65 | c+=wt[juror]/2.0 66 | attendance.append(a*1.0/total_weight) 67 | certainty.append(abs(c-0.5)*2.0/total_weight) 68 | out=[] 69 | for i in range(len(certainty)): 70 | if certainty[i]*attendance[i]>0.55: 71 | out.append(jury['decisions'][i]) 72 | else: 73 | tools.log('participation times certainty was too low to include this decision: ' +str(jury['decisions'][i])) 74 | l=tools.db_get('length') 75 | for i in out: 76 | o=[] 77 | dec=tools.db_get(i) 78 | if not'maturation' in dec and dec['maturation']>l: 79 | o.append(i) 80 | return o 81 | ''' 82 | from decimal import Decimal 83 | def log_e(x): 84 | return(x.ln) 85 | def cost_to_buy_shares(tx): 86 | pm=tools.db_get(tx['PM_id']) 87 | shares_purchased=pm['shares_purchased'] 88 | buy=tx['buy'] 89 | B=Decimal(pm['B']) 90 | E=Decimal('2.718281828459045') 91 | dec C(shares, B): return B*((sum(map(lambda x: E**(x/B), shares))).ln()) 92 | C_old=C(shares_purchased, B) 93 | def add(a, b): return a+b 94 | C_new=C(map(add, shares_purchased, buy), B) 95 | return int(C_new-C_old) 96 | ''' 97 | E=Decimal('2.718281828459045') 98 | def cost_to_buy_shares(tx): 99 | pm=tools.db_get(tx['PM_id']) 100 | shares_purchased=pm['shares_purchased'] 101 | buy=tx['buy'] 102 | B=pm['B']*Decimal('1.0') 103 | def C(shares, B): return B*(sum(map(lambda x: E**(x/B), shares))).ln() 104 | C_old=C(shares_purchased, B) 105 | def add(a, b): return a+b 106 | C_new=C(map(add, shares_purchased, buy), B) 107 | return int(C_new-C_old) 108 | def cost_0(txs, address): 109 | #cost of the zeroth confirmation transactions 110 | total_cost = [] 111 | votecoin_cost = {} 112 | #address=tools.db_get('address') 113 | for Tx in filter(lambda t: address == addr(t), txs): 114 | def spend_(total_cost=total_cost, votecoin_cost=votecoin_cost): 115 | total_cost.append(custom.fee) 116 | if 'vote_id' not in Tx: 117 | total_cost += [Tx['amount']] 118 | else: 119 | if Tx['vote_id'] not in votecoin_cost: 120 | votecoin_cost[Tx['vote_id']]=0 121 | votecoin_cost[Tx['vote_id']]+=Tx['amount'] 122 | def buy_shares_(total_cost=total_cost): 123 | cost = cost_to_buy_shares(Tx) 124 | total_cost.append(custom.buy_shares_fee) 125 | total_cost.append(cost) 126 | total_cost.append(int(abs(cost*0.01))) 127 | Do={'spend':spend_, 128 | 'mint':(lambda: total_cost.append(-custom.block_reward)), 129 | 'create_jury':(lambda: total_cost.append(custom.create_jury_fee)), 130 | 'propose_decision':(lambda: total_cost.append(custom.propose_decision_fee)), 131 | 'jury_vote':(lambda: total_cost.append(custom.jury_vote_fee)), 132 | 'reveal_jury_vote':(lambda: total_cost.append(custom.reveal_jury_vote_fee)), 133 | 'SVD_consensus':(lambda: total_cost.append(custom.SVD_consensus_fee)), 134 | 'collect_winnings':(lambda: total_cost.append(-custom.collect_winnings_reward)), 135 | 'buy_shares':buy_shares_, 136 | 'prediction_market':(lambda: total_cost.append(Tx['B']*(Decimal(len(Tx['states']))).ln()))} 137 | Do[Tx['type']]() 138 | return {'truthcoin_cost':sum(total_cost), 'votecoin_cost':votecoin_cost} 139 | def fee_check(tx, txs, DB): 140 | address = addr(tx) 141 | cost_=cost_0(txs+[tx], address) 142 | truthcoin_cost = cost_['truthcoin_cost'] 143 | votecoin_cost = cost_['votecoin_cost'] 144 | acc=tools.db_get(address, DB) 145 | if int(acc['amount']) < truthcoin_cost: 146 | tools.log('insufficient truthcoin') 147 | return False 148 | for v_id in votecoin_cost: 149 | if v_id not in acc['votecoin']: 150 | tools.log('votecoin_cost: ' +str(votecoin_cost)) 151 | tools.log('acc: ' +str(acc)) 152 | tools.log('0 votecoin: ' +str(v_id)) 153 | return False 154 | if acc['votecoin'][v_id] yahoo com 6 | # 7 | # Pure Python SVD algorithm. 8 | # Input: 2-D list (m by n) with m >= n 9 | # Output: U,W V so that A = U*W*VT 10 | # Note this program returns V not VT (=transpose(V)) 11 | # On error, a ValueError is raised. 12 | # 13 | # Here is the test case (first example) from Golub and Reinsch 14 | # 15 | # a = [[22.,10., 2., 3., 7.], 16 | # [14., 7.,10., 0., 8.], 17 | # [-1.,13.,-1.,-11., 3.], 18 | # [-3.,-2.,13., -2., 4.], 19 | # [ 9., 8., 1., -2., 4.], 20 | # [ 9., 1.,-7., 5.,-1.], 21 | # [ 2.,-6., 6., 5., 1.], 22 | # [ 4., 5., 0., -2., 2.]] 23 | # 24 | # import svd 25 | # import math 26 | # u,w,vt = svd.svd(a) 27 | # print w 28 | # 29 | # [35.327043465311384, 1.2982256062667619e-15, 30 | # 19.999999999999996, 19.595917942265423, 0.0] 31 | # 32 | # the correct answer is (the order may vary) 33 | # 34 | # print (math.sqrt(1248.),20.,math.sqrt(384.),0.,0.) 35 | # 36 | # (35.327043465311391, 20.0, 19.595917942265423, 0.0, 0.0) 37 | # 38 | # transpose and matrix multiplication functions are also included 39 | # to facilitate the solution of linear systems. 40 | # 41 | # Version 1.0 2005 May 01 42 | 43 | 44 | import copy 45 | from cdecimal import Decimal 46 | ten=Decimal('10') 47 | one=Decimal('1') 48 | zero=Decimal('0') 49 | half=Decimal('0.5') 50 | def sqrt(n): return n**half#return sqrt_h(n, decimal.Decimal(1)) 51 | def svd(a): 52 | '''Compute the singular value decomposition of array.''' 53 | 54 | # Golub and Reinsch state that eps should not be smaller than the 55 | # machine precision, ie the smallest number 56 | # for which 1+e>1. tol should be beta/e where beta is the smallest 57 | # positive number representable in the computer. 58 | eps = ten**(-15)# assumes double precision 59 | tol = (ten**(-64))/eps 60 | assert one+eps > one # if this fails, make eps bigger 61 | assert tol > zero # if this fails, make tol bigger 62 | itmax = 50 63 | u = copy.deepcopy(a) 64 | m = len(a) 65 | n = len(a[0]) 66 | #if __debug__: print 'a is ',m,' by ',n 67 | 68 | if m < n: 69 | if __debug__: print 'Error: m is less than n' 70 | raise ValueError,'SVD Error: m is less than n.' 71 | 72 | e = [zero]*n # allocate arrays 73 | q = [zero]*n 74 | v = [] 75 | for k in range(n): v.append([zero]*n) 76 | 77 | # Householder's reduction to bidiagonal form 78 | 79 | g = zero 80 | x = zero 81 | 82 | for i in range(n): 83 | e[i] = g 84 | s = zero 85 | l = i+1 86 | for j in range(i,m): s += (u[j][i]*u[j][i]) 87 | if s <= tol: 88 | g = zero 89 | else: 90 | f = u[i][i] 91 | if f < zero: 92 | g = sqrt(s) 93 | else: 94 | g = -sqrt(s) 95 | h = f*g-s 96 | u[i][i] = f-g 97 | for j in range(l,n): 98 | s = zero 99 | for k in range(i,m): s += u[k][i]*u[k][j] 100 | f = s/h 101 | for k in range(i,m): u[k][j] = u[k][j] + f*u[k][i] 102 | q[i] = g 103 | s = zero 104 | for j in range(l,n): s = s + u[i][j]*u[i][j] 105 | if s <= tol: 106 | g = zero 107 | else: 108 | f = u[i][i+1] 109 | if f < zero: 110 | g = sqrt(s) 111 | else: 112 | g = -sqrt(s) 113 | h = f*g - s 114 | u[i][i+1] = f-g 115 | for j in range(l,n): e[j] = u[i][j]/h 116 | for j in range(l,m): 117 | s=zero 118 | for k in range(l,n): s = s+(u[j][k]*u[i][k]) 119 | for k in range(l,n): u[j][k] = u[j][k]+(s*e[k]) 120 | y = abs(q[i])+abs(e[i]) 121 | if y>x: x=y 122 | # accumulation of right hand gtransformations 123 | for i in range(n-1,-1,-1): 124 | if g != zero: 125 | h = g*u[i][i+1] 126 | for j in range(l,n): v[j][i] = u[i][j]/h 127 | for j in range(l,n): 128 | s=zero 129 | for k in range(l,n): s += (u[i][k]*v[k][j]) 130 | for k in range(l,n): v[k][j] += (s*v[k][i]) 131 | for j in range(l,n): 132 | v[i][j] = zero 133 | v[j][i] = zero 134 | v[i][i] = one 135 | g = e[i] 136 | l = i 137 | #accumulation of left hand transformations 138 | for i in range(n-1,-1,-1): 139 | l = i+1 140 | g = q[i] 141 | for j in range(l,n): u[i][j] = zero 142 | if g != zero: 143 | h = u[i][i]*g 144 | for j in range(l,n): 145 | s=zero 146 | for k in range(l,m): s += (u[k][i]*u[k][j]) 147 | f = s/h 148 | for k in range(i,m): u[k][j] += (f*u[k][i]) 149 | for j in range(i,m): u[j][i] = u[j][i]/g 150 | else: 151 | for j in range(i,m): u[j][i] = zero 152 | u[i][i] += one 153 | #diagonalization of the bidiagonal form 154 | eps = eps*x 155 | for k in range(n-1,-1,-1): 156 | for iteration in range(itmax): 157 | # test f splitting 158 | for l in range(k,-1,-1): 159 | goto_test_f_convergence = False 160 | if abs(e[l]) <= eps: 161 | # goto test f convergence 162 | goto_test_f_convergence = True 163 | break # break out of l loop 164 | if abs(q[l-1]) <= eps: 165 | # goto cancellation 166 | break # break out of l loop 167 | if not goto_test_f_convergence: 168 | #cancellation of e[l] if l>0 169 | c = zero 170 | s = one 171 | l1 = l-1 172 | for i in range(l,k+1): 173 | f = s*e[i] 174 | e[i] = c*e[i] 175 | if abs(f) <= eps: 176 | #goto test f convergence 177 | break 178 | g = q[i] 179 | h = pythag(f,g) 180 | q[i] = h 181 | c = g/h 182 | s = -f/h 183 | for j in range(m): 184 | y = u[j][l1] 185 | z = u[j][i] 186 | u[j][l1] = y*c+z*s 187 | u[j][i] = -y*s+z*c 188 | # test f convergence 189 | z = q[k] 190 | if l == k: 191 | # convergence 192 | if z= itmax-1: 199 | if __debug__: print 'Error: no convergence.' 200 | # should this move on the the next k or exit with error?? 201 | #raise ValueError,'SVD Error: No convergence.' # exit the program with error 202 | break # break out of iteration loop and move on to next k 203 | # shift from bottom 2x2 minor 204 | x = q[l] 205 | y = q[k-1] 206 | g = e[k-1] 207 | h = e[k] 208 | f = ((y-z)*(y+z)+(g-h)*(g+h))/(2*one*h*y) 209 | g = pythag(f,one) 210 | if f < 0: 211 | f = ((x-z)*(x+z)+h*(y/(f-g)-h))/x 212 | else: 213 | f = ((x-z)*(x+z)+h*(y/(f+g)-h))/x 214 | # next QR transformation 215 | c = one 216 | s = one 217 | for i in range(l+1,k+1): 218 | g = e[i] 219 | y = q[i] 220 | h = s*g 221 | g = c*g 222 | z = pythag(f,h) 223 | e[i-1] = z 224 | c = f/z 225 | s = h/z 226 | f = x*c+g*s 227 | g = -x*s+g*c 228 | h = y*s 229 | y = y*c 230 | for j in range(n): 231 | x = v[j][i-1] 232 | z = v[j][i] 233 | v[j][i-1] = x*c+z*s 234 | v[j][i] = -x*s+z*c 235 | z = pythag(f,h) 236 | q[i-1] = z 237 | c = f/z 238 | s = h/z 239 | f = c*g+s*y 240 | x = -s*g+c*y 241 | for j in range(m): 242 | y = u[j][i-1] 243 | z = u[j][i] 244 | u[j][i-1] = y*c+z*s 245 | u[j][i] = -y*s+z*c 246 | e[l] = zero 247 | e[k] = f 248 | q[k] = x 249 | # goto test f splitting 250 | 251 | 252 | #vt = transpose(v) 253 | #return (u,q,vt) 254 | return (u,q,v) 255 | 256 | def pythag(a,b): 257 | absa = abs(a) 258 | absb = abs(b) 259 | if absa > absb: return absa*sqrt(one+(absb/absa)**2) 260 | else: 261 | if absb == zero: return zero 262 | else: return absb*sqrt(one+(absa/absb)**2) 263 | 264 | def transpose(a): 265 | '''Compute the transpose of a matrix.''' 266 | m = len(a) 267 | n = len(a[0]) 268 | at = [] 269 | for i in range(n): at.append([zero]*m) 270 | for i in range(m): 271 | for j in range(n): 272 | at[j][i]=a[i][j] 273 | return at 274 | 275 | def matrixmultiply(a,b): 276 | '''Multiply two matrices. 277 | a must be two dimensional 278 | b can be one or two dimensional.''' 279 | 280 | am = len(a) 281 | bm = len(b) 282 | an = len(a[0]) 283 | try: 284 | bn = len(b[0]) 285 | except TypeError: 286 | bn = 1 287 | if an != bm: 288 | raise ValueError, 'matrixmultiply error: array sizes do not match.' 289 | cm = am 290 | cn = bn 291 | if bn == 1: 292 | c = [zero]*cm 293 | else: 294 | c = [] 295 | for k in range(cm): c.append([zero]*cn) 296 | for i in range(cm): 297 | for j in range(cn): 298 | for k in range(an): 299 | if bn == 1: 300 | c[i] += a[i][k]*b[k] 301 | else: 302 | c[i][j] += a[i][k]*b[k][j] 303 | 304 | return c 305 | if __name__ == "__main__": 306 | a = [[22.,10., 2., 3., 7.], 307 | [14., 7.,10., 0., 8.], 308 | [-1.,13.,-1.,-11., 3.], 309 | [-3.,-2.,13., -2., 4.], 310 | [ 9., 8., 1., -2., 4.], 311 | [ 9., 1.,-7., 5.,-1.], 312 | [ 2.,-6., 6., 5., 1.], 313 | [ 4., 5., 0., -2., 2.]] 314 | a=map(lambda row: map( lambda x: Decimal(x), row), a) 315 | u,w,vt = svd(a) 316 | print w 317 | print([35.327043465311384, 1.2982256062667619e-15, 19.999999999999996, 19.595917942265423, 0.0]) 318 | -------------------------------------------------------------------------------- /pt/transaction.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import re, json, copy 3 | from main import * 4 | 5 | ### Hex to bin converter and vice versa for objects 6 | 7 | def json_is_base(obj,base): 8 | alpha = get_code_string(base) 9 | if isinstance(obj,(str,unicode)): 10 | for i in range(len(obj)): 11 | if alpha.find(obj[i]) == -1: return False 12 | return True 13 | elif isinstance(obj,(int,float,long)) or obj is None: return True 14 | elif isinstance(obj,list): 15 | for i in range(len(obj)): 16 | if not json_is_base(obj[i],base): return False 17 | return True 18 | else: 19 | for x in obj: 20 | if not json_is_base(obj[x],base): return False 21 | return True 22 | 23 | def json_changebase(obj,changer): 24 | if isinstance(obj,(str,unicode)): return changer(obj) 25 | elif isinstance(obj,(int,float,long)) or obj is None: return obj 26 | elif isinstance(obj,list): return [json_changebase(x,changer) for x in obj] 27 | return dict((x, json_changebase(obj[x], changer)) for x in obj) 28 | 29 | ### Transaction serialization and deserialization 30 | 31 | def deserialize(tx): 32 | if re.match('^[0-9a-fA-F]*$',tx): 33 | return json_changebase(deserialize(tx.decode('hex')),lambda x:x.encode('hex')) 34 | # http://stackoverflow.com/questions/4851463/python-closure-write-to-variable-in-parent-scope 35 | # Python's scoping rules are demented, requiring me to make pos an object so that it is call-by-reference 36 | pos = [0] 37 | 38 | def read_as_int(bytez): 39 | pos[0] += bytez 40 | return decode(tx[pos[0]-bytez:pos[0]][::-1],256) 41 | 42 | def read_var_int(): 43 | pos[0] += 1 44 | if ord(tx[pos[0]-1]) < 253: return ord(tx[pos[0]-1]) 45 | return read_as_int(pow(2,ord(tx[pos[0]-1]) - 252)) 46 | 47 | def read_bytes(bytez): 48 | pos[0] += bytez 49 | return tx[pos[0]-bytez:pos[0]] 50 | 51 | def read_var_string(): 52 | size = read_var_int() 53 | return read_bytes(size) 54 | 55 | obj = { "ins" : [] , "outs" : [] } 56 | obj["version"] = read_as_int(4) 57 | ins = read_var_int() 58 | for i in range(ins): 59 | obj["ins"].append({ 60 | "outpoint" : { 61 | "hash" : read_bytes(32)[::-1], 62 | "index": read_as_int(4) 63 | }, 64 | "script" : read_var_string(), 65 | "sequence" : read_as_int(4) 66 | }) 67 | outs = read_var_int() 68 | for i in range(outs): 69 | obj["outs"].append({ 70 | "value" : read_as_int(8), 71 | "script": read_var_string() 72 | }) 73 | obj["locktime"] = read_as_int(4) 74 | return obj 75 | 76 | def serialize(txobj): 77 | o = [] 78 | if json_is_base(txobj,16): 79 | return serialize(json_changebase(txobj,lambda x: x.decode('hex'))).encode('hex') 80 | o.append(encode(txobj["version"],256,4)[::-1]) 81 | o.append(num_to_var_int(len(txobj["ins"]))) 82 | for inp in txobj["ins"]: 83 | o.append(inp["outpoint"]["hash"][::-1]) 84 | o.append(encode(inp["outpoint"]["index"],256,4)[::-1]) 85 | o.append(num_to_var_int(len(inp["script"]))+inp["script"]) 86 | o.append(encode(inp["sequence"],256,4)[::-1]) 87 | o.append(num_to_var_int(len(txobj["outs"]))) 88 | for out in txobj["outs"]: 89 | o.append(encode(out["value"],256,8)[::-1]) 90 | o.append(num_to_var_int(len(out["script"]))+out["script"]) 91 | o.append(encode(txobj["locktime"],256,4)[::-1]) 92 | return ''.join(o) 93 | 94 | ### Hashing transactions for signing 95 | 96 | SIGHASH_ALL = 1 97 | SIGHASH_NONE = 2 98 | SIGHASH_SINGLE = 3 99 | SIGHASH_ANYONECANPAY = 80 100 | 101 | def signature_form(tx, i, script, hashcode = SIGHASH_ALL): 102 | i, hashcode = int(i), int(hashcode) 103 | if isinstance(tx,str): 104 | return serialize(signature_form(deserialize(tx),i,script)) 105 | newtx = copy.deepcopy(tx) 106 | for inp in newtx["ins"]: inp["script"] = "" 107 | newtx["ins"][i]["script"] = script 108 | if hashcode == SIGHASH_NONE: 109 | newtx["outs"] = [] 110 | elif hashcode == SIGHASH_SINGLE: 111 | newtx["outs"] = newtx["outs"][:len(newtx["ins"])] 112 | for out in range(len(newtx["ins"]) - 1): 113 | out.value = 2**64 - 1 114 | out.script = "" 115 | elif hashcode == SIGHASH_ANYONECANPAY: 116 | newtx["ins"] = [newtx["ins"][i]] 117 | else: 118 | pass 119 | return newtx 120 | 121 | ### Making the actual signatures 122 | 123 | def der_encode_sig(v,r,s): 124 | b1, b2 = encode(r,16,64), encode(s,16,64) 125 | if r >= 2**255: b1 = '00' + b1 126 | if s >= 2**255: b2 = '00' + b2 127 | left = '02'+encode(len(b1)/2,16,2)+b1 128 | right = '02'+encode(len(b2)/2,16,2)+b2 129 | return '30'+encode(len(left+right)/2,16,2)+left+right 130 | 131 | def der_decode_sig(sig): 132 | leftlen = decode(sig[6:8],16)*2 133 | left = sig[8:8+leftlen] 134 | rightlen = decode(sig[10+leftlen:12+leftlen],16)*2 135 | right = sig[12+leftlen:12+leftlen+rightlen] 136 | return (None,decode(left,16),decode(right,16)) 137 | 138 | def txhash(tx,hashcode=None): 139 | if re.match('^[0-9a-fA-F]*$',tx): 140 | tx = changebase(tx,16,256) 141 | if hashcode: return dbl_sha256(tx + encode(int(hashcode),256,4)[::-1]) 142 | else: return dbl_sha256(tx)[::-1] 143 | 144 | def bin_txhash(tx,hashcode=None): 145 | return txhash(tx,hashcode).decode('hex') 146 | 147 | def ecdsa_tx_sign(tx,priv,hashcode=SIGHASH_ALL): 148 | rawsig = ecdsa_raw_sign(bin_txhash(tx,hashcode),priv) 149 | return der_encode_sig(*rawsig)+encode(hashcode,16,2) 150 | 151 | def ecdsa_tx_verify(tx,sig,pub,hashcode=SIGHASH_ALL): 152 | return ecdsa_raw_verify(bin_txhash(tx,hashcode),der_decode_sig(sig),pub) 153 | 154 | def ecdsa_tx_recover(tx,sig,hashcode=SIGHASH_ALL): 155 | z = bin_txhash(tx,hashcode) 156 | _,r,s = der_decode_sig(sig) 157 | left = ecdsa_raw_recover(z,(0,r,s)) 158 | right = ecdsa_raw_recover(z,(1,r,s)) 159 | return (encode_pubkey(left,'hex'), encode_pubkey(right,'hex')) 160 | 161 | ### Scripts 162 | 163 | def mk_pubkey_script(addr): # Keep the auxiliary functions around for altcoins' sake 164 | return '76a914' + b58check_to_hex(addr) + '88ac' 165 | 166 | def mk_scripthash_script(addr): 167 | return 'a914' + b58check_to_hex(addr) + '87' 168 | 169 | # Address representation to output script 170 | def address_to_script(addr): 171 | if addr[0] == '3': return mk_scripthash_script(addr) 172 | else: return mk_pubkey_script(addr) 173 | 174 | # Output script to address representation 175 | def script_to_address(script,vbyte=0): 176 | if re.match('^[0-9a-fA-F]*$',script): 177 | script = script.decode('hex') 178 | if script[:3] == '\x76\xa9\x14' and script[-2:] == '\x88\xac' and len(script) == 25: 179 | return bin_to_b58check(script[3:-2],vbyte) # pubkey hash addresses 180 | else: 181 | return bin_to_b58check(script[2:-1],5) # BIP0016 scripthash addresses 182 | 183 | def p2sh_scriptaddr(script): 184 | if re.match('^[0-9a-fA-F]*$',script): script = script.decode('hex') 185 | return hex_to_b58check(hash160(script),5) 186 | scriptaddr = p2sh_scriptaddr 187 | 188 | def deserialize_script(script): 189 | if re.match('^[0-9a-fA-F]*$',script): 190 | return json_changebase(deserialize_script(script.decode('hex')),lambda x:x.encode('hex')) 191 | out, pos = [], 0 192 | while pos < len(script): 193 | code = ord(script[pos]) 194 | if code == 0: 195 | out.append(None) 196 | pos += 1 197 | elif code <= 75: 198 | out.append(script[pos+1:pos+1+code]) 199 | pos += 1 + code 200 | elif code <= 78: 201 | szsz = pow(2,code - 76) 202 | sz = decode(script[pos + szsz : pos : -1],256) 203 | out.append(script[pos + 1 + szsz:pos + 1 + szsz + sz]) 204 | pos += 1 + szsz + sz 205 | elif code <= 96: 206 | out.append(code - 80) 207 | pos += 1 208 | else: 209 | out.append(code) 210 | pos += 1 211 | return out 212 | 213 | def serialize_script_unit(unit): 214 | if isinstance(unit,int): 215 | if unit < 16: return chr(unit + 80) 216 | else: return chr(unit) 217 | elif unit is None: 218 | return '\x00' 219 | else: 220 | if len(unit) <= 75: return chr(len(unit))+unit 221 | elif len(unit) < 256: return chr(76)+chr(len(unit))+unit 222 | elif len(unit) < 65536: return chr(77)+encode(len(unit),256,2)[::-1]+unit 223 | else: return chr(78)+encode(len(unit),256,4)[::-1]+unit 224 | 225 | def serialize_script(script): 226 | if json_is_base(script,16): 227 | return serialize_script(json_changebase(script,lambda x:x.decode('hex'))).encode('hex') 228 | return ''.join(map(serialize_script_unit,script)) 229 | 230 | def mk_multisig_script(*args): # [pubs],k,n or pub1,pub2...pub[n],k,n 231 | if len(args) == 3: pubs, k, n = args[0], int(args[1]), int(args[2]) 232 | else: pubs, k, n = list(args[:-2]), int(args[-2]), int(args[-1]) 233 | return serialize_script([k]+pubs+[n,174]) 234 | 235 | ### Signing and verifying 236 | 237 | def verify_tx_input(tx,i,script,sig,pub): 238 | if re.match('^[0-9a-fA-F]*$',tx): tx = tx.decode('hex') 239 | if re.match('^[0-9a-fA-F]*$',script): script = script.decode('hex') 240 | if not re.match('^[0-9a-fA-F]*$',sig): sig = sig.encode('hex') 241 | hashcode = ord(sig[-1]) 242 | modtx = signature_form(tx,int(i),script) 243 | return ecdsa_tx_verify(modtx,sig,pub) 244 | 245 | def sign(tx,i,priv): 246 | i = int(i) 247 | if not re.match('^[0-9a-fA-F]*$',tx): 248 | return sign(tx.encode('hex'),i,priv).decode('hex') 249 | if len(priv) <= 33: priv = priv.encode('hex') 250 | pub = privkey_to_pubkey(priv) 251 | address = pubkey_to_address(pub) 252 | signing_tx = signature_form(tx,i,mk_pubkey_script(address)) 253 | sig = ecdsa_tx_sign(signing_tx,priv) 254 | txobj = deserialize(tx) 255 | txobj["ins"][i]["script"] = serialize_script([sig,pub]) 256 | return serialize(txobj) 257 | 258 | def multisign(tx,i,script,pk): 259 | if re.match('^[0-9a-fA-F]*$',tx): tx = tx.decode('hex') 260 | if re.match('^[0-9a-fA-F]*$',script): script = script.decode('hex') 261 | modtx = signature_form(tx,i,script) 262 | return ecdsa_tx_sign(modtx,pk) 263 | 264 | def apply_multisignatures(*args): # tx,i,script,sigs OR tx,i,script,sig1,sig2...,sig[n] 265 | tx, i, script = args[0], int(args[1]), args[2] 266 | sigs = args[3] if isinstance(args[3],list) else list(args[3:]) 267 | 268 | txobj = deserialize(tx) 269 | txobj["ins"][i]["script"] = serialize_script([None]+sigs+[script]) 270 | return serialize(txobj) 271 | 272 | def mktx(*args): # [in0, in1...],[out0, out1...] or in0, in1 ... out0 out1 ... 273 | if isinstance(args[0],list): ins, outs = args[0], args[1] 274 | else: 275 | def is_inp(arg): return len(arg) > 64 or "output" in arg or "outpoint" in arg 276 | ins, outs = filter(is_inp, args), filter(lambda x: not is_inp(x), args) 277 | 278 | txobj = { "locktime" : 0, "version" : 1,"ins" : [], "outs" : [] } 279 | for i in ins: 280 | if isinstance(i,dict) and "outpoint" in i: 281 | txobj["ins"].append(i) 282 | else: 283 | if isinstance(i,dict) and "output" in i: i = i["output"] 284 | txobj["ins"].append({ 285 | "outpoint" : { "hash": i[:64], "index": int(i[65:]) }, 286 | "script": "", 287 | "sequence": 4294967295 288 | }) 289 | for o in outs: 290 | if isinstance(o,str): o = { 291 | "address": o[:o.find(':')], 292 | "value": int(o[o.find(':')+1:]) 293 | } 294 | txobj["outs"].append({ 295 | "script": address_to_script(o["address"]), 296 | "value": o["value"] 297 | }) 298 | return serialize(txobj) 299 | -------------------------------------------------------------------------------- /demo: -------------------------------------------------------------------------------- 1 | #Here I go through the steps of using the python interpreter to look up a transaction in the blockchain, and to look up how much money the creator of the transaction has 2 | 3 | >>> import tools, truth_cli 4 | >>> truth_cli.main(['blockcount']) 5 | 1940 6 | >>> truth_cli.main(['info', 1001]) 7 | {u'nonce': 9256365515361252087965937608247566201543L, u'target': u'000003b077726d6c91d86637347e47efd4443445d0de96673ce8400000000000', u'time': 1416238195.288335, u'length': 1001, u'version': u'0.0011', u'diffLength': u'e6cb379b5861036b2fa5f0ea4ce4d02ec22d6aefc9004721771178a4a21e50e8f4a3bb2d', u'prevHash': u'4a2fd2067dbc2c152f2295c0332ce755dcf6be455cf281b31089a1a5f2fb492f', u'txs': [{u'count': 785, u'pubkeys': [u'042a6bb7e11ce33608eeaebe27d8b19b3bbc21ab814759119c6f20418b33b30816d48baf42f595e2930b9ae767f43c5dad8c9e176cd0e36a80af7eef777a2f1a14'], u'signatures': [u'first_sig'], u'type': u'mint'}]} 8 | >>> truth_cli.main(['info', 1001])['txs'] 9 | [{u'count': 785, u'pubkeys': [u'042a6bb7e11ce33608eeaebe27d8b19b3bbc21ab814759119c6f20418b33b30816d48baf42f595e2930b9ae767f43c5dad8c9e176cd0e36a80af7eef777a2f1a14'], u'signatures': [u'first_sig'], u'type': u'mint'}] 10 | >>> truth_cli.main(['info', 1001])['txs'][0] 11 | {u'count': 785, u'pubkeys': [u'042a6bb7e11ce33608eeaebe27d8b19b3bbc21ab814759119c6f20418b33b30816d48baf42f595e2930b9ae767f43c5dad8c9e176cd0e36a80af7eef777a2f1a14'], u'signatures': [u'first_sig'], u'type': u'mint'} 12 | >>> tools.addr(truth_cli.main(['info', 1001])['txs'][0]) 13 | '114msX6KqpdZg3hLqf6vMQDBU2NGUbj' 14 | >>> address=tools.addr(truth_cli.main(['info', 1001])['txs'][0]) 15 | >>> truth_cli.main(['info', address]) 16 | {u'count': 1602, u'votes': {}, u'votecoin': {}, u'amount': 160200000, u'shares': {}} 17 | >>> 18 | 19 | 20 | 21 | #this older demo is probably expired. VVV 22 | #comments in this walk-through start with a # in the front of the line. Lines of shell shart with '$$'. Everything else is stuff the program printed out while running. 23 | #this goes through 4 major steps 24 | #1) creating votecoins 25 | #2) asking the votecoin-holders a decision 26 | #3) creating a prediction market based on that decision 27 | #4) buying shares in the prediction market 28 | $$ ./truthd.py commands 29 | ['SVD_consensus', '', 'help', 'create_jury', 'buy_shares', 'DB', 'mine', 'txs', 'vote_on_decision', 'log', 'my_balance', 'collect_winnings', 'blockcount', 'make_PM', 'stop', 'ask_decision', 'difficulty', 'reveal_vote', 'info', 'commands', 'b', 'my_address', 'votecoin_spend', 'balance', 'spend', 'pushtx'] 30 | $$ ./truthd.py help create_jury 31 | If you want to create a jury called "bitcoin", then type: ./truthd.py create_jury bitcoin. 32 | $$ ./truthd.py create_jury jury_1 33 | added tx: {'count': 10, 'pubkeys': ['049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], 'vote_id': u'jury_1', 'type': 'create_jury', 'signatures': ['HNmHEgNlMRA6e++BjQTPNC5kO+DJg/+XhROYVJv/fRfGMn80F2TwMvO6tazaAoObjLiHFyFTqsxhoUmW9O4t6qs=']} 34 | #I now mine a block so that the newest transaction will get included into the blockchain. 35 | $$ ./truthd.py mine 36 | ^Pminer on. (use "./truthd.py mine off" to turn off) 37 | $$ ./truthd.py blockcount 38 | 9 39 | $$ ./truthd.py blockcount 40 | 9 41 | $$ ./truthd.py blockcount 42 | 10 43 | $$ ./truthd.py mine 44 | miner on. (use "./truthd.py mine off" to turn off) 45 | $$ ./truthd.py mine off 46 | miner is now turned off 47 | $$ ./truthd.py mine 48 | miner on. (use "./truthd.py mine off" to turn off) 49 | $$ ./truthd.py mine off 50 | miner is now turned off 51 | $$ ./truthd.py blockcount 52 | 10 53 | $$ ./truthd.py info 10 54 | {u'nonce': 6505867036870044269095830492902328996022L, u'target': u'00000964a0a74f4e778000000000000000000000000000000000000000000000', u'time': 1411087778.245912, u'length': 10, u'version': u'VERSION2', u'diffLength': u'867efae0be8120e9246ed9c7511cbff97b493bea89c23afb507f54e0312f4ee298ac50', u'prevHash': u'15a14f1b094c47ea624db31072f0485327690b90ebc5e4157875ada9f3f88b85', u'txs': [{u'count': 10, u'pubkeys': [u'049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], u'vote_id': u'jury_1', u'type': u'create_jury', u'signatures': [u'HNmHEgNlMRA6e++BjQTPNC5kO+DJg/+XhROYVJv/fRfGMn80F2TwMvO6tazaAoObjLiHFyFTqsxhoUmW9O4t6qs=']}, {u'count': 11, u'pubkeys': [u'049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], u'signatures': [u'first_sig'], u'type': u'mint'}]} 55 | #the new transaction got included! see ^ 56 | $$ ./truthd.py info jury_1 57 | {u'decisions': [], u'members': [u'112VBGZuUG229onyd2hqgiyZK2jfZTR']} 58 | $$ ./truthd.py my_address 59 | 112VBGZuUG229onyd2hqgiyZK2jfZTR 60 | $$ ./truthd.py help ask_decision 61 | If you wanted to ask the jury , the question "what will the weather be tomorrow", with the unique identifier "weather_question_203", you would type: ./truthd.py ask_decision weather_question_203 what will the weather be tomorrow 62 | $$ ./truthd.py ask_decision jury_1 question_1 word word 63 | added tx: {'count': 46, 'vote_id': u'jury_1', 'decision_id': u'question_1', 'signatures': ['G83m6QPeDzA1DJFk+yH3CiFjcWIp1Yl3wHPDMVzpeTU7LHnc+Rw97vyBsZzSBDh5wpnUWQoSu6yZ1E3oSegVfoA='], 'pubkeys': ['049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], 'txt': u'question_1 word word', 'type': 'propose_decision'} 64 | $$ ./truthd.py txs 65 | [{'count': 46, 'vote_id': u'jury_1', 'decision_id': u'question_1', 'signatures': ['G83m6QPeDzA1DJFk+yH3CiFjcWIp1Yl3wHPDMVzpeTU7LHnc+Rw97vyBsZzSBDh5wpnUWQoSu6yZ1E3oSegVfoA='], 'pubkeys': ['049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], 'txt': u'question_1 word word', 'type': 'propose_decision'}] 66 | $$ ./truthd.py blockcount 67 | 44 68 | $$ ./truthd.py mine 69 | miner on. (use "./truthd.py mine off" to turn off) 70 | $$ ./truthd.py blockcount 71 | 44 72 | $$ ./truthd.py blockcount 73 | 44 74 | $$ ./truthd.py blockcount 75 | 45 76 | $$ ./truthd.py mine off 77 | miner is now turned off 78 | $$ ./truthd.py info 45 79 | {u'nonce': 2181772776417058596572428078960633165869L, u'target': u'000296683a9b333f000000000000000000000000000000000000000000000000', u'time': 1411088163.908362, u'length': 45, u'version': u'VERSION2', u'diffLength': u'b20b38faf49675901ea550d1d7231fd0bee72e8abadd36aebacd6e8d55c81cfb9c3b63', u'prevHash': u'79df3d185a0ba6275c74920c7a823b95467d2a92abcf5d1b3ad47da2900ccbc6', u'txs': [{u'count': 46, u'signatures': [u'G83m6QPeDzA1DJFk+yH3CiFjcWIp1Yl3wHPDMVzpeTU7LHnc+Rw97vyBsZzSBDh5wpnUWQoSu6yZ1E3oSegVfoA='], u'decision_id': u'question_1', u'vote_id': u'jury_1', u'pubkeys': [u'049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], u'txt': u'question_1 word word', u'type': u'propose_decision'}, {u'count': 47, u'pubkeys': [u'049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], u'signatures': [u'first_sig'], u'type': u'mint'}]} 80 | $$ ./truthd.py info jury_1 81 | {u'decisions': [u'question_1'], u'members': [u'112VBGZuUG229onyd2hqgiyZK2jfZTR']} 82 | $$ ./truthd.py commands 83 | ['SVD_consensus', '', 'help', 'create_jury', 'buy_shares', 'DB', 'mine', 'txs', 'vote_on_decision', 'log', 'my_balance', 'collect_winnings', 'blockcount', 'make_PM', 'stop', 'ask_decision', 'difficulty', 'reveal_vote', 'info', 'commands', 'b', 'my_address', 'votecoin_spend', 'balance', 'spend', 'pushtx'] 84 | $$ ./truthd.py make_pm 85 | make_pm is not a command. use "./truthd.py commands" to get the list of truthshell commands. use "./truthd.py help help" to learn about the help tool. 86 | $$ ./truthd.py make_PM 87 | What is the address or pubkey of the owner of the PM?112VBGZuUG229onyd2hqgiyZK2jfZTR 88 | What is the unique name for this new prediction market? 89 | pm_1 90 | how big should B be? Initial investment is B*ln(n) where n is the number of states100 91 | how many decisions is this prediction market to be based upon?1 92 | What is the unique name of the 0 decision?question_1 93 | how many states can this PM result in?2 94 | what is the text title of the 0 state?1 95 | how does the 0 state depend upon the outcome of the decisions? For example: if there are 2 decisions, and this market only comes true when the first is "yes" and the second is "no", then you would put: "1 0" here.1 96 | what is the text title of the 1 state?0 97 | added tx: {'count': 50, u'B': 100, u'type': u'prediction_market', u'states': [u'1', u'0'], u'PM_id': u'pm_1', 'signatures': ['G7qXOYKBZieR7FnHe1EbsmICtY1sUxP+2Qh3gUINEwzTm38EKXMzBmt0JDfJ1kAH/bH9+6oQYoNGpytYN1Fcoec='], u'fees': 0, u'owner': u'112VBGZuUG229onyd2hqgiyZK2jfZTR', 'pubkeys': ['049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], u'decisions': [u'question_1'], u'states_combinatory': [[1]]} 98 | $$ ./truthd.py txs 99 | [{'count': 50, u'B': 100, u'type': u'prediction_market', u'states': [u'1', u'0'], u'PM_id': u'pm_1', 'signatures': ['G7qXOYKBZieR7FnHe1EbsmICtY1sUxP+2Qh3gUINEwzTm38EKXMzBmt0JDfJ1kAH/bH9+6oQYoNGpytYN1Fcoec='], u'fees': 0, u'owner': u'112VBGZuUG229onyd2hqgiyZK2jfZTR', 'pubkeys': ['049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], u'decisions': [u'question_1'], u'states_combinatory': [[1]]}] 100 | $$ ./truthd.py mine 101 | miner on. (use "./truthd.py mine off" to turn off) 102 | $$ ./truthd.py blockcount 103 | 47 104 | $$ ./truthd.py blockcount 105 | 48 106 | $$ ./truthd.py mine off 107 | miner is now turned off 108 | $$ ./truthd.py info 48 109 | {u'nonce': 5000772876419197464637182333766161377917L, u'target': u'000291aca98a220da00000000000000000000000000000000000000000000000', u'time': 1411088268.060414, u'length': 48, u'version': u'VERSION2', u'diffLength': u'b335741e5f396ec374e201b435c2f8ed156eb81ce3a6aa9f1d3fd21deed7a2f95ca227', u'prevHash': u'8d4fc8b48e7293555b14150950bec99091328bbfb18774ec615e90f4c9304dee', u'txs': [{u'count': 50, u'B': 100, u'decisions': [u'question_1'], u'states': [u'1', u'0'], u'PM_id': u'pm_1', u'signatures': [u'G7qXOYKBZieR7FnHe1EbsmICtY1sUxP+2Qh3gUINEwzTm38EKXMzBmt0JDfJ1kAH/bH9+6oQYoNGpytYN1Fcoec='], u'fees': 0, u'owner': u'112VBGZuUG229onyd2hqgiyZK2jfZTR', u'pubkeys': [u'049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], u'type': u'prediction_market', u'states_combinatory': [[1]]}, {u'count': 51, u'pubkeys': [u'049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], u'signatures': [u'first_sig'], u'type': u'mint'}]} 110 | $$ ./truthd.py info pm_1 111 | {u'B': 100, u'shares_purchased': [0, 0], u'author': u'112VBGZuUG229onyd2hqgiyZK2jfZTR', u'states': [u'1', u'0'], u'fees': 0, u'decisions': [u'question_1'], u'states_combinatory': [[1]]} 112 | $$ ./truthd.py info buy_shares 113 | {u'count': 0, u'amount': 0, u'votecoin': {}, u'votes': {}, u'shares': {}} 114 | $$ ./truthd.py buy_shares 115 | What is the unique name for this prediction market?pm_1 116 | how many states does this pm have?2 117 | how many shares do you want to buy of state 0? To sell states, use negative numbers.100 118 | how many shares do you want to buy of state 1? To sell states, use negative numbers.0 119 | added tx: {'count': 54, u'buy': [100, 0], u'PM_id': u'pm_1', 'signatures': ['G5Zr94azcn40WCiouc6HYbJEZhMF3R4UcQqwySsWDa5SN8DaEv3BYFwLF+ql0RAsn0orJEw73HaKpxhL0G3XWeQ='], 'pubkeys': ['049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], u'type': u'buy_shares'} 120 | $$ ./truthd.py info pm_1 121 | {u'B': 100, u'shares_purchased': [0, 0], u'author': u'112VBGZuUG229onyd2hqgiyZK2jfZTR', u'states': [u'1', u'0'], u'fees': 0, u'decisions': [u'question_1'], u'states_combinatory': [[1]]} 122 | $$ ./truthd.py txs 123 | [{'count': 54, u'buy': [100, 0], u'PM_id': u'pm_1', 'signatures': ['G5Zr94azcn40WCiouc6HYbJEZhMF3R4UcQqwySsWDa5SN8DaEv3BYFwLF+ql0RAsn0orJEw73HaKpxhL0G3XWeQ='], 'pubkeys': ['049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], u'type': u'buy_shares'}] 124 | $$ ./truthd.py blockcount 125 | 50 126 | $$ ./truthd.py mine 127 | miner on. (use "./truthd.py mine off" to turn off) 128 | $$ ./truthd.py blockcount 129 | 50 130 | $$ ./truthd.py blockcount 131 | 51 132 | $$ ./truthd.py mine off 133 | miner is now turned off 134 | $$ ./truthd.py info 51 135 | {u'nonce': 9349828590341819470435521826158002461714L, u'target': u'00028db282551196c00000000000000000000000000000000000000000000000', u'time': 1411088349.161174, u'length': 51, u'version': u'VERSION2', u'diffLength': u'b4619a15a981a1c08843ce122c136813fe3293cab271c0372c5c71f0608a482eb440e6', u'prevHash': u'750680513b952c9d2b1ddea445d5143334e660f5bc04872171c7cc2332ed3f4c', u'txs': [{u'count': 54, u'buy': [100, 0], u'PM_id': u'pm_1', u'signatures': [u'G5Zr94azcn40WCiouc6HYbJEZhMF3R4UcQqwySsWDa5SN8DaEv3BYFwLF+ql0RAsn0orJEw73HaKpxhL0G3XWeQ='], u'pubkeys': [u'049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], u'type': u'buy_shares'}, {u'count': 55, u'pubkeys': [u'049541c1e6270840ee05cbe2d32cbb796e846c842e4a9b78132b7691eb659cf2f723adf5343292d493871f0b81b95baa8728a0676d8e28dbcc7f7cc4d58e7a5549'], u'signatures': [u'first_sig'], u'type': u'mint'}]} 136 | $$ ./truthd.py info pm_1 137 | {u'B': 100, u'shares_purchased': [100, 0], u'author': u'112VBGZuUG229onyd2hqgiyZK2jfZTR', u'states': [u'1', u'0'], u'fees': 0, u'decisions': [u'question_1'], u'states_combinatory': [[1]]} 138 | $$ ./truthd.py info my_address 139 | {u'count': 57, u'amount': 5189869, u'votecoin': {u'jury_1': 1296}, u'votes': {}, u'shares': {u'pm_1': [100, 0]}} 140 | -------------------------------------------------------------------------------- /truthcoin_api.py: -------------------------------------------------------------------------------- 1 | """This is the internal API for truthshell. These are the words that are used to interact with truthcoin. 2 | """ 3 | import copy, tools, blockchain, custom, random, transactions, sys, txs_tools, time, networking, txs_truthcoin, target 4 | def easy_add_transaction(tx_orig, DB, privkey='default'): 5 | tx = copy.deepcopy(tx_orig) 6 | if privkey in ['default', 'Default']: 7 | if tools.db_existence('privkey'): 8 | privkey=tools.db_get('privkey') 9 | else: 10 | return('no private key is known, so the tx cannot be signed. Here is the tx: \n'+str(tools.package(tx_orig).encode('base64').replace('\n', ''))) 11 | pubkey=tools.privtopub(privkey) 12 | address=tools.make_address([pubkey], 1) 13 | if 'count' not in tx: 14 | try: 15 | tx['count'] = tools.count(address, {}) 16 | except: 17 | tx['count'] = 1 18 | if 'pubkeys' not in tx: 19 | tx['pubkeys']=[pubkey] 20 | if 'signatures' not in tx: 21 | tx['signatures'] = [tools.sign(tools.det_hash(tx), privkey)] 22 | return(blockchain.add_tx(tx, DB)) 23 | def help_(DB, args): 24 | tell_about_command={ 25 | 'help':'type "./truth_cli.py help " to learn about . type "./truth_cli.py commands" to get a list of all truthshell commands', 26 | 'commands':'returns a list of the truthshell commands', 27 | 'start':'type "./truth_cli.py start" to start truthcoin node', 28 | 'new_address':'type "./truth_cli.py new_address " to make a new privkey, pubkey, and address using the brain wallet=. If you want to use this address, you need to copy/paste the pubkey into the file custom.py', 29 | 'create_jury':'If you want to create a jury called "bitcoin", then type: ./truth_cli.py create_jury bitcoin.', 30 | 'DB_print':'prints the database that is shared between threads', 31 | 'info':'prints the contents of an entree in the hashtable. If you want to know what the first block was: info 0, if you want to know about a particular address : info , if you want to know about yourself: info my_address', 32 | 'my_address':'tells you your own address', 33 | 'spend':'spends money, in satoshis, to an address . Example: spend 1000 11j9csj9802hc982c2h09ds', 34 | 'votecoin_spend':'spend votecoins from jury , to address . Example: votecoin_spend 1000 ', 35 | 'ask_decision': 'If you wanted to ask the jury , the question "what will the weather be tomorrow", with the unique identifier "weather_question_203", you would type: ./truth_cli.py ask_decision maturation_date weather_question_203 what will the weather be tomorrow', 36 | 'vote_on_decision':'If you want to vote in jury , and you want to vote on decision , and you want to vote "yes", for example: vote_on_decision yes', 37 | 'reveal_vote':'If you want to reveal your vote for the decision with the unique identifier which was asked ofjury , then: reveal_vote ', 38 | 'SVD_consensus':'If you want to resolve decisions asked of jury , then: SVD_consensus ', 39 | 'make_PM':'example: ./truth_cli.py make_PM', 40 | 'create_pm':'example: ./truth_cli.py create_pm PM_id B decisions states states_combinatory /n example2: ./truth_cli.py create_pm pm_id_0 1000 decision_0,decision_1 case_1,case_2,case_3,case_4 0,0.1,0.0,1', 41 | 'trade_shares':'example: ./truth_cli.py trade_shares PM_id -200,1000 #this would sell 200 of the first state in PM_id, and buy 1000 of the second', 42 | 'price':'example: ./truth_cli.py price PM_id -200,1000 #this would find the price of selling 200 of the first state in PM_id, and buying 1000 of the second', 43 | 'collect_winnings':'To transform your winning shares from prediction market into truthcoin: collect_winnings ', 44 | 'blockcount':'returns the number of blocks since the genesis block', 45 | 'txs':'returns a list of the zeroth confirmation transactions that are expected to be included in the next block', 46 | 'difficulty':'returns current difficulty', 47 | 'my_balance':'the amount of truthcoin that you own', 48 | 'balance':'if you want to know the balance for address , type: ./truth_cli.py balance ', 49 | 'log':'records the following words into the file "log.py"', 50 | 'stop':'This is the correct way to stop truthcoin. If you turn off in any other way, then you are likely to corrupt your database, and you have to redownload all the blocks again.', 51 | 'mine':'turn the miner on/off. Example to turn on: "./truth_cli.py mine on", example to turn off: "./truth_cli.py mine off"', 52 | 'DB':'returns a database of information that is shared between threads', 53 | 'pushtx':'publishes this transaction to the blockchain, will automatically sign the transaction if necessary: ./truth_cli.py pushtx tx privkey', 54 | 'blocks':'./truth_cli.py blocks 100 200', 55 | 'peers':'tells you your list of peers' 56 | } 57 | if len(args)==0: 58 | return("needs 2 words. example: 'help help'") 59 | try: 60 | return tell_about_command[args[0]] 61 | except: 62 | return(str(args[0])+' is not yet documented') 63 | def csv2vec(a): return map(int, a.split(',')) 64 | def price(DB, args):#args=[pm_id, [1,100,0,-20]] 65 | tx={'PM_id':args[0], 'buy':csv2vec(args[1])} 66 | return txs_tools.cost_to_buy_shares(tx)*1.01 67 | def trade_shares(DB, args): #args = [ PM_id, buy ] 68 | privkey = tools.db_get('privkey') 69 | pubkey = tools.privtopub(privkey) 70 | address = tools.make_address([pubkey], 1) 71 | tx = {'type': 'buy_shares', 72 | 'PM_id': args[0], 73 | 'buy': csv2vec(args[1]), 74 | 'pubkeys': [ pubkey ], 75 | 'count': tools.count(address, {})} 76 | cost = txs_tools.cost_to_buy_shares(tx) 77 | tx['price_limit'] = int(cost * 1.01) + 1 78 | tx = tools.unpackage(tools.package(tx)) 79 | tx = tools.POW(tx) 80 | tx['signatures'] = [tools.sign(tools.det_hash(tx), privkey)] 81 | return easy_add_transaction(tx, DB, privkey) 82 | 83 | def create_pm(DB, args): 84 | tx = {'PM_id': args[0], 85 | 'type': 'prediction_market', 86 | 'fees': 0, 87 | 'B': int(args[1]), 88 | 'decisions': args[2].split(','),# comma seperated list 89 | 'states': args[3].split(','),# comma seperated list 90 | 'states_combinatory': map(lambda x: map(int, x.split(',')), args[4].split('.'))} 91 | return easy_add_transaction(tx, DB, tools.db_get('privkey')) 92 | def create_jury(DB, args): 93 | if len(args)<1: 94 | return('not enough inputs') 95 | return easy_add_transaction({'type': 'create_jury', 'vote_id': args[0]}, DB) 96 | def peers(DB, args): 97 | return(tools.db_get('peers')) 98 | def DB_print(DB, args): 99 | return(DB) 100 | def info(DB, args): 101 | if len(args)<1: 102 | return ('not enough inputs') 103 | if args[0]=='my_address': 104 | address=tools.db_get('address') 105 | else: 106 | address=args[0] 107 | return(tools.db_get(address, DB)) 108 | def my_address(DB, args): 109 | return(tools.db_get('address')) 110 | def spend(DB, args): 111 | if len(args)<2: 112 | return('not enough inputs') 113 | return easy_add_transaction({'type': 'spend', 'amount': int(args[0]), 'to':args[1]}, DB) 114 | def votecoin_spend(DB, args): 115 | if len(args)<3: 116 | return('not enough inputs') 117 | tx = {'type': 'spend', 'amount':int(args[0]), 'to': args[2], 'vote_id':args[1]} 118 | return easy_add_transaction(tx, DB) 119 | def accumulate_words(l, out=''): 120 | if len(l)>0: return accumulate_words(l[1:], out+' '+l[0]) 121 | return out 122 | def ask_decision(DB, args): 123 | if len(args)<4: 124 | return('not enough inputs') 125 | try: 126 | args[1]=int(args[1]) 127 | except: 128 | return('maturation must be an int. it is a blocklength. '+str(args[1])) 129 | tx={'type':'propose_decision', 'vote_id':args[0], 'decision_id':args[2], 'maturation':args[1], 'txt':accumulate_words(args[3:])[1:]} 130 | tools.log('tx: '+str(tx)) 131 | return easy_add_transaction(tx, DB) 132 | def vote_on_decision(DB, args): 133 | if len(args)<3: 134 | return('not enough inputs') 135 | decision_id=args[1] 136 | answer=args[2] 137 | acc=tools.db_get(tools.db_get('address'), DB) 138 | value=[answer, str(random.random())+str(random.random())] 139 | answer_hash=tools.det_hash(value) 140 | m=tools.db_get('memoized_votes') 141 | m[answer_hash]=value 142 | tools.db_put('memoized_votes', m) 143 | #DB['memoized_votes'][answer_hash]=value 144 | old_vote='unsure' 145 | if decision_id in acc['votes']: #this is always False... 146 | old_vote=acc['votes'][decision_id] 147 | tx={'type':'jury_vote', 'vote_id':args[0], 'decision_id':decision_id, 'old_vote':old_vote, 'new_vote':answer_hash} 148 | return easy_add_transaction(tx, DB) 149 | def reveal_vote(DB, args): 150 | if len(args)<2: 151 | return('not enough inputs') 152 | acc=tools.db_get(tools.db_get('address'), DB) 153 | decision_id=args[1] 154 | if decision_id in acc['votes']: 155 | answer_hash=acc['votes'][decision_id] 156 | m=tools.db_get('memoized_votes') 157 | if answer_hash not in m: 158 | return('reveal vote error') 159 | a=m[answer_hash] 160 | tx={'type':'reveal_jury_vote', 'vote_id':args[0], 'decision_id':decision_id, 'old_vote':answer_hash, 'new_vote':a[0], 'secret':a[1]} 161 | return easy_add_transaction(tx, DB) 162 | else: 163 | return('you do not have any encrypted vote to decrypt') 164 | def SVD_consensus(DB, args): 165 | if len(args)<1: 166 | return('unique id for that branch?') 167 | vote_id=args[0] 168 | jury=tools.db_get(vote_id, DB) 169 | k=txs_tools.decisions_keepers(vote_id, jury, DB) 170 | if k=='error': 171 | return('that jury does not exist yet') 172 | tx={'type':'SVD_consensus', 'vote_id':vote_id, 'decisions':k} 173 | return(easy_add_transaction(tx, DB)) 174 | def pushtx(DB, args): 175 | try: 176 | a=args[0].decode('base64') 177 | except: 178 | a=args[0] 179 | tx=tools.unpackage(a) 180 | if len(args)==1: 181 | return easy_add_transaction(tx, DB) 182 | if args[1]=='default': 183 | return easy_add_transaction(tx, DB, tools.db_get('privkey')) 184 | privkey=tools.det_hash(args[1]) 185 | return easy_add_transaction(tx, DB, privkey) 186 | def collect_winnings(DB, args): 187 | if len(args)<1: 188 | return ('not enough arguments') 189 | tools.log('collect_winnings 1') 190 | add=tools.db_get('address') 191 | acc=tools.db_get(add, DB) 192 | tx={'type':'collect_winnings', 'PM_id':args[0], 'address':add} 193 | tx['shares']=acc['shares'][tx['PM_id']] 194 | tools.log('collect_winnings 2') 195 | return easy_add_transaction(tx, DB) 196 | def blockcount(DB, args): return(tools.db_get('length')) 197 | def txs(DB, args): return(tools.db_get('txs')) 198 | def difficulty(DB, args): return(target.target(DB)) 199 | def my_balance(DB, args, address='default'): 200 | if address=='default': 201 | address=tools.db_get('address') 202 | return(tools.db_get(address, DB)['amount']-txs_tools.cost_0(tools.db_get('txs'), address)['truthcoin_cost']) 203 | def balance(DB, args): 204 | if len(args)<1: 205 | return('what address do you want the balance for?') 206 | return(my_balance(DB, args, args[0])) 207 | def log(DB, args): tools.log(accumulate_words(args)[1:]) 208 | def stop_(DB, args): 209 | tools.db_put('stop', True) 210 | return('turning off all threads') 211 | def commands(DB, args): return sorted(Do.keys()+['start', 'new_address']) 212 | def mine(DB, args): 213 | if len(args)>0: 214 | if args[0]=='off': 215 | tools.db_put('mine', False) 216 | return('miner is now turned off') 217 | elif args[0]=='on': 218 | if tools.db_existence('privkey'): 219 | tools.db_put('mine', True) 220 | return ('miner on. (use "./truth_cli.py mine off" to turn off)') 221 | else: 222 | return('there is no private key with which to sign blocks. If you want to mine, you need to uncomment the "brain_wallet" line in custom.py') 223 | else: 224 | m=tools.db_get('mine') 225 | if m: 226 | m='on' 227 | else: 228 | m='off' 229 | return('miner is currently: ' +m) 230 | def pass_(DB, args): return ' ' 231 | def error_(DB, args): return error 232 | def blocks(DB, args): 233 | args=map(int, args) 234 | out=[] 235 | length=tools.db_get('length') 236 | r=args[0] 237 | while args[0]length: return out 239 | out.append(tools.db_get(args[0])) 240 | args[0]+=1 241 | return out 242 | Do={'SVD_consensus':SVD_consensus, 'reveal_vote':reveal_vote, 'vote_on_decision':vote_on_decision, 'ask_decision':ask_decision, 'create_jury':create_jury, 'spend':spend, 'votecoin_spend':votecoin_spend, 'collect_winnings':collect_winnings, 'help':help_, 'blockcount':blockcount, 'txs':txs, 'balance':balance, 'my_balance':my_balance, 'b':my_balance, 'difficulty':difficulty, 'info':info, '':pass_, 'DB':DB_print, 'my_address':my_address, 'log':log, 'stop':stop_, 'commands':commands, 'pushtx':pushtx, 'create_pm':create_pm, 'mine':mine, 'peers':peers, 'trade_shares':trade_shares, 'blocks':blocks, 'price':price} 243 | def main(DB, heart_queue): 244 | def responder(dic): 245 | command=dic['command'] 246 | if command[0] in Do: 247 | args=command[1:] 248 | try: 249 | out=Do[command[0]](DB, args) 250 | except Exception as exc: 251 | tools.log(exc) 252 | out='truthcoin api main failure : ' +str(sys.exc_info()) 253 | else: 254 | out=str(command[0]) + ' is not a command. use "./truth_cli.py commands" to get the list of truthshell commands. use "./truth_cli.py help help" to learn about the help tool.' 255 | return out 256 | try: 257 | return networking.serve_forever(responder, custom.api_port, heart_queue) 258 | except Exception as exc: 259 | tools.log('api error') 260 | tools.log(exc) 261 | -------------------------------------------------------------------------------- /pt/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import hashlib, re, sys, os, base64, time, random, hmac 3 | 4 | ### Elliptic curve parameters 5 | 6 | P = 2**256-2**32-2**9-2**8-2**7-2**6-2**4-1 7 | N = 115792089237316195423570985008687907852837564279074904382605163141518161494337 8 | A = 0 9 | Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240 10 | Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424 11 | G = (Gx,Gy) 12 | 13 | ### Extended Euclidean Algorithm 14 | 15 | def inv(a,n): 16 | lm, hm = 1,0 17 | low, high = a%n,n 18 | while low > 1: 19 | r = high/low 20 | nm, new = hm-lm*r, high-low*r 21 | lm, low, hm, high = nm, new, lm, low 22 | return lm % n 23 | 24 | ### Base switching 25 | 26 | def get_code_string(base): 27 | if base == 2: return '01' 28 | elif base == 10: return '0123456789' 29 | elif base == 16: return '0123456789abcdef' 30 | elif base == 32: return 'abcdefghijklmnopqrstuvwxyz2345657' 31 | elif base == 58: return '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' 32 | elif base == 256: return ''.join([chr(x) for x in range(256)]) 33 | else: raise ValueError("Invalid base!") 34 | 35 | def lpad(msg,symbol,length): 36 | if len(msg) >= length: return msg 37 | return symbol * (length - len(msg)) + msg 38 | 39 | def encode(val,base,minlen=0): 40 | base, minlen = int(base), int(minlen) 41 | code_string = get_code_string(base) 42 | result = "" 43 | while val > 0: 44 | result = code_string[val % base] + result 45 | val /= base 46 | return lpad(result,code_string[0],minlen) 47 | 48 | def decode(string,base): 49 | base = int(base) 50 | code_string = get_code_string(base) 51 | result = 0 52 | if base == 16: string = string.lower() 53 | while len(string) > 0: 54 | result *= base 55 | result += code_string.find(string[0]) 56 | string = string[1:] 57 | return result 58 | 59 | def changebase(string,frm,to,minlen=0): 60 | if frm == to: return lpad(string,minlen) 61 | return encode(decode(string,frm),to,minlen) 62 | 63 | ### Elliptic Curve functions 64 | 65 | def isinf(p): return p[0] == 0 and p[1] == 0 66 | 67 | def base10_add(a,b): 68 | if isinf(a): return b[0],b[1] 69 | if isinf(b): return a[0],a[1] 70 | if a[0] == b[0]: 71 | if a[1] == b[1]: return base10_double((a[0],a[1])) 72 | else: return (0,0) 73 | m = ((b[1]-a[1]) * inv(b[0]-a[0],P)) % P 74 | x = (m*m-a[0]-b[0]) % P 75 | y = (m*(a[0]-x)-a[1]) % P 76 | return (x,y) 77 | 78 | def base10_double(a): 79 | if isinf(a): return (0,0) 80 | m = ((3*a[0]*a[0]+A)*inv(2*a[1],P)) % P 81 | x = (m*m-2*a[0]) % P 82 | y = (m*(a[0]-x)-a[1]) % P 83 | return (x,y) 84 | 85 | def base10_multiply(a,n): 86 | if isinf(a) or n == 0: return (0,0) 87 | if n == 1: return a 88 | if n < 0 or n >= N: return base10_multiply(a,n%N) 89 | if (n%2) == 0: return base10_double(base10_multiply(a,n/2)) 90 | if (n%2) == 1: return base10_add(base10_double(base10_multiply(a,n/2)),a) 91 | 92 | # Functions for handling pubkey and privkey formats 93 | 94 | def get_pubkey_format(pub): 95 | if isinstance(pub,(tuple,list)): return 'decimal' 96 | elif len(pub) == 65 and pub[0] == '\x04': return 'bin' 97 | elif len(pub) == 130 and pub[0:2] == '04': return 'hex' 98 | elif len(pub) == 33 and pub[0] in ['\x02','\x03']: return 'bin_compressed' 99 | elif len(pub) == 66 and pub[0:2] in ['02','03']: return 'hex_compressed' 100 | elif len(pub) == 64: return 'bin_electrum' 101 | elif len(pub) == 128: return 'hex_electrum' 102 | else: raise Exception("Pubkey not in recognized format") 103 | 104 | def encode_pubkey(pub,formt): 105 | if not isinstance(pub,(tuple,list)): 106 | pub = decode_pubkey(pub) 107 | if formt == 'decimal': return pub 108 | elif formt == 'bin': return '\x04' + encode(pub[0],256,32) + encode(pub[1],256,32) 109 | elif formt == 'bin_compressed': return chr(2+(pub[1]%2)) + encode(pub[0],256,32) 110 | elif formt == 'hex': return '04' + encode(pub[0],16,64) + encode(pub[1],16,64) 111 | elif formt == 'hex_compressed': return '0'+str(2+(pub[1]%2)) + encode(pub[0],16,64) 112 | elif formt == 'bin_electrum': return encode(pub[0],256,32) + encode(pub[1],256,32) 113 | elif formt == 'hex_electrum': return encode(pub[0],16,64) + encode(pub[1],16,64) 114 | else: raise Exception("Invalid format!") 115 | 116 | def decode_pubkey(pub,formt=None): 117 | if not formt: formt = get_pubkey_format(pub) 118 | if formt == 'decimal': return pub 119 | elif formt == 'bin': return (decode(pub[1:33],256),decode(pub[33:65],256)) 120 | elif formt == 'bin_compressed': 121 | x = decode(pub[1:33],256) 122 | beta = pow(x*x*x+7,(P+1)/4,P) 123 | y = (P-beta) if ((beta + ord(pub[0])) % 2) else beta 124 | return (x,y) 125 | elif formt == 'hex': return (decode(pub[2:66],16),decode(pub[66:130],16)) 126 | elif formt == 'hex_compressed': 127 | return decode_pubkey(pub.decode('hex'),'bin_compressed') 128 | elif formt == 'bin_electrum': 129 | return (decode(pub[:32],256),decode(pub[32:64],256)) 130 | elif formt == 'hex_electrum': 131 | return (decode(pub[:64],16),decode(pub[64:128],16)) 132 | else: raise Exception("Invalid format!") 133 | 134 | def get_privkey_format(priv): 135 | if isinstance(priv,(int,long)): return 'decimal' 136 | elif len(priv) == 32: return 'bin' 137 | elif len(priv) == 33: return 'bin_compressed' 138 | elif len(priv) == 64: return 'hex' 139 | elif len(priv) == 66: return 'hex_compressed' 140 | else: 141 | bin_p = b58check_to_bin(priv) 142 | if len(bin_p) == 32: return 'wif' 143 | elif len(bin_p) == 33: return 'wif_compressed' 144 | else: raise Exception("WIF does not represent privkey") 145 | 146 | def encode_privkey(priv,formt,vbyte=0): 147 | if not isinstance(priv,(int,long)): 148 | return encode_privkey(decode_privkey(priv),formt,vbyte) 149 | if formt == 'decimal': return priv 150 | elif formt == 'bin': return encode(priv,256,32) 151 | elif formt == 'bin_compressed': return encode(priv,256,32)+'\x01' 152 | elif formt == 'hex': return encode(priv,16,64) 153 | elif formt == 'hex_compressed': return encode(priv,16,64)+'01' 154 | elif formt == 'wif': 155 | return bin_to_b58check(encode(priv,256,32),128+int(vbyte)) 156 | elif formt == 'wif_compressed': 157 | return bin_to_b58check(encode(priv,256,32)+'\x01',128+int(vbyte)) 158 | else: raise Exception("Invalid format!") 159 | 160 | def decode_privkey(priv,formt=None): 161 | if not formt: formt = get_privkey_format(priv) 162 | if formt == 'decimal': return priv 163 | elif formt == 'bin': return decode(priv,256) 164 | elif formt == 'bin_compressed': return decode(priv[:32],256) 165 | elif formt == 'hex': return decode(priv,16) 166 | elif formt == 'hex_compressed': return decode(priv[:64],16) 167 | else: 168 | bin_p = b58check_to_bin(priv) 169 | if len(bin_p) == 32: return decode(bin_p,256) 170 | elif len(bin_p) == 33: return decode(bin_p[:32],256) 171 | else: raise Exception("WIF does not represent privkey") 172 | 173 | def add_pubkeys(p1,p2): 174 | f1,f2 = get_pubkey_format(p1), get_pubkey_format(p2) 175 | return encode_pubkey(base10_add(decode_pubkey(p1,f1),decode_pubkey(p2,f2)),f1) 176 | 177 | def add_privkeys(p1,p2): 178 | f1,f2 = get_privkey_format(p1), get_privkey_format(p2) 179 | return encode_privkey((decode_privkey(p1,f1) + decode_privkey(p2,f2)) % N,f1) 180 | 181 | def multiply(pubkey,privkey): 182 | f1,f2 = get_pubkey_format(pubkey), get_privkey_format(privkey) 183 | pubkey, privkey = decode_pubkey(pubkey,f1), decode_privkey(privkey,f2) 184 | # http://safecurves.cr.yp.to/twist.html 185 | if not isinf(pubkey) and (pubkey[0]**3+7-pubkey[1]*pubkey[1]) % P != 0: 186 | raise Exception("Point not on curve") 187 | return encode_pubkey(base10_multiply(pubkey,privkey),f1) 188 | 189 | def divide(pubkey,privkey): 190 | factor = inv(decode_privkey(privkey),N) 191 | return multiply(pubkey,factor) 192 | 193 | def compress(pubkey): 194 | f = get_pubkey_format(pubkey) 195 | if 'compressed' in f: return pubkey 196 | elif f == 'bin': return encode_pubkey(decode_pubkey(pubkey,f),'bin_compressed') 197 | elif f == 'hex' or f == 'decimal': 198 | return encode_pubkey(decode_pubkey(pubkey,f),'hex_compressed') 199 | 200 | def decompress(pubkey): 201 | f = get_pubkey_format(pubkey) 202 | if 'compressed' not in f: return pubkey 203 | elif f == 'bin_compressed': return encode_pubkey(decode_pubkey(pubkey,f),'bin') 204 | elif f == 'hex_compressed' or f == 'decimal': 205 | return encode_pubkey(decode_pubkey(pubkey,f),'hex') 206 | 207 | def privkey_to_pubkey(privkey): 208 | f = get_privkey_format(privkey) 209 | privkey = decode_privkey(privkey,f) 210 | if privkey == 0 or privkey >= N: 211 | raise Exception("Invalid privkey") 212 | if f in ['bin','bin_compressed','hex','hex_compressed','decimal']: 213 | return encode_pubkey(base10_multiply(G,privkey),f) 214 | else: 215 | return encode_pubkey(base10_multiply(G,privkey),f.replace('wif','hex')) 216 | 217 | privtopub = privkey_to_pubkey 218 | 219 | def privkey_to_address(priv,magicbyte=0): 220 | return pubkey_to_address(privkey_to_pubkey(priv),magicbyte) 221 | privtoaddr = privkey_to_address 222 | 223 | def neg_pubkey(pubkey): 224 | f = get_pubkey_format(pubkey) 225 | pubkey = decode_pubkey(pubkey,f) 226 | return encode_pubkey((pubkey[0],(P-pubkey[1]) % P),f) 227 | 228 | def neg_privkey(privkey): 229 | f = get_privkey_format(privkey) 230 | privkey = decode_privkey(privkey,f) 231 | return encode_privkey((N - privkey) % N,f) 232 | 233 | def subtract_pubkeys(p1, p2): 234 | f1,f2 = get_pubkey_format(p1), get_pubkey_format(p2) 235 | k2 = decode_pubkey(p2,f2) 236 | return encode_pubkey(base10_add(decode_pubkey(p1,f1),(k2[0],(P - k2[1]) % P)),f1) 237 | 238 | def subtract_privkeys(p1, p2): 239 | f1,f2 = get_privkey_format(p1), get_privkey_format(p2) 240 | k2 = decode_privkey(p2,f2) 241 | return encode_privkey((decode_privkey(p1,f1) - k2) % N,f1) 242 | 243 | ### Hashes 244 | 245 | def bin_hash160(string): 246 | intermed = hashlib.sha256(string).digest() 247 | return hashlib.new('ripemd160',intermed).digest() 248 | def hash160(string): 249 | return bin_hash160(string).encode('hex') 250 | 251 | def bin_sha256(string): 252 | return hashlib.sha256(string).digest() 253 | def sha256(string): 254 | return bin_sha256(string).encode('hex') 255 | 256 | def bin_dbl_sha256(string): 257 | return hashlib.sha256(hashlib.sha256(string).digest()).digest() 258 | def dbl_sha256(string): 259 | return bin_dbl_sha256(string).encode('hex') 260 | 261 | def bin_slowsha(string): 262 | orig_input = string 263 | for i in range(100000): 264 | string = hashlib.sha256(string + orig_input).digest() 265 | return string 266 | def slowsha(string): 267 | return bin_slowsha(string).encode('hex') 268 | 269 | def hash_to_int(x): 270 | if len(x) in [40,64]: return decode(x,16) 271 | else: return decode(x,256) 272 | 273 | def num_to_var_int(x): 274 | x = int(x) 275 | if x < 253: return chr(x) 276 | elif x < 65536: return chr(253) + encode(x,256,2)[::-1] 277 | elif x < 4294967296: return chr(254) + encode(x,256,4)[::-1] 278 | else: return chr(255) + encode(x,256,8)[::-1] 279 | 280 | # WTF, Electrum? 281 | def electrum_sig_hash(message): 282 | padded = "\x18Bitcoin Signed Message:\n" + num_to_var_int( len(message) ) + message 283 | return bin_dbl_sha256(padded) 284 | 285 | def random_key(): 286 | # Gotta be secure after that java.SecureRandom fiasco... 287 | entropy = os.urandom(32)+str(random.randrange(2**256))+str(int(time.time())**7) 288 | return sha256(entropy) 289 | 290 | def random_electrum_seed(): 291 | entropy = os.urandom(32)+str(random.randrange(2**256))+str(int(time.time())**7) 292 | return sha256(entropy)[:32] 293 | 294 | ### Encodings 295 | 296 | def bin_to_b58check(inp,magicbyte=0): 297 | inp_fmtd = chr(int(magicbyte)) + inp 298 | leadingzbytes = len(re.match('^\x00*',inp_fmtd).group(0)) 299 | checksum = bin_dbl_sha256(inp_fmtd)[:4] 300 | return '1' * leadingzbytes + changebase(inp_fmtd+checksum,256,58) 301 | 302 | def b58check_to_bin(inp): 303 | leadingzbytes = len(re.match('^1*',inp).group(0)) 304 | data = '\x00' * leadingzbytes + changebase(inp,58,256) 305 | assert bin_dbl_sha256(data[:-4])[:4] == data[-4:] 306 | return data[1:-4] 307 | 308 | def get_version_byte(inp): 309 | leadingzbytes = len(re.match('^1*',inp).group(0)) 310 | data = '\x00' * leadingzbytes + changebase(inp,58,256) 311 | assert bin_dbl_sha256(data[:-4])[:4] == data[-4:] 312 | return ord(data[0]) 313 | 314 | def hex_to_b58check(inp,magicbyte=0): 315 | return bin_to_b58check(inp.decode('hex'),magicbyte) 316 | 317 | def b58check_to_hex(inp): return b58check_to_bin(inp).encode('hex') 318 | 319 | def pubkey_to_address(pubkey,magicbyte=0): 320 | if isinstance(pubkey,(list,tuple)): 321 | pubkey = encode_pubkey(pubkey,'bin') 322 | if len(pubkey) in [66,130]: 323 | return bin_to_b58check(bin_hash160(pubkey.decode('hex')),magicbyte) 324 | return bin_to_b58check(bin_hash160(pubkey),magicbyte) 325 | 326 | pubtoaddr = pubkey_to_address 327 | 328 | ### EDCSA 329 | 330 | def encode_sig(v,r,s): 331 | vb, rb, sb = chr(v), encode(r,256), encode(s,256) 332 | return base64.b64encode(vb+'\x00'*(32-len(rb))+rb+'\x00'*(32-len(sb))+sb) 333 | 334 | def decode_sig(sig): 335 | bytez = base64.b64decode(sig) 336 | return ord(bytez[0]), decode(bytez[1:33],256), decode(bytez[33:],256) 337 | 338 | # https://tools.ietf.org/html/rfc6979#section-3.2 339 | def deterministic_generate_k(msghash,priv): 340 | v = '\x01' * 32 341 | k = '\x00' * 32 342 | priv = encode_privkey(priv,'bin') 343 | msghash = encode(hash_to_int(msghash),256,32) 344 | k = hmac.new(k, v+'\x00'+priv+msghash, hashlib.sha256).digest() 345 | v = hmac.new(k, v, hashlib.sha256).digest() 346 | k = hmac.new(k, v+'\x01'+priv+msghash, hashlib.sha256).digest() 347 | v = hmac.new(k, v, hashlib.sha256).digest() 348 | return decode(hmac.new(k, v, hashlib.sha256).digest(),256) 349 | 350 | def ecdsa_raw_sign(msghash,priv): 351 | 352 | z = hash_to_int(msghash) 353 | k = deterministic_generate_k(msghash,priv) 354 | 355 | r,y = base10_multiply(G,k) 356 | s = inv(k,N) * (z + r*decode_privkey(priv)) % N 357 | 358 | return 27+(y%2),r,s 359 | 360 | def ecdsa_sign(msg,priv): 361 | return encode_sig(*ecdsa_raw_sign(electrum_sig_hash(msg),priv)) 362 | 363 | def ecdsa_raw_verify(msghash,vrs,pub): 364 | v,r,s = vrs 365 | 366 | w = inv(s,N) 367 | z = hash_to_int(msghash) 368 | 369 | u1, u2 = z*w % N, r*w % N 370 | x,y = base10_add(base10_multiply(G,u1), base10_multiply(decode_pubkey(pub),u2)) 371 | 372 | return r == x 373 | 374 | def ecdsa_verify(msg,sig,pub): 375 | return ecdsa_raw_verify(electrum_sig_hash(msg),decode_sig(sig),pub) 376 | 377 | def ecdsa_raw_recover(msghash,vrs): 378 | v,r,s = vrs 379 | 380 | x = r 381 | beta = pow(x*x*x+7,(P+1)/4,P) 382 | y = beta if v%2 ^ beta%2 else (P - beta) 383 | z = hash_to_int(msghash) 384 | 385 | Qr = base10_add(neg_pubkey(base10_multiply(G,z)),base10_multiply((x,y),s)) 386 | Q = base10_multiply(Qr,inv(r,N)) 387 | 388 | if ecdsa_raw_verify(msghash,vrs,Q): return Q 389 | return False 390 | 391 | def ecdsa_recover(msg,sig): 392 | return encode_pubkey(ecdsa_raw_recover(electrum_sig_hash(msg),decode_sig(sig)),'hex') 393 | -------------------------------------------------------------------------------- /txs_truthcoin.py: -------------------------------------------------------------------------------- 1 | """These are transactions that make up a truthcoin system. Transaction types that are used in blockchains more generally are left in transactions.py 2 | """ 3 | import txs_tools 4 | import ConsensusMechanism 5 | import pprint 6 | import custom 7 | import tools 8 | import blockchain 9 | import transactions 10 | import copy 11 | from cdecimal import Decimal 12 | addr=tools.addr 13 | E_check=tools.E_check 14 | is_number=tools.is_number 15 | def create_jury_check(tx, txs, out, DB): 16 | address=addr(tx) 17 | mine=filter(lambda t: t['type']=='create_jury', txs) 18 | mine=filter(lambda t: addr(t)==address, mine) 19 | if len(mine)>0: 20 | out[0]+='you cannot create 2 juries on the same block from the same address' 21 | return False 22 | if not transactions.signature_check(tx): 23 | out[0]+='signature check' 24 | return False 25 | if not E_check(tx, 'vote_id', [str, unicode]): 26 | out[0]+='vote id error' 27 | return False 28 | if tools.is_number(tx['vote_id']): 29 | out[0]+='vote_id can not be a number' 30 | return False 31 | if len(tx['vote_id'])>1000: return False 32 | if tools.db_existence(tx['vote_id'], DB): 33 | out[0]+='this vote_id is already being used' 34 | return False 35 | if not tools.db_existence(address, DB): 36 | out[0]+='this address is not used by anyone' 37 | return False 38 | acc=tools.db_get(address, DB) 39 | if not txs_tools.fee_check(tx, txs, DB): return False 40 | return True 41 | def propose_decision_check(tx, txs, out, DB): 42 | if 'maturation' in tx: 43 | n=tx['maturation'] 44 | if type(n)!=int or n<0: return False 45 | if not transactions.signature_check(tx): 46 | out[0]+='signature check' 47 | return False 48 | if not E_check(tx, 'vote_id', [str, unicode]): 49 | out[0]+='no vote id' 50 | return False 51 | if not E_check(tx, 'decision_id', [str, unicode]): 52 | out[0]+='no decision id' 53 | return False 54 | if is_number(tx['vote_id']) or is_number(tx['decision_id']): 55 | out[0]+='that can not be a number' 56 | return False 57 | if len(tx['decision_id'])>custom.max_key_length: 58 | out[0]+='decision id too long' 59 | return False 60 | if not tools.db_existence(tx['vote_id'], DB): 61 | out[0]+='that vote id has not been created yet' 62 | return False 63 | if tools.db_existence(tx['decision_id'], DB): 64 | out[0]+='that decision id has already been used' 65 | return False 66 | for t in txs: 67 | if 'decision_id' in t: 68 | if t['decision_id']==tx['decision_id']: 69 | out[0]+='already have a zeroth confirmation tx of this' 70 | return False 71 | if not txs_tools.fee_check(tx, txs, DB): 72 | out[0]+='you do not have enough money' 73 | return False 74 | if not E_check(tx, 'txt', [str, unicode]): 75 | out[0]+='what is the txt of this decision?' 76 | return False 77 | if len(tx['txt'])>6**5: 78 | out[0]+='the txt of this decision is too long' 79 | return False 80 | return True 81 | def jury_vote_check(tx, txs, out, DB): 82 | #make sure that this person is one of the 1000 richest people for this rep type. 83 | if not transactions.signature_check(tx): 84 | out[0]+='signature check' 85 | return False 86 | if not E_check(tx, 'decision_id', [str, unicode]): return False 87 | if not E_check(tx, 'vote_id', [str, unicode]): return False 88 | if is_number(tx['vote_id']) or is_number(tx['decision_id']): 89 | out[0]+='that can not be a number' 90 | return False 91 | if not E_check(tx, 'old_vote', [str, unicode]): return False 92 | if not E_check(tx, 'new_vote', [str, unicode]): return False 93 | decision=tools.db_get(tx['decision_id'], DB) 94 | if 'state' not in decision: 95 | out[0]+='that is not a decision_id' 96 | out[0]+='decision: ' +str(decision) 97 | out[0]+='tx: ' +str(tx) 98 | return False 99 | if decision['state']!='proposed': 100 | out[0]+='this decision has already been decided' 101 | return False 102 | if not tools.db_existence(tx['decision_id'], DB): 103 | out[0]+='decision error' 104 | return False 105 | if tools.reveal_time_p(DB): 106 | out[0]+='reveal time check' 107 | return False 108 | if len(tx['new_vote'])<4: 109 | out[0]+='secret too short error' 110 | return False 111 | if not txs_tools.fee_check(tx, txs, DB): return False 112 | return True 113 | def slasher_jury_vote_check(tx, txs, out, DB): 114 | address=addr(tx) 115 | if tools.reveal_time_p(DB): 116 | out[0]+='reveal time check slasher' 117 | return False 118 | if not transactions.signature_check(tx): 119 | out[0]+='signature check' 120 | return False 121 | if not E_check(tx, 'amount', int): 122 | out[0]+='how many votecoins are we confiscating?' 123 | return False 124 | if not E_check(tx, 'reveal', dict): 125 | out[0]+='no reveal' 126 | return False 127 | if not reveal_jury_vote_check(tx['reveal'], txs, DB): 128 | out[0]+='this is an invalid reveal tx' 129 | return False 130 | victim=tools.db_get(addr(tx['reveal']), DB) 131 | decision=tx['reveal']['decision_id'] 132 | decision=tools.db_get(decision, DB) 133 | if victim['votecoin'][tx['reveal']['vote_id']]!=tx['amount']: 134 | out[0]+='that is not how many votecoins they have' 135 | return False 136 | 137 | return True 138 | def reveal_jury_vote_check(tx, txs, out, DB): 139 | if not transactions.signature_check(tx): 140 | out[0]+='signature check' 141 | return False 142 | address=addr(tx) 143 | acc=tools.db_get(address, DB) 144 | if not E_check(tx, 'decision_id', [str, unicode]): 145 | out[0]+='decision id error' 146 | return False 147 | if is_number(tx['decision_id']): 148 | out[0]+='that can not be a number' 149 | return False 150 | decision=tools.db_get(tx['decision_id'], DB) 151 | if decision['state']!='proposed': 152 | out[0]+='this decision has already been decided' 153 | return False 154 | if not E_check(tx, 'old_vote', [str, unicode]): return False 155 | if not E_check(tx, 'secret', [str, unicode]): return False 156 | if not E_check(tx, 'new_vote', [str, unicode]): 157 | out[0]+='new vote error' 158 | return False 159 | if tx['decision_id'] not in acc['votes']: 160 | out[0]+='decision id not in acc[votes] error' 161 | return False 162 | answer_hash=acc['votes'][tx['decision_id']] 163 | if not answer_hash==tools.det_hash([tx['new_vote'], tx['secret']]): 164 | out[0]+='hash does not match' 165 | return False 166 | if not E_check(tx, 'old_vote', [str, unicode]): 167 | out[0]+='old vote does not exist error' 168 | return False 169 | if not txs_tools.fee_check(tx, txs, DB): return False 170 | return True 171 | def part_cert(matrix, weights): 172 | tools.log('before COnsensus: '+str(matrix)) 173 | tools.log('weights: ' +str(weights)) 174 | result=ConsensusMechanism.main(matrix, weights) 175 | tools.log('after COnsensus') 176 | tools.log('result: ' +str(result)) 177 | participation=result['participation'] 178 | certainty=result['certainty'] 179 | out=[] 180 | tools.log('participation: ' +str(participation)) 181 | tools.log('certainty: ' +str(certainty)) 182 | for i in range(len(certainty)): 183 | out.append(float(participation)*float(certainty[i])) 184 | return out 185 | def SVD_consensus_check(tx, txs, out, DB): 186 | if not E_check(tx, 'vote_id', [str, unicode]): return False 187 | if not E_check(tx, 'decisions', [list]): return False 188 | if not tools.reveal_time_p(DB, custom.SVD_length): 189 | out[0]+='this is not the correct time to do SVD' 190 | return False 191 | if is_number(tx['vote_id']): 192 | out[0]+='that can not be a number' 193 | return False 194 | jury=tools.db_get(tx['vote_id'], DB) 195 | if len(tx['decisions'])<5: 196 | out[0]+='need at least 5 decisions to compute SVD' 197 | return False 198 | if not E_check(jury, 'members', [list]): 199 | out[0]+='that jury has not been created yet' 200 | return False 201 | if len(jury['members'])<3: 202 | out[0]+='need at least 3 voters in order to compute SVD' 203 | return False 204 | try: 205 | matrix=txs_tools.decision_matrix(jury, tx['decisions'], DB) 206 | except: 207 | tools.log(sys.exc_info()) 208 | tools.log('matrix failure') 209 | return False 210 | w=txs_tools.weights(tx['vote_id'], DB, jury) 211 | k=txs_tools.decisions_keepers(tx['vote_id'], jury, DB) 212 | for decision in tx['decisions']: 213 | if not decision in k: 214 | out[0]+='one of the decisions has insufficient participation*certainty or has not matured yet: ' +str(decision)+' '+str(tools.db_get(decision)) 215 | return False 216 | if not txs_tools.fee_check(tx, txs, DB): 217 | out[0]+='you do not have enough money' 218 | return False 219 | return True 220 | def prediction_market_check(tx, txs, out, DB): 221 | if not transactions.signature_check(tx): 222 | out[0]+='signature check' 223 | return False 224 | address=addr(tx) 225 | #if type(tx['fee'])!=int or tx['fee']<0 or tx['fee']>100000: 226 | # out[0]+='fee is not in range 0%-100%' 227 | # return False 228 | for l in ['states', 'states_combinatory', 'decisions']: 229 | if not E_check(tx, l, list): 230 | out[0]+=str(l)+ ' error' 231 | return False 232 | for dec in tx['decisions']: 233 | l=map(lambda x: x['decision_id'], filter(lambda x: x['type']=='propose_decision', txs)) 234 | if not tools.db_existence(dec, DB) and dec not in l: 235 | out[0]+='decision is not in the database: ' +str(dec) 236 | out[0]+=' zeroth confimation txs: ' +str(l) 237 | out[0]+=' txs: '+str(txs) 238 | return False 239 | if is_number(dec): 240 | out[0]+='decision_id can not be a number' 241 | return False 242 | if is_number(tx['PM_id']): 243 | out[0]+='PM_id can not be a number' 244 | return False 245 | if len(tx['states'])>200: 246 | out[0]+='too many states' 247 | return False 248 | if not E_check(tx, 'B', int): 249 | out[0]+='B error' 250 | return False 251 | for comb in tx['states_combinatory']: 252 | if len(comb)!=len(tx['decisions']): 253 | out[0]+=str(comb)+' comb error' 254 | return False 255 | for l in [tx['states_combinatory'], tx['states'], tx['decisions']]: 256 | for comb in l: 257 | copies=len(filter(lambda comb2: comb==comb2, l)) 258 | if copies!=1: 259 | out[0]+=str(comb)+' not mutually exclusive' 260 | return False 261 | if len(tx['states'])!=len(tx['states_combinatory'])+1: 262 | out[0]+='wrong number of possible states?' 263 | return False 264 | if not E_check(tx, 'PM_id', [str, unicode]): 265 | out[0]+='PM_id error' 266 | return False 267 | if len(tx['PM_id'])>1000: 268 | out[0]+='PM_id too long' 269 | return False 270 | if tools.db_existence(tx['PM_id'], DB): 271 | #out[0]+='PM: ' +str(tools.db_get(tx['PM_id'], DB)) 272 | out[0]+='this PM_id is already being used' 273 | return False 274 | for t in txs: 275 | if t['type']=='prediction_market': 276 | if t['PM_id']==tx['PM_id']: 277 | out[0]+='Someone used that PM in this block already' 278 | return False 279 | acc=tools.db_get(address, DB) 280 | if not txs_tools.fee_check(tx, txs, DB): 281 | out[0]+='you do not have enough money' 282 | return False 283 | return True 284 | def buy_shares_check(tx, txs, out, DB): 285 | #make sure that we can only buy the shares of undecided markets. 286 | if not transactions.signature_check(tx): 287 | out[0]+='signature check' 288 | return False 289 | a=copy.deepcopy(tx) 290 | a.pop('signatures') 291 | half_way=tools.make_half_way(a) 292 | if tools.det_hash(half_way)>custom.buy_shares_target: 293 | out[0]+='insufficient POW' 294 | return False 295 | if not E_check(tx, 'buy', list): 296 | out[0]+='buy error' 297 | return False 298 | if not E_check(tx, 'PM_id', [str, unicode]): 299 | out[0]+='pm id error' 300 | return False 301 | pm=tools.db_get(tx['PM_id'], DB) 302 | if 'decisions' not in pm: 303 | out[0]+='that is not a prediction market yet' 304 | return False 305 | if len(tx['buy'])!=len(pm['shares_purchased']): 306 | out[0]+='buy length error' 307 | return False 308 | stop=True 309 | for i in tx['buy']: 310 | if i!=0: 311 | stop=False 312 | if stop: 313 | out[0]+='you need to buy a non-zero amount of at least one share' 314 | return False 315 | if 'price_limit' in tx: 316 | price = txs_tools.cost_to_buy_shares(tx) 317 | if price>tx['price_limit']: 318 | out[0]+='that is outside the price limit for that tx '+str(price) + ' is bigger than ' +str(tx) 319 | return False 320 | for purchase in tx['buy']: 321 | if type(purchase)!=int: 322 | return False 323 | for i in range(len(tx['buy'])): 324 | if tx['buy'][i]+pm['shares_purchased'][i]<0: 325 | out[0]+='PM cannot have negative shares' 326 | return False 327 | if not txs_tools.fee_check(tx, txs, DB): 328 | out[0]+='fee check error' 329 | return False 330 | for dec in pm['decisions']: 331 | decision = tools.db_get(dec, DB) 332 | bad=True 333 | if decision['state'] not in ['yes', 'no']: 334 | bad=False 335 | if bad: 336 | out[0]+='this PM is already expired. you cannot buy shares.' 337 | return False 338 | return True 339 | def collect_winnings_check(tx, txs, out, DB): 340 | if not transactions.signature_check(tx): 341 | out[0]+='signature check' 342 | return False 343 | if not E_check(tx, 'address', [str, unicode]): 344 | out[0]+='no address error' 345 | return False 346 | acc=tools.db_get(tx['address'], DB) 347 | if not E_check(tx, 'PM_id', [str, unicode]): 348 | out[0]+='no PM_id error' 349 | return False 350 | if tx['PM_id'] not in acc['shares']: 351 | out[0]+='you do not own any shares for this PM' 352 | return False 353 | if not tx['shares']==acc['shares'][tx['PM_id']]: 354 | out[0]+='that is not how many shares you have error' 355 | return False 356 | pm=tools.db_get(tx['PM_id'], DB) 357 | if 'decisions' not in pm: 358 | out[0]+='that is not a prediction market yet' 359 | return False 360 | for dec in pm['decisions']: 361 | decision = tools.db_get(dec, DB) 362 | if decision['state'] not in ['yes', 'no']: 363 | out[0]+='we have not yet reached consensus on the outcome of this market error' 364 | return False 365 | return True 366 | adjust_int=txs_tools.adjust_int 367 | adjust_dict=txs_tools.adjust_dict 368 | adjust_list=txs_tools.adjust_list 369 | adjust_string=txs_tools.adjust_string 370 | symmetric_put=txs_tools.symmetric_put 371 | def create_jury(tx, DB, add_block): 372 | #specify when voting rounds end. 373 | address=addr(tx) 374 | adjust_int(['count'], address, 1, DB, add_block) 375 | adjust_int(['amount'], address, -custom.create_jury_fee, DB, add_block) 376 | adjust_dict(['votecoin'], address, False, {tx['vote_id']: custom.total_votecoins}, DB, add_block) 377 | jury={'decisions':[], 'members':[address]} 378 | symmetric_put(tx['vote_id'], jury, DB, add_block) 379 | def propose_decision(tx, DB, add_block): 380 | address=addr(tx) 381 | adjust_int(['count'], address, 1, DB, add_block) 382 | adjust_list(['decisions'], tx['vote_id'], False, tx['decision_id'], DB, add_block) 383 | adjust_int(['amount'], address, -custom.propose_decision_fee, DB, add_block) 384 | decision={'state':'proposed',#proposed, yes, no 385 | 'maturation':tx['maturation'], 386 | 'txt':tx['txt']} 387 | symmetric_put(tx['decision_id'], decision, DB, add_block) 388 | def jury_vote(tx, DB, add_block):#while votes exist, should not be able to send votecoins 389 | address=addr(tx) 390 | acc=tools.db_get(address, DB) 391 | if tx['decision_id'] not in acc['votes']: 392 | acc['votes'][tx['decision_id']]='unsure' 393 | tools.db_put(address, acc, DB) 394 | adjust_int(['count'], address, 1, DB, add_block) 395 | adjust_int(['amount'], address, -custom.jury_vote_fee, DB, add_block) 396 | adjust_string(['votes', tx['decision_id']], address, tx['old_vote'], tx['new_vote'], DB, add_block) 397 | def slasher_jury_vote(tx, DB, add_block): 398 | address=addr(tx) 399 | adjust_int(['count'], address, 1, DB, add_block) 400 | victim=addr(tx['reveal']) 401 | decision=tx['reveal']['decision_id'] 402 | decision=tools.db_get(decision, DB) 403 | txs_tools.initialize_to_zero_votecoin(tx['vote_id'], address, DB, add_block) 404 | txs_tools.initialize_to_zero_votecoin(tx['vote_id'], victim, DB, add_block) 405 | adjust_int(['votecoin',decision['vote_id']], victim, -tx['amount'], DB, add_block) 406 | adjust_int(['votecoin',decision['vote_id']], address, (4*tx['amount'])/5, DB, add_block) 407 | tx_tools.memory_leak_votecoin(tx['vote_id'], address, DB, add_block) 408 | tx_tools.memory_leak_votecoin(tx['vote_id'], victim, DB, add_block) 409 | #remove votecoins from victim, give 4/5ths to address. 410 | def reveal_jury_vote(tx, DB, add_block): 411 | address=addr(tx) 412 | adjust_int(['count'], address, 1, DB, add_block) 413 | adjust_string(['votes', tx['decision_id']], address, tx['old_vote'], tx['new_vote'], DB, add_block) 414 | def SVD_consensus(tx, DB, add_block): 415 | address=addr(tx) 416 | adjust_int(['count'], address, 1, DB, add_block) 417 | jury=tools.db_get(tx['vote_id'], DB) 418 | matrix=txs_tools.decision_matrix(jury, tx['decisions'], DB) 419 | w=txs_tools.weights(tx['vote_id'], DB, jury) 420 | result=ConsensusMechanism.main(matrix, w) 421 | #create fee. If there are more decisions, then the fee is lower. 422 | #tools.log('matrix: ' +str(matrix)) 423 | #tools.log(pprint.pformat(result)) 424 | for i in range(len(tx['decisions'])): 425 | adjust_list(['decisions'], tx['vote_id'], True, tx['decisions'][i], DB, add_block) 426 | new='yes' 427 | if float(result['outcome'][i])<0.5: 428 | new='no' 429 | adjust_string(['state'], tx['decisions'][i], 'proposed', new, DB, add_block) 430 | #if a prediction market expires, then we should give 1/2 it's fees to votecoin holders, and 1/2 it's fees to the author 431 | #the prediction market may have unused seed capital. This seed capital should go to the author 432 | def prediction_market(tx, DB, add_block):#also used to increase liquidity of existing market, eventually 433 | address=addr(tx) 434 | adjust_int(['count'], address, 1, DB, add_block) 435 | adjust_int(['amount'], address, int(-tx['B']*(Decimal(len(tx['states']))).ln()), DB, add_block) 436 | pm={} 437 | for i in ['fees', 'B', 'states', 'states_combinatory', 'decisions']: 438 | pm[i]=tx[i] 439 | pm['author']=address 440 | pm['shares_purchased']=[] 441 | #if 'fee' in tx: 442 | # pm['fee']=tx['fee'] 443 | #else: 444 | # pm['fee']=1000# 1% fee 445 | for i in range(len(tx['states'])): pm['shares_purchased'].append(0) 446 | symmetric_put(tx['PM_id'], pm, DB, add_block) 447 | #tools.log('created PM: '+str(tx['PM_id'])) 448 | #has a 'buy_shares' inside of it, eventually 449 | def buy_shares(tx, DB, add_block): 450 | address = addr(tx) 451 | acc = tools.db_get(address, DB) 452 | adjust_int(['count'], address, 1, DB, add_block) 453 | cost=txs_tools.cost_to_buy_shares(tx) 454 | fee=int(abs(cost*0.01)) 455 | adjust_int(['fees'], tx['PM_id'], fee, DB, add_block) 456 | adjust_int(['amount'], address, -fee, DB, add_block) 457 | adjust_int(['amount'], address, -cost, DB, add_block) 458 | all_zeros=[] 459 | for i in tx['buy']: all_zeros.append(0) 460 | dic={tx['PM_id']:all_zeros} 461 | if tx['PM_id'] not in acc['shares']:#initialize to zero 462 | adjust_dict(['shares'], address, False, dic, DB, add_block) 463 | for i in range(len(tx['buy'])): 464 | adjust_int(['shares_purchased', i], tx['PM_id'], tx['buy'][i], DB, add_block) 465 | adjust_int(['shares', tx['PM_id'], i], address, tx['buy'][i], DB, add_block) 466 | acc = tools.db_get(address, DB) 467 | if acc['shares'][tx['PM_id']]==all_zeros: 468 | adjust_dict(['shares'], address, True, dic, DB, add_block) 469 | def collect_winnings(tx, DB, add_block): 470 | address = addr(tx) 471 | acc = tools.db_get(address, DB) 472 | pm = tools.db_get(tx['PM_id'], DB) 473 | outcome_combination=[] 474 | for dec in pm['decisions']: 475 | decision = tools.db_get(dec, DB) 476 | do={'yes':(lambda: outcome_combination.append(1)), 477 | 'no':(lambda: outcome_combination.append(0))} 478 | do[decision['state']]() 479 | decs=len(pm['states_combinatory']) 480 | else_=True 481 | for i in range(decs): 482 | if pm['states_combinatory'][i]==outcome_combination: 483 | adjust_int(['amount'], address, tx['shares'][i], DB, add_block) 484 | else_=False 485 | if else_: 486 | adjust_int(['amount'], address, tx['shares'][-1], DB, add_block) 487 | adjust_dict(['shares'], address, True, {tx['PM_id']:tx['shares']}, DB, add_block) 488 | --------------------------------------------------------------------------------