Skip to content
Snippets Groups Projects
Commit cdf2e29c authored by inso's avatar inso
Browse files

Fix transactions build for protocol 0.30

parent 70dab8d4
No related branches found
No related tags found
No related merge requests found
......@@ -175,22 +175,52 @@ class Wallet(QObject):
:return: The list of inputs to use in the transaction document
"""
# such a dirty algorithmm
# everything should be done again from scratch
# in future versions
def current_value(inputs, overhs):
i = 0
for s in inputs:
i += s['amount'] * (10**s['base'])
for o in overhs:
i -= o[0] * (10**o[1])
return i
amount, amount_base = reduce_base(amount, 0)
cache = self.caches[community.currency]
current_base = amount_base
while current_base >= 0:
current_base = max([src['base'] for src in cache.available_sources])
value = 0
sources = []
outputs = []
overheads = []
buf_sources = list(cache.available_sources)
while current_base >= 0:
for s in [src for src in cache.available_sources if src['base'] == current_base]:
value += s['amount'] * pow(10, s['base'])
test_sources = sources + [s]
val = current_value(test_sources, overheads)
# if we have to compute an overhead
if current_value(test_sources, overheads) > amount * (10**amount_base):
overhead = current_value(test_sources, overheads) - int(amount) * (10**amount_base)
# we round the overhead in the current base
# exemple : 12 in base 1 -> 1*10^1
overhead = int(round(float(overhead) / (10**current_base)))
source_value = s['amount'] * (10**s['base'])
out = int((source_value - (overhead * (10**current_base)))/(10**current_base))
if out * (10**current_base) <= amount * (10**amount_base):
sources.append(s)
buf_sources.remove(s)
if value >= amount * pow(10, amount_base):
overhead = value - int(amount) * pow(10, amount_base)
overhead, overhead_max_base = reduce_base(overhead, 0)
if overhead_max_base >= current_base:
return (sources, buf_sources)
overheads.append((overhead, current_base))
outputs.append((out, current_base))
# else just add the output
else:
sources.append(s)
buf_sources.remove(s)
outputs.append((s['amount'] , s['base']))
if current_value(sources, overheads) == amount * (10 ** amount_base):
return sources, outputs, overheads, buf_sources
current_base -= 1
raise NotEnoughMoneyError(value, community.currency,
......@@ -222,31 +252,35 @@ class Wallet(QObject):
unlocks.append(Unlock(i, [SIGParameter(0)]))
return unlocks
def tx_outputs(self, pubkey, amount, inputs):
def tx_outputs(self, pubkey, outputs, overheads):
"""
Get outputs to generate a transaction with a given amount of money
:param str pubkey: The target pubkey of the transaction
:param int amount: The amount to send
:param list outputs: The amount to send
:param list inputs: The inputs used to send the given amount of money
:param list overheads: The overheads used to send the given amount of money
:return: The list of outputs to use in the transaction document
"""
outputs = []
inputs_value = 0
for i in inputs:
logging.debug(i)
inputs_value += i['amount'] * pow(10, i['base'])
inputs_max_base = max([i['base'] for i in inputs])
overhead = inputs_value - int(amount)
amount, amount_base = int(amount / pow(10, inputs_max_base)), inputs_max_base
overhead, overhead_base = int(overhead / pow(10, inputs_max_base)), inputs_max_base
outputs.append(OutputSource(amount, amount_base, output.Condition.token(output.SIG.token(pubkey))))
if overhead != 0:
outputs.append(OutputSource(overhead, overhead_base, output.Condition.token(output.SIG.token(self.pubkey))))
return outputs
total = []
outputs_bases = set(o[1] for o in outputs)
for base in outputs_bases:
output_sum = 0
for o in outputs:
if o[1] == base:
output_sum += o[0]
total.append(OutputSource(output_sum, base, output.Condition.token(output.SIG.token(pubkey))))
overheads_bases = set(o[1] for o in overheads)
for base in overheads_bases:
overheads_sum = 0
for o in overheads:
if o[1] == base:
overheads_sum += o[0]
total.append(OutputSource(overheads_sum, base, output.Condition.token(output.SIG.token(self.pubkey))))
return total
def prepare_tx(self, pubkey, blockstamp, amount, message, community):
"""
......@@ -260,12 +294,14 @@ class Wallet(QObject):
"""
result = self.tx_sources(int(amount), community)
sources = result[0]
self.caches[community.currency].available_sources = result[1][1:]
computed_outputs = result[1]
overheads = result[2]
self.caches[community.currency].available_sources = result[3][1:]
logging.debug("Inputs : {0}".format(sources))
inputs = self.tx_inputs(sources)
unlocks = self.tx_unlocks(sources)
outputs = self.tx_outputs(pubkey, amount, sources)
outputs = self.tx_outputs(pubkey, computed_outputs, overheads)
logging.debug("Outputs : {0}".format(outputs))
tx = Transaction(PROTOCOL_VERSION, community.currency, blockstamp, 0,
[self.pubkey], inputs, unlocks,
......
......@@ -173,4 +173,90 @@ Unlocks:
Outputs:
10:1:SIG(FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn)
1:1:SIG(7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ)
Comment:""" + " \n")
def test_prepare_tx_base_1_overheads(self):
community = MagicMock("sakia.core.Community")
community.currency = "test_currency"
cache = MagicMock("sakia.core.txhistory.TxHistory")
cache.available_sources = [{
"pubkey": "7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ",
"type": "D",
"noffset": 2,
"identifier": "FCAD5A388AC8A811B45A9334A375585E77071AA9F6E5B6896582961A6C66F365",
"amount": 15,
"base": 0
},
{
"pubkey": "7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ",
"type": "D",
"noffset": 4,
"identifier": "A0AC57E2E4B24D66F2D25E66D8501D8E881D9E6453D1789ED753D7D426537ED5",
"amount": 85,
"base": 0
},
{
"pubkey": "FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn",
"type": "T",
"noffset": 4,
"identifier": "7518C700E78B56CC21FB1DDC6CBAB24E0FACC9A798F5ED8736EA007F38617D67",
"amount": 11,
"base": 1
}]
wallet = Wallet(0, "7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ",
"Wallet 1", self.identities_registry)
wallet.caches["test_currency"] = cache
tx = wallet.prepare_tx("FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn",
BlockUID(32, "000005E0F228038E4DDD4F6CA4ACB01EC88FBAF8"),
101, "", community)
self.assertEqual(tx.blockstamp.number, 32)
self.assertEqual(tx.blockstamp.sha_hash, "000005E0F228038E4DDD4F6CA4ACB01EC88FBAF8")
self.assertEqual(len(tx.issuers), 1)
self.assertEqual(tx.issuers[0], "7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ")
self.assertEqual(len(tx.inputs), 2)
self.assertEqual(tx.inputs[0].origin_id, "7518C700E78B56CC21FB1DDC6CBAB24E0FACC9A798F5ED8736EA007F38617D67")
self.assertEqual(tx.inputs[0].source, "T")
self.assertEqual(tx.inputs[0].index, 4)
self.assertEqual(tx.inputs[1].origin_id, "FCAD5A388AC8A811B45A9334A375585E77071AA9F6E5B6896582961A6C66F365")
self.assertEqual(tx.inputs[1].source, "D")
self.assertEqual(tx.inputs[1].index, 2)
self.assertEqual(len(tx.outputs), 4)
self.assertEqual(tx.outputs[0].amount, 1)
self.assertEqual(tx.outputs[0].base, 0)
self.assertEqual(pypeg2.compose(tx.outputs[0].conditions, output.Condition),
"SIG(FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn)")
self.assertEqual(tx.outputs[1].amount, 10)
self.assertEqual(tx.outputs[1].base, 1)
self.assertEqual(pypeg2.compose(tx.outputs[1].conditions, output.Condition),
"SIG(FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn)")
self.assertEqual(tx.outputs[2].amount, 14)
self.assertEqual(tx.outputs[2].base, 0)
self.assertEqual(pypeg2.compose(tx.outputs[2].conditions, output.Condition),
"SIG(7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ)")
self.assertEqual(tx.outputs[3].amount, 1)
self.assertEqual(tx.outputs[3].base, 1)
self.assertEqual(pypeg2.compose(tx.outputs[3].conditions, output.Condition),
"SIG(7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ)")
self.assertEqual(len(tx.unlocks), 2)
self.assertEqual(tx.unlocks[0].index, 0)
self.assertEqual(tx.unlocks[0].parameters[0].index, 0)
self.assertEqual(tx.unlocks[1].index, 1)
self.assertEqual(tx.unlocks[1].parameters[0].index, 0)
self.assertEqual(tx.raw(), """Version: 2
Type: Transaction
Currency: test_currency
Locktime: 0
Issuers:
7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ
Inputs:
T:7518C700E78B56CC21FB1DDC6CBAB24E0FACC9A798F5ED8736EA007F38617D67:4
D:FCAD5A388AC8A811B45A9334A375585E77071AA9F6E5B6896582961A6C66F365:2
Unlocks:
0:SIG(0)
1:SIG(0)
Outputs:
1:0:SIG(FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn)
10:1:SIG(FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn)
14:0:SIG(7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ)
1:1:SIG(7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ)
Comment:""" + " \n")
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment