From 9417549ddb5e6ffb51e668228e6faf8d18937db5 Mon Sep 17 00:00:00 2001 From: pythcoiner Date: Mon, 17 Mar 2025 16:09:11 +0100 Subject: [PATCH] lianad: docs & tests for updatederivationindexes command --- doc/API.md | 33 ++++++++++++- tests/test_rpc.py | 123 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 1 deletion(-) diff --git a/doc/API.md b/doc/API.md index c7f3d754..ead31e98 100644 --- a/doc/API.md +++ b/doc/API.md @@ -9,8 +9,9 @@ Commands must be sent as valid JSONRPC 2.0 requests, ending with a `\n`. | ----------------------------------------------------------- | ---------------------------------------------------- | | [`stop`](#stop) | Stops liana daemon | | [`getinfo`](#getinfo) | Get general information about the daemon | +| [`updatederivationindexes`](#updatederivationindexes) | Update last generated addresses derivation indexes | | [`getnewaddress`](#getnewaddress) | Get a new receiving address | -| [`listaddresses`](#listaddresses) | List addresses given start_index and count | +| [`listaddresses`](#listaddresses) | List addresses given start_index and count | | [`listcoins`](#listcoins) | List all wallet transaction outputs. | | [`createspend`](#createspend) | Create a new Spend transaction | | [`updatespend`](#updatespend) | Store a created Spend transaction | @@ -66,6 +67,36 @@ This command does not take any parameter for now. | `receive_index` | integer | Last index used to generate a receive address | | `change_index` | integer | Last index used to generate a change address | + +### `updatederivationindexes` + +Updates the last generated address derivation indexes in the wallet database. +At least one of the `receive` or `change` arguments is required. + +Derivation indexes **must be unhardened**. If a provided index is lower than +the one currently stored in the database, it will be ignored. + +**Note:** Each time a derivation index in the database is incremented, the +corresponding new addresses must be inserted into the database. To prevent +excessive increments, there is a limit: the derivation index can only be +incremented by a maximum of **1000** from its current value. + +The updated indexes will be returned in the response. + +#### Request + +| Field | Type | Description | +|-----------|-------------------|----------------------------------------------------------| +| `receive` | integer(optional) | The latest receive address derivation index to update | +| `change` | integer(optional) | The latest change address derivation index to update | + +#### Response + +| Field | Type | Description | +|-----------|---------|----------------------------------------------------------| +| `receive` | integer | The updated receive address derivation index | +| `change` | integer | The updated change address derivation index | + ### `getnewaddress` Get a new address for receiving coins. This will always generate a new address regardless of whether diff --git a/tests/test_rpc.py b/tests/test_rpc.py index c46e5a9a..4b7a4a3c 100644 --- a/tests/test_rpc.py +++ b/tests/test_rpc.py @@ -20,6 +20,8 @@ from test_framework.utils import ( USE_TAPROOT, ) +MAX_DERIV = 2**31 - 1 + def test_getinfo(lianad): res = lianad.rpc.getinfo() @@ -40,6 +42,127 @@ def test_getinfo(lianad): assert res["change_index"] == 0 +def test_update_derivation_indexes(lianad): + info = lianad.rpc.getinfo() + assert info["receive_index"] == 0 + assert info["change_index"] == 0 + + ret = lianad.rpc.updatederivationindexes(0, 0) + info = lianad.rpc.getinfo() + assert info["receive_index"] == 0 + assert info["change_index"] == 0 + assert ret["receive"] == 0 + assert ret["change"] == 0 + + ret = lianad.rpc.updatederivationindexes(receive=3) + info = lianad.rpc.getinfo() + assert info["receive_index"] == 3 + assert info["change_index"] == 0 + assert ret["receive"] == 3 + assert ret["change"] == 0 + + ret = lianad.rpc.updatederivationindexes(change=4) + info = lianad.rpc.getinfo() + assert info["receive_index"] == 3 + assert info["change_index"] == 4 + assert ret["receive"] == 3 + assert ret["change"] == 4 + + ret = lianad.rpc.updatederivationindexes(receive=1, change=2) + info = lianad.rpc.getinfo() + assert info["receive_index"] == 3 + assert info["change_index"] == 4 + assert ret["receive"] == 3 + assert ret["change"] == 4 + + ret = lianad.rpc.updatederivationindexes(5, 6) + info = lianad.rpc.getinfo() + assert info["receive_index"] == 5 + assert info["change_index"] == 6 + assert ret["receive"] == 5 + assert ret["change"] == 6 + + ret = lianad.rpc.updatederivationindexes(0, 0) + info = lianad.rpc.getinfo() + assert info["receive_index"] == 5 + assert info["change_index"] == 6 + assert ret["receive"] == 5 + assert ret["change"] == 6 + + # Will explicitly error on invalid indexes + with pytest.raises( + RpcError, + match=re.escape( + "Invalid params: Invalid value for \'receive\' param" + ), + ): + lianad.rpc.updatederivationindexes(-1) + + with pytest.raises( + RpcError, + match=re.escape( + "Invalid params: Invalid value for \'change\' param" + ), + ): + lianad.rpc.updatederivationindexes(0, -1) + + with pytest.raises( + RpcError, + match=re.escape( + "Unhardened or overflowing BIP32 derivation index." + ), + ): + lianad.rpc.updatederivationindexes(MAX_DERIV + 1, 2) + + with pytest.raises( + RpcError, + match=re.escape( + "Unhardened or overflowing BIP32 derivation index." + ), + ): + lianad.rpc.updatederivationindexes(0, MAX_DERIV + 1) + + with pytest.raises( + RpcError, + match=re.escape( + "Unhardened or overflowing BIP32 derivation index." + ), + ): + lianad.rpc.updatederivationindexes(receive=(MAX_DERIV+1)) + + with pytest.raises( + RpcError, + match=re.escape( + "Unhardened or overflowing BIP32 derivation index." + ), + ): + lianad.rpc.updatederivationindexes(change=(MAX_DERIV+1)) + + with pytest.raises( + RpcError, + match=re.escape( + "Invalid params: Missing \'receive\' or \'change\' parameter" + ), + ): + lianad.rpc.updatederivationindexes() + + last_derivs = lianad.rpc.updatederivationindexes(0, 0) + last_receive = last_derivs["receive"] + last_change = last_derivs["change"] + + ret = lianad.rpc.updatederivationindexes(0, (MAX_DERIV - 1)) + assert ret["receive"] == last_receive + assert ret["change"] == last_change + 1000 + + last_derivs = lianad.rpc.updatederivationindexes(0, 0) + last_receive = last_derivs["receive"] + last_change = last_derivs["change"] + + ret = lianad.rpc.updatederivationindexes((MAX_DERIV -1 ), 0) + assert ret["receive"] == last_receive + 1000 + assert ret["change"] == last_change + + def test_getaddress(lianad): res = lianad.rpc.getnewaddress() assert "address" in res