async def post(self): config = self.config mongo = self.config.mongo body = json.loads(self.request.body.decode('utf-8')) try: fg = FastGraph.from_dict(0, body.get('txn'), raw=True) fg.verify() except: raise return 'invalid transaction', 400 res = mongo.db.signed_transactions.find_one({'hash': body.get('hash')}) if res: return 'no', 400 try: rid = TU.generate_rid(config, body.get('bulletin_secret')) my_entry_for_relationship = GU().get_transaction_by_rid( rid, config.wif, rid=True, my=True, public_key=config.public_key) their_entry_for_relationship = GU().get_transaction_by_rid( rid, rid=True, raw=True, theirs=True, public_key=config.public_key) verified = verify_signature( base64.b64decode(body.get('bulletin_secret')), my_entry_for_relationship['relationship'] ['their_username'].encode(), bytes.fromhex(their_entry_for_relationship['public_key'])) if not verified: return 'no', 400 verified = verify_signature( base64.b64decode(body.get('id')), body.get('hash').encode('utf-8'), bytes.fromhex(their_entry_for_relationship['public_key'])) address = str( P2PKHBitcoinAddress.from_pubkey( bytes.fromhex(their_entry_for_relationship['public_key']))) found = False for x in BU().get_wallet_unspent_transactions( address, [body.get('input')]): if body.get('input') == x['id']: found = True if not found: for x in BU().get_wallet_unspent_fastgraph_transactions( address): if body.get('input') == x['id']: found = True if found: signature = mongo.db.signed_transactions.find_one({ 'input': body.get('input'), 'txn.public_key': body['txn']['public_key'] }) if signature: already_spent = mongo.db.fastgraph_transactions.find_one({ 'txn.inputs.id': body['input'], 'txn.public_key': body['txn']['public_key'] }) if already_spent: self.set_status(400) self.write('already spent!') self.finish() return True else: signature['txn']['signatures'] = [ signature['signature'] ] fastgraph = FastGraph.from_dict(0, signature['txn']) try: fastgraph.verify() except Exception as e: raise return 'did not verify', 400 result = mongo.db.fastgraph_transactions.find_one( {'txn.hash': fastgraph.hash}) if result: return 'duplicate transaction found', 400 spent_check = mongo.db.fastgraph_transactions.find_one( { 'txn.inputs.id': { '$in': [x.id for x in fastgraph.inputs] } }) if spent_check: return 'already spent input', 400 fastgraph.save() else: return 'no transactions with this input found', 400 if verified: transaction_signature = TU.generate_signature_with_private_key( config.private_key, body.get('hash')) signature = { 'signature': transaction_signature, 'hash': body.get('hash'), 'bulletin_secret': body.get('bulletin_secret'), 'input': body.get('input'), 'id': body.get('id'), 'txn': body.get('txn') } mongo.db.signed_transactions.insert(signature) if '_id' in signature: del signature['_id'] self.render_as_json(signature, indent=4) else: return 'no', 400 except Exception as e: raise self.render_as_json({'status': 'error', 'msg': e})
def __init__( self, block_height, bulletin_secret='', username='', value=0, fee=0.0, requester_rid='', requested_rid='', public_key='', dh_public_key='', private_key='', dh_private_key='', to='', inputs='', outputs='', coinbase=False, chattext=None, signin=None, no_relationship=False ): self.config = get_config() self.mongo = self.config.mongo self.app_log = getLogger('tornado.application') self.block_height = block_height self.bulletin_secret = bulletin_secret self.username = username self.requester_rid = requester_rid self.requested_rid = requested_rid self.public_key = public_key self.dh_public_key = dh_public_key self.private_key = private_key self.value = value self.fee = float(fee) self.dh_private_key = dh_private_key self.to = to self.time = str(int(time.time())) self.outputs = [] self.no_relationship = no_relationship for x in outputs: self.outputs.append(Output.from_dict(x)) self.inputs = [] for x in inputs: if 'signature' in x and 'public_key' in x and 'address' in x: self.inputs.append(ExternalInput.from_dict(x)) else: self.inputs.append(Input.from_dict(x)) self.coinbase = coinbase self.chattext = chattext self.signin = signin self.do_money() inputs_concat = self.get_input_hashes() outputs_concat = self.get_output_hashes() if bulletin_secret: self.rid = self.generate_rid() if self.chattext: self.relationship = json.dumps({ "chatText": self.chattext }) self.cipher = Crypt(self.config.wif) self.encrypted_relationship = self.cipher.encrypt(self.relationship) elif self.signin: for shared_secret in TU.get_shared_secrets_by_rid(self.rid): self.relationship = SignIn(self.signin) self.cipher = Crypt(shared_secret.hex(), shared=True) self.encrypted_relationship = self.cipher.shared_encrypt(self.relationship.to_json()) break elif self.no_relationship: self.encrypted_relationship = '' else: if not self.dh_public_key or not self.dh_private_key: a = os.urandom(32).decode('latin1') self.dh_public_key = scalarmult_base(a).encode('latin1').hex() self.dh_private_key = a.encode().hex() self.relationship = self.generate_relationship() if not private_key: raise Exception('missing private key') self.cipher = Crypt(self.config.wif) self.encrypted_relationship = self.cipher.encrypt(self.relationship.to_json()) else: self.rid = '' self.encrypted_relationship = '' self.header = ( self.public_key + self.time + self.dh_public_key + self.rid + self.encrypted_relationship + "{0:.8f}".format(self.fee) + self.requester_rid + self.requested_rid + inputs_concat + outputs_concat ) self.hash = hashlib.sha256(self.header.encode('utf-8')).digest().hex() if self.private_key: self.transaction_signature = TU.generate_signature_with_private_key(private_key, self.hash) else: self.transaction_signature = '' self.transaction = self.generate_transaction()