Skip to content
This repository has been archived by the owner on Nov 15, 2021. It is now read-only.

Commit

Permalink
Fix exception thrown when signing without open wallet (#710)
Browse files Browse the repository at this point in the history
Fix silent failing when trying to sign with a multi-sig key not in the wallet
Fix transaction retry failure due to not cleaning up internal KnownHashes on add failure
Fix ghost thread throwing exceptions when trying to add to a non existing wallet
Fix signatures sorting on encoded ECPoint bytes values instead of a combination of ECPoint.X and ECPoint.Y preventing CHECKMULTISIG to pass
  • Loading branch information
ixje authored Nov 9, 2018
1 parent 8690a46 commit f8c03ba
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ All notable changes to this project are documented in this file.
- Fix confirmed tx not being purged from mempool `#703 </~https://github.com/CityOfZion/neo-python/issues/703>`_
- Fix bootstrap thread joining failure on Ubuntu systems
- Make bootstrap lookup dynamic such that users don't have to update their configs from here on forward
- Fix various issues related to signing multi-signature transactions
- Move some warnings and 'expected' errors to `DEBUG` level to avoid logging to console by default
- Empty VerificationScripts for deployed contracts now work as intended
- Fix RPC's ``getaccountstate`` response schema to match ``neo-cli`` `#714 </~https://github.com/CityOfZion/neo-python/issues/714>`
Expand Down
6 changes: 6 additions & 0 deletions neo/Network/NodeLeader.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,12 @@ def Relay(self, inventory):

elif type(inventory) is Transaction or issubclass(type(inventory), Transaction):
if not self.AddTransaction(inventory):
# if we fail to add the transaction for whatever reason, remove it from the known hashes list or we cannot retry the same transaction again
try:
self.KnownHashes.remove(inventory.Hash.ToBytes())
except ValueError:
# it not found
pass
return False
else:
# consensus
Expand Down
4 changes: 1 addition & 3 deletions neo/Prompt/Commands/Send.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ def process_transaction(wallet, contract_tx, scripthash_from=None, scripthash_ch
signer_contract = wallet.GetContract(standard_contract)

if not signer_contract.IsMultiSigContract and owners is None:

data = standard_contract.Data
tx.Attributes = [TransactionAttribute(usage=TransactionAttributeUsage.Script,
data=data)]
Expand All @@ -201,7 +200,7 @@ def process_transaction(wallet, contract_tx, scripthash_from=None, scripthash_ch

tx.scripts = context.GetScripts()

# print("will send tx: %s " % json.dumps(tx.ToJson(),indent=4))
# print("will send tx: %s " % json.dumps(tx.ToJson(),indent=4))

relayed = NodeLeader.Instance().Relay(tx)

Expand All @@ -228,7 +227,6 @@ def process_transaction(wallet, contract_tx, scripthash_from=None, scripthash_ch


def parse_and_sign(wallet, jsn):

try:
context = ContractParametersContext.FromJson(jsn)
if context is None:
Expand Down
13 changes: 9 additions & 4 deletions neo/SmartContract/ContractParameterContext.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from neo.VM import OpCode
from neo.Core.Witness import Witness
from neo.logging import log_manager
from neocore.Cryptography.ECCurve import ECDSA

logger = log_manager.getLogger('vm')

Expand Down Expand Up @@ -158,26 +159,30 @@ def AddSignature(self, contract, pubkey, signature):
elif pubkey.encode_point(True) in item.Signatures:
return False

ecdsa = ECDSA.secp256r1()
points = []
temp = binascii.unhexlify(contract.Script)
ms = MemoryStream(binascii.unhexlify(contract.Script))
reader = BinaryReader(ms)
numr = reader.ReadUInt8()
while reader.ReadUInt8() == 33:
points.append(binascii.hexlify(reader.ReadBytes(33)))
ecpoint = ecdsa.ec.decode_from_hex(binascii.hexlify(reader.ReadBytes(33)).decode())
points.append(ecpoint)
ms.close()

if pubkey.encode_point(True) not in points:
if pubkey not in points:
return False

item.Signatures[pubkey.encode_point(True).decode()] = binascii.hexlify(signature)

if len(item.Signatures) == len(contract.ParameterList):

i = 0
points.sort(reverse=True)
for k in points:
if k.decode() in item.Signatures:
if self.Add(contract, i, item.Signatures[k.decode()]) is None:
pubkey = k.encode_point(True).decode()
if pubkey in item.Signatures:
if self.Add(contract, i, item.Signatures[pubkey]) is None:
raise Exception("Invalid operation")
i += 1
item.Signatures = None
Expand Down
1 change: 1 addition & 0 deletions neo/Wallets/Wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,7 @@ def Sign(self, context):

contract = self.GetContract(hash)
if contract is None:
logger.info(f"Cannot find key belonging to script_hash {hash}. Make sure the source address you're trying to sign the transaction for is imported in the wallet.")
continue

key = self.GetKeyByScriptHash(hash)
Expand Down
8 changes: 6 additions & 2 deletions neo/bin/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,13 +304,15 @@ def do_create(self, arguments):
def start_wallet_loop(self):
if self.wallet_loop_deferred:
self.stop_wallet_loop()
walletdb_loop = task.LoopingCall(self.Wallet.ProcessBlocks)
self.wallet_loop_deferred = walletdb_loop.start(1)
self.walletdb_loop = task.LoopingCall(self.Wallet.ProcessBlocks)
self.wallet_loop_deferred = self.walletdb_loop.start(1)
self.wallet_loop_deferred.addErrback(self.on_looperror)

def stop_wallet_loop(self):
self.wallet_loop_deferred.cancel()
self.wallet_loop_deferred = None
if self.walletdb_loop and self.walletdb_loop.running:
self.walletdb_loop.stop()

def do_close_wallet(self):
if self.Wallet:
Expand Down Expand Up @@ -559,6 +561,8 @@ def do_send_many(self, arguments):
process_transaction(self.Wallet, contract_tx=framework[0], scripthash_from=framework[1], scripthash_change=framework[2], fee=framework[3], owners=framework[4], user_tx_attributes=framework[5])

def do_sign(self, arguments):
if not self.Wallet:
print("Please open a wallet before trying to sign")
jsn = get_arg(arguments)
parse_and_sign(self.Wallet, jsn)

Expand Down

0 comments on commit f8c03ba

Please sign in to comment.