wallet: chain_moves and channel_moves tables.
What changed, and why it matters
This commit adds three new database tables to Core Lightning's wallet module: one for account names and two for recording on-chain and off-chain fund movements. It is a straightforward schema migration with no logic changes, no bug fixes, and no security-sensitive operations visible in the diff.
No security action required. Review the new schema as part of normal code review and ensure follow-up commits that populate or query these tables validate inputs appropriately.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch extends wallet/db.c’s migration array with SQL creating move_accounts, chain_moves, and channel_moves tables. These tables store accounting data: move_accounts provides named accounts, chain_moves records on-chain transaction movements (with channel/non-channel account references, tags, amounts, UTXOs, txids, block heights), and channel_moves records off-chain payment movements (payment hashes, part/group IDs, fees). The schema includes foreign-key references to channels and move_accounts, and a comment notes that peer_id intentionally does not reference peers(node_id) because zeroconf channels may be forgotten. No code logic, query execution, or input handling is changed.
Changed components
wallet/db.cmove_accounts tablechain_moves tablechannel_moves tableInspect captured patch +44 / −0
diff --git a/wallet/db.c b/wallet/db.c
index bfed9455..d435b199 100644
--- a/wallet/db.c
+++ b/wallet/db.c
@@ -1045,6 +1045,50 @@ static struct migration dbmigrations[] = {
{SQL("ALTER TABLE channel_funding_inflights ADD i_sent_sigs INTEGER DEFAULT 0"), NULL},
{SQL("ALTER TABLE channels ADD old_scids BLOB DEFAULT NULL;"), NULL},
{NULL, migrate_initialize_alias_local},
+ /* Avoids duplication in chain_moves and coin_moves tables */
+ {SQL("CREATE TABLE move_accounts ("
+ " id BIGSERIAL,"
+ " name TEXT,"
+ " PRIMARY KEY (id),"
+ " UNIQUE (name)"
+ ")"), NULL},
+ {SQL("CREATE TABLE chain_moves ("
+ " id BIGSERIAL,"
+ /* One of these is null */
+ " account_channel_id BIGINT references channels(id),"
+ " account_nonchannel_id BIGINT references move_accounts(id),"
+ " tag_bitmap BIGINT NOT NULL,"
+ " credit_or_debit BIGINT NOT NULL,"
+ " timestamp BIGINT NOT NULL,"
+ " utxo BLOB NOT NULL,"
+ " spending_txid BLOB,"
+ /* This does NOT reference peers(node_id), since we can have
+ * MVT_CHANNEL_PROPOSED events on zeroconf channels where we end up
+ * forgetting the channel, thus the peer */
+ " peer_id BLOB,"
+ " payment_hash BLOB,"
+ " block_height INTEGER NOT NULL,"
+ " output_sat BIGINT NOT NULL,"
+ /* One of these is null */
+ " originating_channel_id BIGINT references channels(id),"
+ " originating_nonchannel_id BIGINT references move_accounts(id),"
+ " output_count INTEGER,"
+ " PRIMARY KEY (id)"
+ ")"), NULL},
+ {SQL("CREATE TABLE channel_moves ("
+ " id BIGSERIAL,"
+ /* One of these is null */
+ " account_channel_id BIGINT references channels(id),"
+ " account_nonchannel_id BIGINT references move_accounts(id),"
+ " tag_bitmap BIGINT NOT NULL,"
+ " credit_or_debit BIGINT NOT NULL,"
+ " timestamp BIGINT NOT NULL,"
+ " payment_hash BLOB,"
+ " payment_part_id BIGINT,"
+ " payment_group_id BIGINT,"
+ " fees BIGINT NOT NULL,"
+ " PRIMARY KEY (id)"
+ ")"), NULL},
};
/**
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.