bkpr: add new RPC bkpr-editdescriptionbyoutpoint

Given an {outpoint}, sets the description on the matching outpoint (if exists).

Note that if no outpoint exists in bookkeeper, will return an empty list

Changleog-Added: PLUGINS: bookkeeper has a new RPC `bkrp-editdescriptionbyoutpoint` which will set/update a description for an outpoint creation event.
This commit is contained in:
niftynei 2024-08-22 18:00:22 -05:00 committed by Rusty Russell
parent a61b7ef347
commit 2b4b91ff5c
6 changed files with 685 additions and 0 deletions

View file

@ -2605,6 +2605,275 @@
}
]
},
"lightning-bkpr-editdescriptionbyoutpoint.json": {
"$schema": "../rpc-schema-draft.json",
"type": "object",
"additionalProperties": false,
"rpc": "bkpr-editdescriptionbyoutpoint",
"title": "Command to change the description for events with {outpoint} after they're made",
"description": [
"The **bkpr-editdescriptionbyoutpoint** RPC command updates all chain and channel events that match the {outpoint} with the provided {description}"
],
"request": {
"required": [
"outpoint",
"description"
],
"properties": {
"outpoint": {
"type": "string",
"description": [
"The outpoint to update the description for."
]
},
"description": {
"type": "string",
"description": [
"The description to update to"
]
}
}
},
"response": {
"required": [
"updated"
],
"properties": {
"updated": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"required": [
"account",
"type",
"tag",
"credit_msat",
"debit_msat",
"currency",
"timestamp",
"description"
],
"properties": {
"account": {
"type": "string",
"description": [
"The account name. If the account is a channel, the channel_id."
]
},
"type": {
"type": "string",
"enum": [
"chain",
"channel"
],
"description": [
"Coin movement type."
]
},
"tag": {
"type": "string",
"description": [
"Description of movement."
]
},
"credit_msat": {
"type": "msat",
"description": [
"Amount credited."
]
},
"debit_msat": {
"type": "msat",
"description": [
"Amount debited."
]
},
"currency": {
"type": "string",
"description": [
"Human-readable bech32 part for this coin type."
]
},
"timestamp": {
"type": "u32",
"description": [
"Timestamp this event was recorded by the node. For consolidated events such as onchain_fees, the most recent timestamp."
]
},
"description": {
"type": "string",
"description": [
"The description of this event"
]
}
},
"allOf": [
{
"if": {
"properties": {
"type": {
"type": "string",
"enum": [
"chain"
]
}
}
},
"then": {
"properties": {
"account": {},
"type": {},
"tag": {},
"credit_msat": {},
"debit_msat": {},
"currency": {},
"timestamp": {},
"description": {
"type": "string",
"description": [
"A description of this outpoint."
]
},
"outpoint": {
"type": "string",
"description": [
"The txid:outnum for this event."
]
},
"blockheight": {
"type": "u32",
"description": [
"For chain events, blockheight this occured at."
]
},
"origin": {
"type": "string",
"description": [
"The account this movement originated from."
]
},
"payment_id": {
"type": "hex",
"description": [
"Lightning payment identifier. For an htlc, this will be the preimage."
]
},
"txid": {
"type": "txid",
"description": [
"The txid of the transaction that created this event."
]
}
},
"required": [
"outpoint",
"blockheight"
],
"additionalProperties": false
}
},
{
"if": {
"properties": {
"type": {
"type": "string",
"enum": [
"onchain_fee"
]
}
}
},
"then": {
"properties": {
"account": {},
"type": {},
"tag": {},
"credit_msat": {},
"debit_msat": {},
"currency": {},
"timestamp": {},
"description": {},
"txid": {
"type": "txid",
"description": [
"The txid of the transaction that created this event."
]
}
},
"required": [
"txid"
],
"additionalProperties": false
}
},
{
"if": {
"properties": {
"type": {
"type": "string",
"enum": [
"channel"
]
}
}
},
"then": {
"properties": {
"account": {},
"type": {},
"tag": {},
"credit_msat": {},
"debit_msat": {},
"currency": {},
"timestamp": {},
"description": {},
"fees_msat": {
"type": "msat",
"description": [
"Amount paid in fees."
]
},
"is_rebalance": {
"type": "boolean",
"description": [
"Is this payment part of a rebalance."
]
},
"payment_id": {
"type": "hex",
"description": [
"Lightning payment identifier. For an htlc, this will be the preimage."
]
},
"part_id": {
"type": "u32",
"description": [
"Counter for multi-part payments."
]
}
},
"additionalProperties": false
}
}
]
}
}
}
},
"author": [
"Lisa Neigut <<niftynei@gmail.com>> is mainly responsible."
],
"see_also": [
"lightning-bkpr-editdescriptionbypaymentid(7)",
"lightning-bkpr-listaccountevents(7)",
"lightning-bkpr-listincome(7)"
],
"resources": [
"Main web site: <https://github.com/ElementsProject/lightning>"
],
"examples": []
},
"lightning-bkpr-editdescriptionbypaymentid.json": {
"$schema": "../rpc-schema-draft.json",
"type": "object",
@ -2859,6 +3128,7 @@
"Lisa Neigut <<niftynei@gmail.com>> is mainly responsible."
],
"see_also": [
"lightning-bkpr-editdescriptionbyoutpoint(7)",
"lightning-bkpr-listaccountevents(7)",
"lightning-bkpr-listincome(7)"
],

View file

@ -0,0 +1,270 @@
{
"$schema": "../rpc-schema-draft.json",
"type": "object",
"additionalProperties": false,
"rpc": "bkpr-editdescriptionbyoutpoint",
"title": "Command to change the description for events with {outpoint} after they're made",
"description": [
"The **bkpr-editdescriptionbyoutpoint** RPC command updates all chain and channel events that match the {outpoint} with the provided {description}"
],
"request": {
"required": [
"outpoint",
"description"
],
"properties": {
"outpoint": {
"type": "string",
"description": [
"The outpoint to update the description for."
]
},
"description": {
"type": "string",
"description": [
"The description to update to"
]
}
}
},
"response": {
"required": [
"updated"
],
"properties": {
"updated": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"required": [
"account",
"type",
"tag",
"credit_msat",
"debit_msat",
"currency",
"timestamp",
"description"
],
"properties": {
"account": {
"type": "string",
"description": [
"The account name. If the account is a channel, the channel_id."
]
},
"type": {
"type": "string",
"enum": [
"chain",
"channel"
],
"description": [
"Coin movement type."
]
},
"tag": {
"type": "string",
"description": [
"Description of movement."
]
},
"credit_msat": {
"type": "msat",
"description": [
"Amount credited."
]
},
"debit_msat": {
"type": "msat",
"description": [
"Amount debited."
]
},
"currency": {
"type": "string",
"description": [
"Human-readable bech32 part for this coin type."
]
},
"timestamp": {
"type": "u32",
"description": [
"Timestamp this event was recorded by the node. For consolidated events such as onchain_fees, the most recent timestamp."
]
},
"description": {
"type": "string",
"description": [
"The description of this event"
]
}
},
"allOf": [
{
"if": {
"properties": {
"type": {
"type": "string",
"enum": [
"chain"
]
}
}
},
"then": {
"properties": {
"account": {},
"type": {},
"tag": {},
"credit_msat": {},
"debit_msat": {},
"currency": {},
"timestamp": {},
"description": {
"type": "string",
"description": [
"A description of this outpoint."
]
},
"outpoint": {
"type": "string",
"description": [
"The txid:outnum for this event."
]
},
"blockheight": {
"type": "u32",
"description": [
"For chain events, blockheight this occured at."
]
},
"origin": {
"type": "string",
"description": [
"The account this movement originated from."
]
},
"payment_id": {
"type": "hex",
"description": [
"Lightning payment identifier. For an htlc, this will be the preimage."
]
},
"txid": {
"type": "txid",
"description": [
"The txid of the transaction that created this event."
]
}
},
"required": [
"outpoint",
"blockheight"
],
"additionalProperties": false
}
},
{
"if": {
"properties": {
"type": {
"type": "string",
"enum": [
"onchain_fee"
]
}
}
},
"then": {
"properties": {
"account": {},
"type": {},
"tag": {},
"credit_msat": {},
"debit_msat": {},
"currency": {},
"timestamp": {},
"description": {},
"txid": {
"type": "txid",
"description": [
"The txid of the transaction that created this event."
]
}
},
"required": [
"txid"
],
"additionalProperties": false
}
},
{
"if": {
"properties": {
"type": {
"type": "string",
"enum": [
"channel"
]
}
}
},
"then": {
"properties": {
"account": {},
"type": {},
"tag": {},
"credit_msat": {},
"debit_msat": {},
"currency": {},
"timestamp": {},
"description": {},
"fees_msat": {
"type": "msat",
"description": [
"Amount paid in fees."
]
},
"is_rebalance": {
"type": "boolean",
"description": [
"Is this payment part of a rebalance."
]
},
"payment_id": {
"type": "hex",
"description": [
"Lightning payment identifier. For an htlc, this will be the preimage."
]
},
"part_id": {
"type": "u32",
"description": [
"Counter for multi-part payments."
]
}
},
"additionalProperties": false
}
}
]
}
}
}
},
"author": [
"Lisa Neigut <<niftynei@gmail.com>> is mainly responsible."
],
"see_also": [
"lightning-bkpr-editdescriptionbypaymentid(7)",
"lightning-bkpr-listaccountevents(7)",
"lightning-bkpr-listincome(7)"
],
"resources": [
"Main web site: <https://github.com/ElementsProject/lightning>"
],
"examples": [
]
}

View file

@ -252,6 +252,7 @@
"Lisa Neigut <<niftynei@gmail.com>> is mainly responsible."
],
"see_also": [
"lightning-bkpr-editdescriptionbyoutpoint(7)",
"lightning-bkpr-listaccountevents(7)",
"lightning-bkpr-listincome(7)"
],

View file

@ -479,6 +479,47 @@ static struct command_result *json_list_account_events(struct command *cmd,
return command_finished(cmd, res);
}
static struct command_result *param_outpoint(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok,
struct bitcoin_outpoint **outp)
{
*outp = tal(cmd, struct bitcoin_outpoint);
if (json_to_outpoint(buffer, tok, *outp))
return NULL;
return command_fail_badparam(cmd, name, buffer, tok,
"should be a txid:outnum");
}
static struct command_result *json_edit_desc_utxo(struct command *cmd,
const char *buf,
const jsmntok_t *params)
{
struct json_stream *res;
struct bitcoin_outpoint *outpoint;
const char *new_desc;
struct chain_event **chain_events;
if (!param(cmd, buf, params,
p_req("identifier", param_outpoint, &outpoint),
p_req("description", param_string, &new_desc),
NULL))
return command_param_failed();
db_begin_transaction(db);
edit_utxo_description(db, outpoint, new_desc);
chain_events = get_chain_events_by_outpoint(cmd, db, outpoint, true);
db_commit_transaction(db);
res = jsonrpc_stream_success(cmd);
json_array_start(res, "updated");
json_add_events(res, NULL, chain_events, NULL);
json_array_end(res);
return command_finished(cmd, res);
}
static struct command_result *json_edit_desc_payment_id(struct command *cmd,
const char *buf,
const jsmntok_t *params)
@ -2031,6 +2072,10 @@ static const struct plugin_command commands[] = {
"bkpr-editdescriptionbypaymentid",
json_edit_desc_payment_id
},
{
"bkpr-editdescriptionbyoutpoint",
json_edit_desc_utxo
},
};
static const char *init(struct command *init_cmd, const char *b, const jsmntok_t *t)

View file

@ -654,6 +654,26 @@ void maybe_mark_account_onchain(struct db *db, struct account *acct)
tal_free(ctx);
}
void edit_utxo_description(struct db *db,
struct bitcoin_outpoint *outpoint,
const char *desc)
{
struct db_stmt *stmt;
/* Ok, now we update the account with this blockheight */
stmt = db_prepare_v2(db, SQL("UPDATE chain_events SET"
" ev_desc = ?"
" WHERE"
" utxo_txid = ?"
" AND outnum = ?"
" AND credit > 0"));
db_bind_text(stmt, desc);
db_bind_txid(stmt, &outpoint->txid);
db_bind_int(stmt, outpoint->n);
db_exec_prepared_v2(take(stmt));
}
void add_payment_hash_desc(struct db *db,
struct sha256 *payment_hash,
const char *desc)
@ -723,6 +743,73 @@ struct chain_event *find_chain_event_by_id(const tal_t *ctx,
return e;
}
struct chain_event **get_chain_events_by_outpoint(const tal_t *ctx,
struct db *db,
const struct bitcoin_outpoint *outpoint,
bool credits_only)
{
struct db_stmt *stmt;
if (credits_only)
stmt = db_prepare_v2(db, SQL("SELECT"
" e.id"
", e.account_id"
", a.name"
", e.origin"
", e.tag"
", e.credit"
", e.debit"
", e.output_value"
", e.currency"
", e.timestamp"
", e.blockheight"
", e.utxo_txid"
", e.outnum"
", e.spending_txid"
", e.payment_id"
", e.ignored"
", e.stealable"
", e.ev_desc"
", e.spliced"
" FROM chain_events e"
" LEFT OUTER JOIN accounts a"
" ON e.account_id = a.id"
" WHERE "
" e.utxo_txid = ?"
" AND e.outnum = ?"
" AND credit > 0"));
else
stmt = db_prepare_v2(db, SQL("SELECT"
" e.id"
", e.account_id"
", a.name"
", e.origin"
", e.tag"
", e.credit"
", e.debit"
", e.output_value"
", e.currency"
", e.timestamp"
", e.blockheight"
", e.utxo_txid"
", e.outnum"
", e.spending_txid"
", e.payment_id"
", e.ignored"
", e.stealable"
", e.ev_desc"
", e.spliced"
" FROM chain_events e"
" LEFT OUTER JOIN accounts a"
" ON e.account_id = a.id"
" WHERE "
" e.utxo_txid = ?"
" AND e.outnum = ?"));
db_bind_txid(stmt, &outpoint->txid);
db_bind_int(stmt, outpoint->n);
return find_chain_events(ctx, take(stmt));
}
struct chain_event **get_chain_events_by_id(const tal_t *ctx,
struct db *db,
const struct sha256 *id)

View file

@ -112,6 +112,12 @@ struct chain_event **get_chain_events_by_id(const tal_t *ctx,
struct db *db,
const struct sha256 *id);
/* Get all chain events for a utxo */
struct chain_event **get_chain_events_by_outpoint(const tal_t *ctx,
struct db *db,
const struct bitcoin_outpoint *outpoint,
bool credits_only);
/* Calculate the balances for an account
*
* @calc_sum - compute the total balance. error if negative
@ -220,6 +226,12 @@ void add_payment_hash_desc(struct db *db,
struct sha256 *payment_hash,
const char *desc);
/* Set the description for all events on this outpoint to
* the provided one */
void edit_utxo_description(struct db *db,
struct bitcoin_outpoint *outpoint,
const char *desc);
/* When we make external deposits from the wallet, we don't
* count them until any output that was spent *into* them is
* confirmed onchain.