Merge branch 'master' of https://github.com/spesmilo/electrum into uncopyable-seed
This commit is contained in:
commit
68af712c8b
|
@ -412,26 +412,18 @@ class Commands:
|
|||
return tx
|
||||
|
||||
@command('wp')
|
||||
def payto(self, destination, amount, tx_fee=None, from_addr=None, change_addr=None, nocheck=False, unsigned=False, deserialized=False, broadcast=False):
|
||||
def payto(self, destination, amount, tx_fee=None, from_addr=None, change_addr=None, nocheck=False, unsigned=False, deserialized=False):
|
||||
"""Create a transaction. """
|
||||
domain = [from_addr] if from_addr else None
|
||||
tx = self._mktx([(destination, amount)], tx_fee, change_addr, domain, nocheck, unsigned)
|
||||
if broadcast:
|
||||
r, h = self.wallet.sendtx(tx)
|
||||
return h
|
||||
else:
|
||||
return tx.deserialize() if deserialized else tx
|
||||
return tx.deserialize() if deserialized else tx
|
||||
|
||||
@command('wp')
|
||||
def paytomany(self, outputs, tx_fee=None, from_addr=None, change_addr=None, nocheck=False, unsigned=False, deserialized=False, broadcast=False):
|
||||
def paytomany(self, outputs, tx_fee=None, from_addr=None, change_addr=None, nocheck=False, unsigned=False, deserialized=False):
|
||||
"""Create a multi-output transaction. """
|
||||
domain = [from_addr] if from_addr else None
|
||||
tx = self._mktx(outputs, tx_fee, change_addr, domain, nocheck, unsigned)
|
||||
if broadcast:
|
||||
r, h = self.wallet.sendtx(tx)
|
||||
return h
|
||||
else:
|
||||
return tx.deserialize() if deserialized else tx
|
||||
return tx.deserialize() if deserialized else tx
|
||||
|
||||
@command('wn')
|
||||
def history(self):
|
||||
|
@ -620,7 +612,6 @@ param_descriptions = {
|
|||
}
|
||||
|
||||
command_options = {
|
||||
'broadcast': (None, "--broadcast", "Broadcast the transaction to the Bitcoin network"),
|
||||
'password': ("-W", "--password", "Password"),
|
||||
'concealed': ("-C", "--concealed", "Don't echo seed to console when restoring"),
|
||||
'receiving': (None, "--receiving", "Show only receiving addresses"),
|
||||
|
|
|
@ -141,61 +141,6 @@ class TestTransaction(unittest.TestCase):
|
|||
res = transaction.parse_xpub('fd007d260305ef27224bbcf6cf5238d2b3638b5a78d5')
|
||||
self.assertEquals(res, (None, '1CQj15y1N7LDHp7wTt28eoD1QhHgFgxECH'))
|
||||
|
||||
def test_sign_tx(self):
|
||||
tx = transaction.Transaction(unsigned_blob)
|
||||
tx.deserialize()
|
||||
|
||||
x_pubkey = 'ff0488b21e03ef2afea18000000089689bff23e1e7fb2f161daa37270a97a3d8c2e537584b2d304ecb47b86d21fc021b010d3bd425f8cf2e04824bfdf1f1f5ff1d51fadd9a41f9e3fb8dd3403b1bfe00000000'
|
||||
privkey = 'L187zmkzzGgf9QdB23MrZvwJ52WoZuQHtkddjmePtbVjXxicJND2'
|
||||
|
||||
tx.sign(keypairs={x_pubkey: privkey})
|
||||
self.assertEquals(tx.serialize(), signed_blob)
|
||||
|
||||
tx.sign(keypairs={x_pubkey: privkey})
|
||||
self.assertEquals(tx.serialize(), signed_blob)
|
||||
|
||||
def test_sweep(self):
|
||||
privkeys = ['5HuH1SHoSVrgtPEwew9JzVAHGoKyp47x564mBCTgVmUT2Me1Q18']
|
||||
unspent = [
|
||||
{
|
||||
"height": 371447,
|
||||
"tx_hash": "8e4d173db094786cc128b0c12eebc2200c0d8bfc3ad04ba39f487222d18bae3c",
|
||||
"tx_pos": 0,
|
||||
"value": 599995800
|
||||
}
|
||||
]
|
||||
to_address = '1JtBahwvii2pRkBmb4QMfcJQux1rk3Jkbq'
|
||||
network = NetworkMock(unspent)
|
||||
tx = transaction.Transaction.sweep(privkeys, network, to_address, fee=5000)
|
||||
result = transaction.deserialize(tx.serialize())
|
||||
expected = {
|
||||
'inputs': [{
|
||||
'address': '1t28kmZypcPQrunmJk212dcPGPxbBtB6Y',
|
||||
'is_coinbase': False,
|
||||
'num_sig': 1,
|
||||
'prevout_hash': '8e4d173db094786cc128b0c12eebc2200c0d8bfc3ad04ba39f487222d18bae3c',
|
||||
'prevout_n': 0,
|
||||
'pubkeys': ['047b9f9014f8d0d6f24dcaf5681b6ab185bd821e0fcce29d84e0452845baf1b2dbe332a7cd4dbdab786adda6d71b2188298c756b265c63de2794f7317b71a7ac02'],
|
||||
'scriptSig': '48304502203f1ff200490d18bcb802c7cf7ba4264727b089f1db6746a62997285b5ac77969022100e495591ea5111bb23a782984736f32942570fda781b7ed085fc8c88a9756aaac0141047b9f9014f8d0d6f24dcaf5681b6ab185bd821e0fcce29d84e0452845baf1b2dbe332a7cd4dbdab786adda6d71b2188298c756b265c63de2794f7317b71a7ac02',
|
||||
'sequence': 4294967295,
|
||||
'signatures': ['304502203f1ff200490d18bcb802c7cf7ba4264727b089f1db6746a62997285b5ac77969022100e495591ea5111bb23a782984736f32942570fda781b7ed085fc8c88a9756aaac'],
|
||||
'x_pubkeys': ['047b9f9014f8d0d6f24dcaf5681b6ab185bd821e0fcce29d84e0452845baf1b2dbe332a7cd4dbdab786adda6d71b2188298c756b265c63de2794f7317b71a7ac02']}],
|
||||
'lockTime': 0,
|
||||
'outputs': [{'address': '1JtBahwvii2pRkBmb4QMfcJQux1rk3Jkbq',
|
||||
'prevout_n': 0,
|
||||
'scriptPubKey': '76a914c4282f6060b811ee695ebb2068b8788213451d6a88ac',
|
||||
'type': 'address',
|
||||
'value': 599990800}],
|
||||
'version': 1}
|
||||
self.assertEquals(result, expected)
|
||||
|
||||
network = NetworkMock([])
|
||||
tx = transaction.Transaction.sweep(privkeys, network, to_address, fee=5000)
|
||||
self.assertEquals(tx, None)
|
||||
|
||||
privkeys = []
|
||||
tx = transaction.Transaction.sweep(privkeys, network, to_address, fee=5000)
|
||||
self.assertEquals(tx, None)
|
||||
|
||||
class NetworkMock(object):
|
||||
|
||||
|
|
|
@ -470,7 +470,14 @@ class Transaction:
|
|||
return self.raw
|
||||
|
||||
def __init__(self, raw):
|
||||
self.raw = raw.strip() if raw else None
|
||||
if raw is None:
|
||||
self.raw = None
|
||||
elif type(raw) in [str, unicode]:
|
||||
self.raw = raw.strip() if raw else None
|
||||
elif type(raw) is dict:
|
||||
self.raw = raw['hex']
|
||||
else:
|
||||
raise BaseException("cannot initialize transaction", raw)
|
||||
self.inputs = None
|
||||
|
||||
def update(self, raw):
|
||||
|
|
|
@ -125,6 +125,10 @@ class WalletStorage(PrintError):
|
|||
f.write(s)
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
|
||||
if 'ANDROID_DATA' not in os.environ:
|
||||
import stat
|
||||
mode = os.stat(self.path).st_mode if os.path.exists(self.path) else stat.S_IREAD | stat.S_IWRITE
|
||||
# perform atomic write on POSIX systems
|
||||
try:
|
||||
os.rename(temp_path, self.path)
|
||||
|
@ -133,7 +137,7 @@ class WalletStorage(PrintError):
|
|||
os.rename(temp_path, self.path)
|
||||
if 'ANDROID_DATA' not in os.environ:
|
||||
import stat
|
||||
os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE)
|
||||
os.chmod(self.path, mode)
|
||||
self.print_error("saved")
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue