2016-01-21 21:08:08 +01:00
|
|
|
#include "permute_tx.h"
|
2015-05-28 23:38:27 +02:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
static bool input_better(const struct bitcoin_tx_input *a,
|
|
|
|
const struct bitcoin_tx_input *b)
|
|
|
|
{
|
|
|
|
int cmp;
|
|
|
|
|
|
|
|
cmp = memcmp(&a->txid, &b->txid, sizeof(a->txid));
|
|
|
|
if (cmp != 0)
|
|
|
|
return cmp < 0;
|
|
|
|
if (a->index != b->index)
|
|
|
|
return a->index < b->index;
|
|
|
|
|
|
|
|
/* These shouldn't happen, but let's get a canonical order anyway. */
|
2017-01-25 00:35:43 +01:00
|
|
|
if (tal_len(a->script) != tal_len(b->script))
|
|
|
|
return tal_len(a->script) < tal_len(b->script);
|
|
|
|
cmp = memcmp(a->script, b->script, tal_len(a->script));
|
2015-05-28 23:38:27 +02:00
|
|
|
if (cmp != 0)
|
|
|
|
return cmp < 0;
|
|
|
|
return a->sequence_number < b->sequence_number;
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t find_best_in(struct bitcoin_tx_input *inputs, size_t num)
|
|
|
|
{
|
|
|
|
size_t i, best = 0;
|
|
|
|
|
|
|
|
for (i = 1; i < num; i++) {
|
|
|
|
if (input_better(&inputs[i], &inputs[best]))
|
|
|
|
best = i;
|
|
|
|
}
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
2017-02-07 02:44:22 +01:00
|
|
|
static void swap_inputs(struct bitcoin_tx_input *inputs,
|
2017-02-21 05:45:29 +01:00
|
|
|
const void **map,
|
2017-02-07 02:44:22 +01:00
|
|
|
size_t i1, size_t i2)
|
2015-05-28 23:38:27 +02:00
|
|
|
{
|
|
|
|
struct bitcoin_tx_input tmpinput;
|
2017-02-21 05:45:29 +01:00
|
|
|
const void *tmp;
|
2015-05-28 23:38:27 +02:00
|
|
|
|
2018-01-02 18:29:07 +01:00
|
|
|
if (i1 == i2)
|
|
|
|
return;
|
|
|
|
|
2015-05-28 23:38:27 +02:00
|
|
|
tmpinput = inputs[i1];
|
|
|
|
inputs[i1] = inputs[i2];
|
|
|
|
inputs[i2] = tmpinput;
|
2017-02-21 05:45:29 +01:00
|
|
|
|
|
|
|
if (map) {
|
|
|
|
tmp = map[i1];
|
|
|
|
map[i1] = map[i2];
|
|
|
|
map[i2] = tmp;
|
|
|
|
}
|
2015-05-28 23:38:27 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 05:45:29 +01:00
|
|
|
void permute_inputs(struct bitcoin_tx_input *inputs, size_t num_inputs,
|
|
|
|
const void **map)
|
2015-05-28 23:38:27 +02:00
|
|
|
{
|
2015-07-20 02:26:15 +02:00
|
|
|
size_t i;
|
2015-05-28 23:38:27 +02:00
|
|
|
|
|
|
|
/* Now do a dumb sort (num_inputs is small). */
|
2018-01-02 18:29:07 +01:00
|
|
|
for (i = 0; i < num_inputs-1; i++) {
|
2015-05-28 23:38:27 +02:00
|
|
|
/* Swap best into first place. */
|
2017-02-21 05:45:29 +01:00
|
|
|
swap_inputs(inputs, map,
|
2015-05-28 23:38:27 +02:00
|
|
|
i, i + find_best_in(inputs + i, num_inputs - i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-18 06:53:46 +02:00
|
|
|
static void swap_outputs(struct bitcoin_tx_output *outputs,
|
2017-02-21 05:45:29 +01:00
|
|
|
const void **map,
|
2017-02-07 02:44:22 +01:00
|
|
|
size_t i1, size_t i2)
|
2015-05-28 23:38:27 +02:00
|
|
|
{
|
|
|
|
struct bitcoin_tx_output tmpoutput;
|
2017-02-21 05:45:29 +01:00
|
|
|
const void *tmp;
|
2015-05-28 23:38:27 +02:00
|
|
|
|
2018-01-02 18:29:07 +01:00
|
|
|
if (i1 == i2)
|
|
|
|
return;
|
|
|
|
|
2015-05-28 23:38:27 +02:00
|
|
|
tmpoutput = outputs[i1];
|
|
|
|
outputs[i1] = outputs[i2];
|
|
|
|
outputs[i2] = tmpoutput;
|
2017-02-07 02:44:22 +01:00
|
|
|
|
2017-02-21 05:45:29 +01:00
|
|
|
if (map) {
|
|
|
|
tmp = map[i1];
|
|
|
|
map[i1] = map[i2];
|
|
|
|
map[i2] = tmp;
|
2017-02-07 02:44:22 +01:00
|
|
|
}
|
2015-05-28 23:38:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool output_better(const struct bitcoin_tx_output *a,
|
|
|
|
const struct bitcoin_tx_output *b)
|
|
|
|
{
|
2015-07-20 02:26:15 +02:00
|
|
|
size_t len;
|
|
|
|
int ret;
|
|
|
|
|
2015-05-28 23:38:27 +02:00
|
|
|
if (a->amount != b->amount)
|
|
|
|
return a->amount < b->amount;
|
|
|
|
|
2017-12-07 23:59:39 +01:00
|
|
|
/* Lexicographical sort. */
|
2017-01-25 00:35:43 +01:00
|
|
|
if (tal_len(a->script) < tal_len(b->script))
|
|
|
|
len = tal_len(a->script);
|
2015-07-20 02:26:15 +02:00
|
|
|
else
|
2017-01-25 00:35:43 +01:00
|
|
|
len = tal_len(b->script);
|
2015-07-20 02:26:15 +02:00
|
|
|
|
|
|
|
ret = memcmp(a->script, b->script, len);
|
|
|
|
if (ret != 0)
|
|
|
|
return ret < 0;
|
2015-05-28 23:38:27 +02:00
|
|
|
|
2017-01-25 00:35:43 +01:00
|
|
|
return tal_len(a->script) < tal_len(b->script);
|
2015-05-28 23:38:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static size_t find_best_out(struct bitcoin_tx_output *outputs, size_t num)
|
|
|
|
{
|
|
|
|
size_t i, best = 0;
|
|
|
|
|
|
|
|
for (i = 1; i < num; i++) {
|
|
|
|
if (output_better(&outputs[i], &outputs[best]))
|
|
|
|
best = i;
|
|
|
|
}
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
2017-02-21 05:45:29 +01:00
|
|
|
void permute_outputs(struct bitcoin_tx_output *outputs, size_t num_outputs,
|
|
|
|
const void **map)
|
2015-05-28 23:38:27 +02:00
|
|
|
{
|
2015-07-20 02:26:15 +02:00
|
|
|
size_t i;
|
2015-05-28 23:38:27 +02:00
|
|
|
|
|
|
|
/* Now do a dumb sort (num_outputs is small). */
|
2018-01-02 18:29:07 +01:00
|
|
|
for (i = 0; i < num_outputs-1; i++) {
|
2015-05-28 23:38:27 +02:00
|
|
|
/* Swap best into first place. */
|
2017-02-21 05:45:29 +01:00
|
|
|
swap_outputs(outputs, map,
|
2015-05-28 23:38:27 +02:00
|
|
|
i, i + find_best_out(outputs + i, num_outputs - i));
|
|
|
|
}
|
|
|
|
}
|