mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 09:54:16 +01:00
txprepare: remove old code, switch to plugin.
Some minor phrasing differences cause test changes. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Changelog-Changed: txprepare reservations stay across restarts: use fundpsbt/reservepsbt/unreservepsbt Changelog-Removed: txprepare `destination` `satoshi` argument form removed (deprecated v0.7.3)
This commit is contained in:
parent
843d3d6745
commit
6b2a3f4dfb
@ -434,21 +434,21 @@ static struct command_result *json_txsend(struct command *cmd,
|
|||||||
|
|
||||||
static const struct plugin_command commands[] = {
|
static const struct plugin_command commands[] = {
|
||||||
{
|
{
|
||||||
"newtxprepare",
|
"txprepare",
|
||||||
"bitcoin",
|
"bitcoin",
|
||||||
"Create a transaction, with option to spend in future (either txsend and txdiscard)",
|
"Create a transaction, with option to spend in future (either txsend and txdiscard)",
|
||||||
"Create an unsigned transaction paying {outputs} with optional {feerate}, {minconf} and {utxos}",
|
"Create an unsigned transaction paying {outputs} with optional {feerate}, {minconf} and {utxos}",
|
||||||
json_txprepare
|
json_txprepare
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"newtxdiscard",
|
"txdiscard",
|
||||||
"bitcoin",
|
"bitcoin",
|
||||||
"Discard a transaction created by txprepare",
|
"Discard a transaction created by txprepare",
|
||||||
"Discard a transcation by {txid}",
|
"Discard a transcation by {txid}",
|
||||||
json_txdiscard
|
json_txdiscard
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"newtxsend",
|
"txsend",
|
||||||
"bitcoin",
|
"bitcoin",
|
||||||
"Send a transaction created by txprepare",
|
"Send a transaction created by txprepare",
|
||||||
"Send a transacation by {txid}",
|
"Send a transacation by {txid}",
|
||||||
|
@ -771,7 +771,7 @@ def test_funding_fail(node_factory, bitcoind):
|
|||||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||||
|
|
||||||
# We don't have enough left to cover fees if we try to spend it all.
|
# We don't have enough left to cover fees if we try to spend it all.
|
||||||
with pytest.raises(RpcError, match=r'Cannot afford transaction'):
|
with pytest.raises(RpcError, match=r'Could not afford'):
|
||||||
l1.rpc.fundchannel(l2.info['id'], funds)
|
l1.rpc.fundchannel(l2.info['id'], funds)
|
||||||
|
|
||||||
# Should still be connected.
|
# Should still be connected.
|
||||||
@ -863,7 +863,7 @@ def test_funding_by_utxos(node_factory, bitcoind):
|
|||||||
utxos = [utxo["txid"] + ":" + str(utxo["output"]) for utxo in l1.rpc.listfunds()["outputs"]]
|
utxos = [utxo["txid"] + ":" + str(utxo["output"]) for utxo in l1.rpc.listfunds()["outputs"]]
|
||||||
|
|
||||||
# Fund with utxos we don't own
|
# Fund with utxos we don't own
|
||||||
with pytest.raises(RpcError, match=r"No matching utxo was found from the wallet"):
|
with pytest.raises(RpcError, match=r"Unknown UTXO "):
|
||||||
l3.rpc.fundchannel(l2.info["id"], int(0.01 * 10**8), utxos=utxos)
|
l3.rpc.fundchannel(l2.info["id"], int(0.01 * 10**8), utxos=utxos)
|
||||||
|
|
||||||
# Fund with an empty array
|
# Fund with an empty array
|
||||||
@ -878,7 +878,7 @@ def test_funding_by_utxos(node_factory, bitcoind):
|
|||||||
l1.rpc.fundchannel(l3.info["id"], int(0.007 * 10**8), utxos=[utxos[2]])
|
l1.rpc.fundchannel(l3.info["id"], int(0.007 * 10**8), utxos=[utxos[2]])
|
||||||
|
|
||||||
# Fund another channel with already spent utxos
|
# Fund another channel with already spent utxos
|
||||||
with pytest.raises(RpcError, match=r"No matching utxo was found from the wallet"):
|
with pytest.raises(RpcError, match=r"Already spent UTXO "):
|
||||||
l1.rpc.fundchannel(l3.info["id"], int(0.01 * 10**8), utxos=utxos)
|
l1.rpc.fundchannel(l3.info["id"], int(0.01 * 10**8), utxos=utxos)
|
||||||
|
|
||||||
|
|
||||||
|
@ -341,8 +341,7 @@ def test_txprepare(node_factory, bitcoind, chainparams):
|
|||||||
# Try passing unconfirmed utxos
|
# Try passing unconfirmed utxos
|
||||||
unconfirmed_utxo = l1.rpc.withdraw(l1.rpc.newaddr()["bech32"], 10**5)
|
unconfirmed_utxo = l1.rpc.withdraw(l1.rpc.newaddr()["bech32"], 10**5)
|
||||||
uutxos = [unconfirmed_utxo["txid"] + ":0"]
|
uutxos = [unconfirmed_utxo["txid"] + ":0"]
|
||||||
with pytest.raises(RpcError, match=r"Cannot afford transaction .* use "
|
with pytest.raises(RpcError, match=r"Could not afford"):
|
||||||
"confirmed utxos."):
|
|
||||||
l1.rpc.txprepare([{addr: Millisatoshi(amount * 3.5 * 1000)}],
|
l1.rpc.txprepare([{addr: Millisatoshi(amount * 3.5 * 1000)}],
|
||||||
utxos=uutxos)
|
utxos=uutxos)
|
||||||
|
|
||||||
@ -357,15 +356,24 @@ def test_txprepare(node_factory, bitcoind, chainparams):
|
|||||||
|
|
||||||
# We should have a change output, so this is exact
|
# We should have a change output, so this is exact
|
||||||
assert len(decode['vout']) == 3 if chainparams['feeoutput'] else 2
|
assert len(decode['vout']) == 3 if chainparams['feeoutput'] else 2
|
||||||
assert decode['vout'][1]['value'] == Decimal(amount * 3.5) / 10**8
|
# Change output pos is random.
|
||||||
assert decode['vout'][1]['scriptPubKey']['type'] == 'witness_v0_keyhash'
|
for vout in decode['vout']:
|
||||||
assert decode['vout'][1]['scriptPubKey']['addresses'] == [addr]
|
if vout['scriptPubKey']['addresses'] == [addr]:
|
||||||
|
changeout = vout
|
||||||
|
|
||||||
|
assert changeout['value'] == Decimal(amount * 3.5) / 10**8
|
||||||
|
assert changeout['scriptPubKey']['type'] == 'witness_v0_keyhash'
|
||||||
|
assert changeout['scriptPubKey']['addresses'] == [addr]
|
||||||
|
|
||||||
# Discard prep4 and get all funds again
|
# Discard prep4 and get all funds again
|
||||||
l1.rpc.txdiscard(prep5['txid'])
|
l1.rpc.txdiscard(prep5['txid'])
|
||||||
with pytest.raises(RpcError, match=r'this destination wants all satoshi. The count of outputs can\'t be more than 1'):
|
# You can have one which is all, but not two.
|
||||||
prep5 = l1.rpc.txprepare([{addr: Millisatoshi(amount * 3 * 1000)},
|
prep5 = l1.rpc.txprepare([{addr: Millisatoshi(amount * 3 * 1000)},
|
||||||
{addr: 'all'}])
|
{addr: 'all'}])
|
||||||
|
l1.rpc.txdiscard(prep5['txid'])
|
||||||
|
with pytest.raises(RpcError, match=r"'all'"):
|
||||||
|
prep5 = l1.rpc.txprepare([{addr: 'all'}, {addr: 'all'}])
|
||||||
|
|
||||||
prep5 = l1.rpc.txprepare([{addr: Millisatoshi(amount * 3 * 500 + 100000)},
|
prep5 = l1.rpc.txprepare([{addr: Millisatoshi(amount * 3 * 500 + 100000)},
|
||||||
{addr: Millisatoshi(amount * 3 * 500 - 100000)}])
|
{addr: Millisatoshi(amount * 3 * 500 - 100000)}])
|
||||||
decode = bitcoind.rpc.decoderawtransaction(prep5['unsigned_tx'])
|
decode = bitcoind.rpc.decoderawtransaction(prep5['unsigned_tx'])
|
||||||
|
@ -470,126 +470,6 @@ create_tx:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command_result *json_txprepare(struct command *cmd,
|
|
||||||
const char *buffer,
|
|
||||||
const jsmntok_t *obj UNNEEDED,
|
|
||||||
const jsmntok_t *params)
|
|
||||||
{
|
|
||||||
struct unreleased_tx *utx;
|
|
||||||
struct command_result *res;
|
|
||||||
struct json_stream *response;
|
|
||||||
|
|
||||||
res = json_prepare_tx(cmd, buffer, params, false, &utx, NULL);
|
|
||||||
if (res)
|
|
||||||
return res;
|
|
||||||
|
|
||||||
/* utx will persist past this command. */
|
|
||||||
tal_steal(cmd->ld->wallet, utx);
|
|
||||||
add_unreleased_tx(cmd->ld->wallet, utx);
|
|
||||||
|
|
||||||
response = json_stream_success(cmd);
|
|
||||||
json_add_tx(response, "unsigned_tx", utx->tx);
|
|
||||||
json_add_txid(response, "txid", &utx->txid);
|
|
||||||
return command_success(cmd, response);
|
|
||||||
}
|
|
||||||
static const struct json_command txprepare_command = {
|
|
||||||
"txprepare",
|
|
||||||
"bitcoin",
|
|
||||||
json_txprepare,
|
|
||||||
"Create a transaction, with option to spend in future (either txsend and txdiscard)",
|
|
||||||
false
|
|
||||||
};
|
|
||||||
AUTODATA(json_command, &txprepare_command);
|
|
||||||
|
|
||||||
static struct command_result *param_unreleased_txid(struct command *cmd,
|
|
||||||
const char *name,
|
|
||||||
const char *buffer,
|
|
||||||
const jsmntok_t *tok,
|
|
||||||
struct unreleased_tx **utx)
|
|
||||||
{
|
|
||||||
struct command_result *res;
|
|
||||||
struct bitcoin_txid *txid;
|
|
||||||
|
|
||||||
res = param_txid(cmd, name, buffer, tok, &txid);
|
|
||||||
if (res)
|
|
||||||
return res;
|
|
||||||
|
|
||||||
*utx = find_unreleased_tx(cmd->ld->wallet, txid);
|
|
||||||
if (!*utx)
|
|
||||||
return command_fail(cmd, LIGHTNINGD,
|
|
||||||
"%s not an unreleased txid",
|
|
||||||
type_to_string(cmd, struct bitcoin_txid,
|
|
||||||
txid));
|
|
||||||
tal_free(txid);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct command_result *json_txsend(struct command *cmd,
|
|
||||||
const char *buffer,
|
|
||||||
const jsmntok_t *obj UNNEEDED,
|
|
||||||
const jsmntok_t *params)
|
|
||||||
{
|
|
||||||
struct unreleased_tx *utx;
|
|
||||||
|
|
||||||
if (!param(cmd, buffer, params,
|
|
||||||
p_req("txid", param_unreleased_txid, &utx),
|
|
||||||
NULL))
|
|
||||||
return command_param_failed();
|
|
||||||
|
|
||||||
/* We delete from list now, and this command owns it. */
|
|
||||||
remove_unreleased_tx(utx);
|
|
||||||
tal_steal(cmd, utx);
|
|
||||||
|
|
||||||
/* We're the owning cmd now. */
|
|
||||||
utx->wtx->cmd = cmd;
|
|
||||||
|
|
||||||
wallet_transaction_add(cmd->ld->wallet, utx->tx->wtx, 0, 0);
|
|
||||||
wallet_transaction_annotate(cmd->ld->wallet, &utx->txid,
|
|
||||||
TX_UNKNOWN, 0);
|
|
||||||
|
|
||||||
return broadcast_and_wait(cmd, utx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct json_command txsend_command = {
|
|
||||||
"txsend",
|
|
||||||
"bitcoin",
|
|
||||||
json_txsend,
|
|
||||||
"Sign and broadcast a transaction created by txprepare",
|
|
||||||
false
|
|
||||||
};
|
|
||||||
AUTODATA(json_command, &txsend_command);
|
|
||||||
|
|
||||||
static struct command_result *json_txdiscard(struct command *cmd,
|
|
||||||
const char *buffer,
|
|
||||||
const jsmntok_t *obj UNNEEDED,
|
|
||||||
const jsmntok_t *params)
|
|
||||||
{
|
|
||||||
struct unreleased_tx *utx;
|
|
||||||
struct json_stream *response;
|
|
||||||
|
|
||||||
if (!param(cmd, buffer, params,
|
|
||||||
p_req("txid", param_unreleased_txid, &utx),
|
|
||||||
NULL))
|
|
||||||
return command_param_failed();
|
|
||||||
|
|
||||||
/* Free utx with this command */
|
|
||||||
tal_steal(cmd, utx);
|
|
||||||
|
|
||||||
response = json_stream_success(cmd);
|
|
||||||
json_add_tx(response, "unsigned_tx", utx->tx);
|
|
||||||
json_add_txid(response, "txid", &utx->txid);
|
|
||||||
return command_success(cmd, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct json_command txdiscard_command = {
|
|
||||||
"txdiscard",
|
|
||||||
"bitcoin",
|
|
||||||
json_txdiscard,
|
|
||||||
"Abandon a transaction created by txprepare",
|
|
||||||
false
|
|
||||||
};
|
|
||||||
AUTODATA(json_command, &txdiscard_command);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* json_withdraw - Entrypoint for the withdrawal flow
|
* json_withdraw - Entrypoint for the withdrawal flow
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user