def sometx(): secret = "A" * 32 public = rscoin.Key(secret, public=False).id() directory = [(public, "127.0.0.1", 8080)] factory = RSCFactory(secret, directory, None) # Build one transaction k1 = rscoin.Key(urandom(32), public=False) k2 = rscoin.Key(urandom(32), public=False) tx1 = rscoin.Tx([], [rscoin.OutputTx(k1.id(), 100)]) tx2 = rscoin.Tx([], [rscoin.OutputTx(k2.id(), 150)]) tx3 = rscoin.Tx([rscoin.InputTx(tx1.id(), 0), rscoin.InputTx(tx2.id(), 0)], [rscoin.OutputTx(k1.id(), 250)]) for kv, vv in tx1.get_utxo_out_entries() + tx2.get_utxo_out_entries(): factory.db[kv] = vv # Run the protocol instance = factory.buildProtocol(None) tr = StringTransport() instance.makeConnection(tr) return (factory, instance, tr), (k1, k2, tx1, tx2, tx3)
def msg_mass(): secret = "A" * 32 public = rscoin.Key(secret, public=False).id() directory = [(public, "127.0.0.1", 8080)] factory = RSCFactory(secret, directory, None) # Run the protocol instance = factory.buildProtocol(None) tr = StringTransport() instance.makeConnection(tr) sometx = (factory, instance, tr) # Make special keys for making coins secret_special = "KEYSPECIAL" public_special = rscoin.Key(secret_special, public=False).pub.export() # Define a number of keys all_keys = [] secret = "KEYX" public = rscoin.Key(secret, public=False).id() directory = [(public, "127.0.0.1", 8080)] # Make a mass of transactions k1 = rscoin.Key(urandom(32), public=False) k2 = rscoin.Key(urandom(32), public=False) all_tx = [] for _ in range(1000): tx1 = rscoin.Tx([], [rscoin.OutputTx(k1.id(), 100)]) tx2 = rscoin.Tx([], [rscoin.OutputTx(k2.id(), 150)]) tx3 = rscoin.Tx( [rscoin.InputTx(tx1.id(), 0), rscoin.InputTx(tx2.id(), 0)], [rscoin.OutputTx(k1.id(), 250)]) all_tx += [([tx1, tx2], tx3)] for intx, _ in all_tx: for tx in intx: for kv, vv in tx.get_utxo_out_entries(): factory.db[kv] = vv mesages_q = [] for ([tx1, tx2], tx3) in all_tx: H, data, core = package_query(tx3, [tx1, tx2], [k1, k2]) mesages_q += [(tx3, data, core)] return (sometx, mesages_q)
def test_TxQuery(sometx): (factory, instance, tr), (k1, k2, tx1, tx2, tx3) = sometx tx4 = rscoin.Tx([rscoin.InputTx(tx1.id(), 0)], [rscoin.OutputTx(k1.id(), 100)]) for kv, vv in tx1.get_utxo_out_entries() + tx2.get_utxo_out_entries(): factory.db[kv] = vv # Check the list is up to date for ik in tx3.get_utxo_in_keys(): assert ik in factory.db data = (tx3, [tx1.serialize(), tx2.serialize()], [k1.export()[0], k2.export()[0]], [k1.sign(tx3.id()), k2.sign(tx3.id())]) # Put the transaction through print "Number of Authorities: %s" % len(factory.get_authorities(tx1.id())) assert factory.key.id() in factory.get_authorities(tx1.id()) assert factory.process_TxQuery(data) for ik in tx3.get_utxo_in_keys(): assert ik not in factory.db ## A transaction should be indepotent assert factory.process_TxQuery(data) data2 = (tx4, [tx1.serialize()], [k1.export()[0]], [k1.sign(tx3.id())]) assert not factory.process_TxQuery(data2)
def test_online_issue(sometx): (factory, instance, tr), (k1, k2, tx1, tx2, tx3) = sometx kIssue = rscoin.Key(file("secret.key").read(), False) # rscoin.Key(urandom(32), public=False) pubIssue = kIssue.pub.export() factory.special_key = kIssue.id() print "Public ID: %s" % b64encode(factory.special_key) # Build a new coin k1 = rscoin.Key(urandom(32), public=False) k1pub = k1.pub.export() tx3 = rscoin.Tx([], [rscoin.OutputTx(k1.id(), 250)]) sig1 = kIssue.sign(tx3.id()) ## Now we test the Commit #data1 = map(b64encode, [tx3.serialize(), pubIssue, sig1]) #data = " ".join(["Commit", str(len(data1))] + data1) data = package_issue(tx3, [kIssue, sig1]) # test on fake tr.clear() instance.lineReceived(data) # Ensure the returned signatures check ret, pub, sig = tr.value().split(" ") assert ret == "OK" kx = rscoin.Key(b64decode(pub)) assert kx.verify(tx3.id(), b64decode(sig)) # Second time: tr.clear() instance.lineReceived(data) ret2, pub2, sig2 = tr.value().split(" ") assert ret2 == ret assert pub2 == pub assert sig != sig2 assert kx.verify(tx3.id(), b64decode(sig2)) import socket HOST = master_ip # The remote host PORT = 8080 # The same port as used by the server s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) s.sendall(data + '\r\n') data_rec = '' data_rec += s.recv(4096) print "Data: '%s'" % data_rec s.close() # Ensure the returned signatures check ret, pub, sig = data_rec.split(" ") assert ret == "OK" kx = rscoin.Key(b64decode(pub)) assert kx.verify(tx3.id(), b64decode(sig))
def test_TxCommit_Issued(sometx): (factory, instance, tr), (k1, k2, tx1, tx2, tx3) = sometx kIssue = rscoin.Key(urandom(32), public=False) pubIssue = kIssue.export()[0] factory.special_key = kIssue.id() # Asssign this as the special key tx3 = rscoin.Tx([], [rscoin.OutputTx(k1.id(), 250)]) sig1 = kIssue.sign(tx3.id()) assert tx3.check_transaction_utxo([], [pubIssue], [sig1], kIssue.id()) assert tx3.check_transaction([], [pubIssue], [sig1], kIssue.id()) ## Now we test the Commit # Ensure the entries are not in before sending message for k, v in tx3.get_utxo_out_entries(): assert k not in factory.db # Send message tr.clear() data = package_issue(tx3, [kIssue, sig1]) instance.lineReceived(data) # Ensure the returned signatures check ret, pub, sig = tr.value().split(" ") assert ret == "OK" kx = rscoin.Key(b64decode(pub)) assert kx.verify(tx3.id(), b64decode(sig)) # Ensure the entries are now in for k, v in tx3.get_utxo_out_entries(): assert factory.db[k] == v
def test_multiple(): import os try: os.mkdir("testscratch") except: pass # Make special keys for making coins secret_special = "KEYSPECIAL" public_special = rscoin.Key(secret_special, public=False).id() # Define a number of keys all_keys = [] for x in range(100): secret = "KEY%s" % x public = rscoin.Key(secret, public=False).id() all_keys += [(public, secret)] # Make up the directory directory = [] for x, (pub, _) in enumerate(all_keys): directory += [(pub, "127.0.0.1", 8080 + x)] # Build the factories factories = {} for pub, sec in all_keys: factory = RSCFactory(sec, directory, public_special, conf_dir="testscratch", N=5) factories[pub] = factory # Make a mass of transactions k1 = rscoin.Key(urandom(32), public=False) k2 = rscoin.Key(urandom(32), public=False) all_tx_in = [] all_tx_out = [] for _ in range(10): tx1 = rscoin.Tx([], [rscoin.OutputTx(k1.id(), 100)]) tx2 = rscoin.Tx([], [rscoin.OutputTx(k2.id(), 150)]) tx3 = rscoin.Tx( [rscoin.InputTx(tx1.id(), 0), rscoin.InputTx(tx2.id(), 0)], [rscoin.OutputTx(k1.id(), 250)]) all_tx_in += [tx1, tx2] all_tx_out += [tx3] print "Lens: all_tx_in: %s all_tx_out: %s" % (len(all_tx_in), len(all_tx_out)) for tx in all_tx_in: for kv, vv in tx.get_utxo_out_entries(): for f in factories.values(): f.db[kv] = vv data = (tx3, [tx1.serialize(), tx2.serialize()], [k1.export()[0], k2.export()[0]], [k1.sign(tx3.id()), k2.sign(tx3.id())]) # Put the transaction through total = 0 [kid1, kid2] = tx3.get_utxo_in_keys() au1 = get_authorities(directory, kid1, N=5) au2 = get_authorities(directory, kid2, N=5) auxes = set(au1 + au2) assert len(auxes) == 10 for aid in auxes: assert isinstance(aid, str) and len(aid) == 32 assert aid in factories H, msg, dataCore = package_query(tx3, [tx1, tx2], [k1, k2]) xset = [] rss = [] for kid, f in factories.iteritems(): # resp = f.process_TxQuery(data) instance = f.buildProtocol(None) tr = StringTransport() instance.makeConnection(tr) instance.lineReceived(msg) resp_msg = unpackage_query_response(tr.value().strip()) assert kid == f.key.id() if resp_msg[0] == "OK": [r, s] = resp_msg[1:] total += 1 xset += [f.key.id()] rss += [(r, s)] else: pass assert 5 <= total <= 10 assert set(auxes) == set(xset) ## Now test the commit phase assert 5 <= len(rss) <= 10 msg_commit = package_commit(dataCore, rss) #from twisted.python import log #import sys #log.startLogging(sys.stdout) total = 0 for kid, f in factories.iteritems(): instance = f.buildProtocol(None) tr = StringTransport() instance.makeConnection(tr) instance.lineReceived(msg_commit) resp_commit = tr.value().strip() resp_l = unpackage_commit_response(resp_commit) if resp_l[0] == "OK": total += 1 assert total == 5
def main(): dir_data = load_setup(file("directory.conf").read()) # directory = dir_data["directory"] directory = [(kid, socket.gethostbyname(ip), port) for (kid, ip, port) in dir_data["directory"]] special_id = dir_data["special"] # Options parser = argparse.ArgumentParser(description='RSCoin client.') parser.add_argument('--dir', action='store_true', help='List mintettes.') parser.add_argument('--mock', action='store_true', help='Do not connect to the network.') parser.add_argument('--balances', action='store_true', help='List balances of all addresses.') parser.add_argument('--issue', nargs=2, metavar=("VALUE", "ADDRESS"), help='Issue a coin to an address.') parser.add_argument('--pay', nargs=3, metavar=("VALUE", "ADDRESS", "CHANGEADDRESS"), help='Pay and address some amount, and return change') parser.add_argument('--newaddress', nargs=1, metavar="NAME", help='Make a new address with a specific name.') parser.add_argument('--storeaddress', nargs=2, metavar=("NAME", "KEYID"), help='Load an address ID with a specific name.') parser.add_argument('--listaddress', action='store_true', help='List all known addresses.') parser.add_argument('--play', nargs=1, metavar="FILE", help='Play a set of transaction cores.') parser.add_argument('--conn', default=20, type=int, metavar="CONNECTIONS", help='Number of simultaneaous connections.') args = parser.parse_args() if args.dir: for (kid, ip, port) in directory: print "%s\t%s\t%s" % (ip, port, b64encode(kid)) elif args.balances: keys = load_keys() active = ActiveTx("activetx.log", keys) for (k, v) in active.balances().iteritems(): print "%s\t%s RSC" % (k, v) elif args.listaddress: keys = load_keys() for k in keys: if k[0] == "#": print "%s\t%s (%s)" % (k, keys[k][2], keys[k][1]) elif args.newaddress: sec_str = urandom(32) k_sec = rscoin.Key(sec_str, public=False) k_pub = k_sec.pub.export() k_id = k_sec.id() f = file("keychain.txt", "a") data = "#%s sec %s %s" % (args.newaddress[0], b64encode(k_id), b64encode(sec_str)) print data f.write(data + "\n") f.close() elif args.storeaddress: f = file("keychain.txt", "a") data = "#%s pub %s" % (args.storeaddress[0], args.storeaddress[1]) f.write(data + "\n") f.close() elif args.play: threads = [None] * args.conn cores = [] for core in file(args.play[0]): c = core.strip().split() cores += [c] def play_another_song(var): if var is not None and (not isinstance(var, float) or not isinstance(var, float)): print "ERROR", var if cores != []: c = cores.pop() d = play(c, directory) d.addCallback(play_another_song) def replay(): cores += [c] d.addErrback(replay) d.addErrback(play_another_song) else: threads.pop() if threads == []: reactor.stop() for _ in threads: play_another_song(None) t0 = default_timer() reactor.run() t1 = default_timer() print "Overall time: %s" % (t1 - t0) for (ip, v) in sorted(_stats.iteritems()): print "Stats: %s %s" % (ip, v) elif args.pay: (val, dest_addr, change_addr) = args.pay val = int(val) assert isinstance(val, int) and 0 < val keys = load_keys() dest_addr = b64decode(keys["#" + dest_addr][2]) change_addr = b64decode(keys["#" + change_addr][2]) active = ActiveTx("activetx.log", keys) print val xval, txs = active.get_value(int(val)) assert len(txs) > 0 if val <= xval: # build the transactions inTx = [] outTx = [rscoin.OutputTx(dest_addr, val)] if xval - val > 0: outTx += [rscoin.OutputTx(change_addr, xval - val)] inTx_list = [] keys_list = [] for (tx_id, i, key_id, value) in txs: inTx_list += [ rscoin.Tx.parse(active.Tx[(tx_id, i, key_id, value)]) ] keys_list += [rscoin.Key(b64decode(keys[key_id][3]), False)] inTx += [rscoin.InputTx(tx_id, i)] newtx = rscoin.Tx(inTx, outTx) newtx_ser = newtx.serialize() ## Now we sign and remove from the list active.add(newtx_ser) for k in txs: active.remove(k) active.save(reactor) ## Now run the on-line checking sechash, query_string, core = package_query( newtx, inTx_list, keys_list) print " ".join(core) d = play(core, directory) d.addBoth(r_stop) reactor.run() else: print "Insufficient balance: %s ( < %s)" % (val, xval) elif args.issue: # Parse the basic files. secret = file("secret.key").read() mykey = rscoin.Key(secret, public=False) # Ensure the secret key corresponds to the special public key. assert special_id == mykey.id() [value_str, key_name] = args.issue keys = load_keys() key_id = b64decode(keys["#" + key_name][2]) tx = rscoin.Tx([], [rscoin.OutputTx(key_id, int(value_str))]) sig = mykey.sign(tx.id()) ## Now we test the Commit tx_ser = tx.serialize() #core = map(b64encode, [tx_ser, mykey.pub.export(), sig]) #data = " ".join(["Commit", str(len(core))] + core) data = package_issue(tx, [mykey, sig]) if args.mock: print data else: auths = set(get_authorities(directory, tx.id())) small_dir = [(kid, ip, port) for (kid, ip, port) in directory if kid in auths] d = broadcast(small_dir, data) def r_process(results): for msg in results: parsed = unpackage_commit_response(msg) if parsed[0] != "OK": raise Exception("Response not OK.") pub, sig = parsed[1:] kx = rscoin.Key(pub) if not (kx.verify(tx.id(), sig) and kx.id() in auths): raise Exception("Invalid Signature.") auths.remove(kx.id()) active = ActiveTx("activetx.log", keys) active.add(tx_ser) active.save(reactor) print " ".join(core) d.addCallback(r_process) d.addBoth(r_stop) reactor.run()