diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh index 1037cc97d8aa..698c1c7f7c81 100755 --- a/.github/scripts/build.sh +++ b/.github/scripts/build.sh @@ -7,7 +7,6 @@ export CC=${COMPILER:-gcc} export COMPAT=${COMPAT:-1} export TEST_CHECK_DBSTMTS=${TEST_CHECK_DBSTMTS:-0} export DEVELOPER=${DEVELOPER:-1} -export EXPERIMENTAL_FEATURES=${EXPERIMENTAL_FEATURES:-0} export PATH=$CWD/dependencies/bin:"$HOME"/.local/bin:"$PATH" export PYTEST_OPTS="--maxfail=5 --suppress-no-test-exit-code ${PYTEST_OPTS}" export PYTEST_PAR=${PYTEST_PAR:-10} @@ -80,16 +79,6 @@ then rm sqlite-src-3260000.zip rm -rf sqlite-src-3260000 - wget -q https://gmplib.org/download/gmp/gmp-6.1.2.tar.xz - tar xf gmp-6.1.2.tar.xz - cd gmp-6.1.2 || exit 1 - ./configure --disable-assembly --prefix="$QEMU_LD_PREFIX" --host="$TARGET_HOST" - make - sudo make install - cd .. - rm gmp-6.1.2.tar.xz - rm -rf gmp-6.1.2 - ./configure CC="$TARGET_HOST-gcc" --enable-static make -s -j32 CC="$TARGET_HOST-gcc" diff --git a/.github/scripts/install-bitcoind.sh b/.github/scripts/install-bitcoind.sh index b2734644044f..3059f8433c67 100755 --- a/.github/scripts/install-bitcoind.sh +++ b/.github/scripts/install-bitcoind.sh @@ -4,14 +4,14 @@ set -e DIRNAME="bitcoin-${BITCOIN_VERSION}" EDIRNAME="elements-${ELEMENTS_VERSION}" -FILENAME="${DIRNAME}-x86_64-linux-gnu.tar.bz2" -EFILENAME="${EDIRNAME}-x86_64-linux-gnu.tar.bz2" +FILENAME="${DIRNAME}-x86_64-linux-gnu.tar.gz" +EFILENAME="${EDIRNAME}-x86_64-linux-gnu.tar.gz" cd /tmp/ -wget "https://storage.googleapis.com/c-lightning-tests/$FILENAME" -wget -q "https://storage.googleapis.com/c-lightning-tests/${EFILENAME}" -tar -xaf "${FILENAME}" -tar -xaf "${EFILENAME}" +wget "https://bitcoincore.org/bin/bitcoin-core-${BITCOIN_VERSION}/${FILENAME}" +wget "https://github.com/ElementsProject/elements/releases/download/elements-${ELEMENTS_VERSION}/${EFILENAME}" +tar -xf "${FILENAME}" +tar -xf "${EFILENAME}" sudo mv "${DIRNAME}"/bin/* "/usr/local/bin" sudo mv "${EDIRNAME}"/bin/* "/usr/local/bin" diff --git a/.github/scripts/setup.sh b/.github/scripts/setup.sh index b1b4f252f138..146437a7f9c7 100755 --- a/.github/scripts/setup.sh +++ b/.github/scripts/setup.sh @@ -1,8 +1,8 @@ #!/bin/bash set -e export DEBIAN_FRONTEND=noninteractive -export BITCOIN_VERSION=0.20.1 -export ELEMENTS_VERSION=0.18.1.8 +export BITCOIN_VERSION=25.0 +export ELEMENTS_VERSION=22.0.2 export RUST_VERSION=stable sudo useradd -ms /bin/bash tester @@ -24,7 +24,6 @@ sudo apt-get -qq install --no-install-recommends --allow-unauthenticated -yy \ git \ libc6-dev-arm64-cross \ libc6-dev-armhf-cross \ - libgmp-dev \ libpq-dev \ libprotobuf-c-dev \ libsqlite3-dev \ @@ -56,17 +55,17 @@ sudo chmod 0440 /etc/sudoers.d/tester ( cd /tmp/ || exit 1 - wget https://storage.googleapis.com/c-lightning-tests/bitcoin-$BITCOIN_VERSION-x86_64-linux-gnu.tar.bz2 - wget -q https://storage.googleapis.com/c-lightning-tests/elements-$ELEMENTS_VERSION-x86_64-linux-gnu.tar.bz2 - tar -xjf bitcoin-$BITCOIN_VERSION-x86_64-linux-gnu.tar.bz2 - tar -xjf elements-$ELEMENTS_VERSION-x86_64-linux-gnu.tar.bz2 - sudo mv bitcoin-$BITCOIN_VERSION/bin/* /usr/local/bin - sudo mv elements-$ELEMENTS_VERSION/bin/* /usr/local/bin + wget https://bitcoincore.org/bin/bitcoin-core-${BITCOIN_VERSION}/bitcoin-${BITCOIN_VERSION}-x86_64-linux-gnu.tar.gz + wget https://github.com/ElementsProject/elements/releases/download/elements-${ELEMENTS_VERSION}/elements-${ELEMENTS_VERSION}-x86_64-linux-gnu.tar.gz + tar -xf bitcoin-${BITCOIN_VERSION}-x86_64-linux-gnu.tar.gz + tar -xf elements-${ELEMENTS_VERSION}-x86_64-linux-gnu.tar.gz + sudo mv bitcoin-${BITCOIN_VERSION}/bin/* /usr/local/bin + sudo mv elements-${ELEMENTS_VERSION}/bin/* /usr/local/bin rm -rf \ - bitcoin-$BITCOIN_VERSION-x86_64-linux-gnu.tar.gz \ - bitcoin-$BITCOIN_VERSION \ - elements-$ELEMENTS_VERSION-x86_64-linux-gnu.tar.bz2 \ - elements-$ELEMENTS_VERSION + bitcoin-${BITCOIN_VERSION}-x86_64-linux-gnu.tar.gz \ + bitcoin-${BITCOIN_VERSION} \ + elements-${ELEMENTS_VERSION}-x86_64-linux-gnu.tar.gz \ + elements-${ELEMENTS_VERSION} ) curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- \ @@ -82,4 +81,4 @@ sudo chmod a+x /usr/local/bin/protoc export PROTOC=/usr/local/bin/protoc export PATH=$PATH:/usr/local/bin env -ls -lha /usr/local/bin \ No newline at end of file +ls -lha /usr/local/bin diff --git a/.github/workflows/bsd.yml b/.github/workflows/bsd.yml index fee739519814..bc19d754c8ac 100644 --- a/.github/workflows/bsd.yml +++ b/.github/workflows/bsd.yml @@ -10,10 +10,10 @@ jobs: testfreebsd: runs-on: macos-10.15 name: Build and test on FreeBSD + timeout-minutes: 120 env: DEVELOPER: 1 VALGRIND: 0 - EXPERIMENTAL_FEATURES: 0 COMPAT: 1 steps: - uses: actions/checkout@v2 @@ -21,7 +21,7 @@ jobs: id: test uses: vmactions/freebsd-vm@v0.1.5 with: - envs: 'DEVELOPER VALGRIND EXPERIMENTAL_FEATURES COMPAT' + envs: 'DEVELOPER VALGRIND COMPAT' usesh: true prepare: | pkg install -y \ @@ -35,7 +35,6 @@ jobs: autoconf \ automake \ libtool \ - gmp \ bash \ gettext \ sqlite3 \ @@ -45,12 +44,12 @@ jobs: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly-2021-08-3z1 cd /tmp/ || exit 1 - wget https://storage.googleapis.com/c-lightning-tests/bitcoin-0.20.1-x86_64-linux-gnu.tar.bz2 - tar -xjf bitcoin-0.20.1-x86_64-linux-gnu.tar.bz2 - sudo mv bitcoin-0.20.1/bin/* /usr/local/bin + wget https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-x86_64-linux-gnu.tar.gz + tar -xf bitcoin-25.0-x86_64-linux-gnu.tar.bz2 + sudo mv bitcoin-25.0/bin/* /usr/local/bin rm -rf \ - bitcoin-0.20.1-x86_64-linux-gnu.tar.gz \ - bitcoin-0.20.1 + bitcoin-25.0-x86_64-linux-gnu.tar.gz \ + bitcoin-25.0 run: | PATH=/root/.local/bin:$PATH diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 672923dec1e3..eec3ee1a6174 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -20,6 +20,7 @@ jobs: prebuild: name: Pre-build checks runs-on: ubuntu-20.04 + timeout-minutes: 30 env: RUST: 1 COMPAT: 1 @@ -29,6 +30,16 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + + - name: Rebase + run: | + git config user.name github-actions + git config user.email github-actions@github.com + git fetch origin ${{ github.base_ref }} + git rebase origin/${{ github.base_ref }} - name: Set up Python 3.7 uses: actions/setup-python@v4 @@ -47,7 +58,7 @@ jobs: - name: Configure run: ./configure - name: Check source - run: make -j 4 check-source + run: make -j 4 check-source BASE_REF="origin/${{ github.base_ref }}" - name: Check Generated Files have been updated run: make -j 4 check-gen-updated - name: Check docs @@ -58,6 +69,7 @@ jobs: # on the integration tests), so run them with `valgrind` name: Run unit tests runs-on: ubuntu-22.04 + timeout-minutes: 30 env: COMPAT: 1 VALGRIND: 1 @@ -89,9 +101,77 @@ jobs: ./configure make -j $(nproc) check-units installcheck + check-units-sanitizers: + name: Run unit tests with ASan and UBSan + runs-on: ubuntu-22.04 + timeout-minutes: 30 + env: + COMPAT: 1 + ASAN: 1 + UBSAN: 1 + VALGRIND: 0 + needs: + - prebuild + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Python 3.7 + uses: actions/setup-python@v4 + with: + python-version: 3.7 + + - name: Install dependencies + run: | + bash -x .github/scripts/setup.sh + sudo apt-get install -y -qq lowdown + pip install -U pip wheel poetry + # Export and then use pip to install into the current env + poetry export -o /tmp/requirements.txt --without-hashes --with dev + pip install -r /tmp/requirements.txt + + - name: Build + run: | + ./configure CC=clang + make -j $(nproc) check-units installcheck + + check-fuzz: + name: Run fuzz regression tests + runs-on: ubuntu-22.04 + env: + COMPAT: 1 + DEVELOPER: 1 + ASAN: 1 + UBSAN: 1 + VALGRIND: 0 + needs: + - prebuild + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Python 3.7 + uses: actions/setup-python@v4 + with: + python-version: 3.7 + + - name: Install dependencies + run: | + bash -x .github/scripts/setup.sh + pip install -U pip wheel poetry + # Export and then use pip to install into the current env + poetry export -o /tmp/requirements.txt --without-hashes --with dev + pip install -r /tmp/requirements.txt + + - name: Build + run: | + ./configure --enable-fuzzing CC=clang + make -j $(nproc) check-fuzz + compile: name: Compile CLN ${{ matrix.cfg }} runs-on: ubuntu-22.04 + timeout-minutes: 30 env: COMPAT: 1 needs: @@ -100,26 +180,15 @@ jobs: fail-fast: true matrix: include: - - CFG: gcc-dev1-exp1 - DEVELOPER: 1 - EXPERIMENTAL_FEATURES: 1 - COMPILER: gcc - - CFG: gcc-dev1-exp0 + - CFG: gcc-dev1 DEVELOPER: 1 - EXPERIMENTAL_FEATURES: 0 COMPILER: gcc - - CFG: gcc-dev0-exp1 + - CFG: gcc-dev0 DEVELOPER: 0 - EXPERIMENTAL_FEATURES: 1 - COMPILER: gcc - - CFG: gcc-dev0-exp0 - DEVELOPER: 0 - EXPERIMENTAL_FEATURES: 0 COMPILER: gcc # While we're at it let's try to compile with clang - - CFG: clang-dev1-exp1 + - CFG: clang-dev1 DEVELOPER: 1 - EXPERIMENTAL_FEATURES: 1 COMPILER: clang steps: - name: Checkout @@ -138,7 +207,6 @@ jobs: env: VALGRIND: ${{ matrix.VALGRIND }} DEVELOPER: ${{ matrix.DEVELOPER }} - EXPERIMENTAL_FEATURES: ${{ matrix.EXPERIMENTAL_FEATURES }} COMPILER: ${{ matrix.COMPILER }} COMPAT: 1 CFG: ${{ matrix.CFG }} @@ -153,6 +221,8 @@ jobs: # Rename now so we don't clash mv testpack.tar.bz2 cln-${CFG}.tar.bz2 + - name: Check rust packages + run: cargo test --all - uses: actions/upload-artifact@v2.2.4 with: name: cln-${{ matrix.CFG }}.tar.bz2 @@ -161,56 +231,61 @@ jobs: integration: name: Test CLN ${{ matrix.name }} runs-on: ubuntu-22.04 + timeout-minutes: 120 env: COMPAT: 1 - BITCOIN_VERSION: 0.20.1 - ELEMENTS_VERSION: 0.18.1.8 + BITCOIN_VERSION: "25.0" + ELEMENTS_VERSION: 22.0.2 RUST_PROFILE: release # Has to match the one in the compile step + PYTEST_OPTS: --timeout=1200 needs: - compile strategy: fail-fast: true matrix: include: - - NAME: gcc-dev1-exp1 - CFG: gcc-dev1-exp1 + - NAME: gcc-dev1 + CFG: gcc-dev1 DEVELOPER: 1 - EXPERIMENTAL_FEATURES: 1 TEST_DB_PROVIDER: sqlite3 COMPILER: gcc - - NAME: gcc-dev1-exp0 - CFG: gcc-dev1-exp0 - DEVELOPER: 1 - EXPERIMENTAL_FEATURES: 0 - TEST_DB_PROVIDER: sqlite3 - COMPILER: gcc - - NAME: gcc-dev0-exp1 - CFG: gcc-dev0-exp1 - DEVELOPER: 0 - EXPERIMENTAL_FEATURES: 1 - TEST_DB_PROVIDER: sqlite3 - COMPILER: gcc - - NAME: gcc-dev0-exp0 - CFG: gcc-dev0-exp0 + TEST_NETWORK: regtest + - NAME: gcc-dev0 + CFG: gcc-dev0 DEVELOPER: 0 - EXPERIMENTAL_FEATURES: 0 TEST_DB_PROVIDER: sqlite3 COMPILER: gcc + TEST_NETWORK: regtest # While we're at it let's try to compile with clang - - NAME: clang-dev1-exp1 - CFG: clang-dev1-exp1 + - NAME: clang-dev1 + CFG: clang-dev1 DEVELOPER: 1 - EXPERIMENTAL_FEATURES: 1 TEST_DB_PROVIDER: sqlite3 COMPILER: clang + TEST_NETWORK: regtest # And of course we want to test postgres too - NAME: postgres - CFG: gcc-dev1-exp1 + CFG: gcc-dev1 DEVELOPER: 1 - EXPERIMENTAL_FEATURES: 1 COMPILER: gcc TEST_DB_PROVIDER: postgres - + TEST_NETWORK: regtest + # And don't forget about elements (like cdecker did when + # reworking the CI...) + - NAME: liquid + CFG: gcc-dev1 + DEVELOPER: 1 + COMPILER: gcc + TEST_NETWORK: liquid-regtest + TEST_DB_PROVIDER: sqlite3 + # And dual funding! + - NAME: dual-fund + CFG: gcc-dev1 + TEST_DB_PROVIDER: sqlite3 + COMPILER: gcc + TEST_NETWORK: regtest + DEVELOPER: 1 + EXPERIMENTAL_DUAL_FUND: 1 steps: - name: Checkout uses: actions/checkout@v3 @@ -237,14 +312,15 @@ jobs: env: VALGRIND: ${{ matrix.VALGRIND }} DEVELOPER: ${{ matrix.DEVELOPER }} - EXPERIMENTAL_FEATURES: ${{ matrix.EXPERIMENTAL_FEATURES }} COMPILER: ${{ matrix.COMPILER }} + EXPERIMENTAL_DUAL_FUND: ${{ matrix.EXPERIMENTAL_DUAL_FUND }} COMPAT: 1 CFG: ${{ matrix.CFG }} SLOW_MACHINE: 1 PYTEST_PAR: 10 TEST_DEBUG: 1 TEST_DB_PROVIDER: ${{ matrix.TEST_DB_PROVIDER }} + TEST_NETWORK: ${{ matrix.TEST_NETWORK }} run: | tar -xaf cln-${CFG}.tar.bz2 poetry run pytest tests/ -vvv -n ${PYTEST_PAR} ${PYTEST_OPTS} @@ -252,16 +328,16 @@ jobs: integration-valgrind: name: Valgrind Test CLN ${{ matrix.name }} runs-on: ubuntu-22.04 + timeout-minutes: 120 env: COMPAT: 1 - BITCOIN_VERSION: 0.20.1 - ELEMENTS_VERSION: 0.18.1.8 + BITCOIN_VERSION: "25.0" + ELEMENTS_VERSION: 22.0.2 RUST_PROFILE: release # Has to match the one in the compile step VALGRIND: 1 - CFG: gcc-dev1-exp1 + CFG: gcc-dev1 DEVELOPER: 1 - EXPERIMENTAL_FEATURES: 1 - PYTEST_OPTS: --test-group-random-seed=42 + PYTEST_OPTS: --test-group-random-seed=42 --timeout=1800 needs: - compile strategy: @@ -309,10 +385,10 @@ jobs: - name: Download build uses: actions/download-artifact@v3 with: - name: cln-gcc-dev1-exp1.tar.bz2 + name: cln-gcc-dev1.tar.bz2 - name: Unpack build - run: tar -xvjf cln-gcc-dev1-exp1.tar.bz2 + run: tar -xvjf cln-gcc-dev1.tar.bz2 - name: Test env: @@ -324,6 +400,78 @@ jobs: sed -i 's/VALGRIND=0/VALGRIND=1/g' config.vars poetry run pytest tests/ -vvv -n 3 ${PYTEST_OPTS} ${{ matrix.PYTEST_OPTS }} + integration-sanitizers: + name: Sanitizers Test CLN + runs-on: ubuntu-22.04 + timeout-minutes: 120 + env: + COMPAT: 1 + BITCOIN_VERSION: "25.0" + ELEMENTS_VERSION: 22.0.2 + RUST_PROFILE: release + ASAN: 1 + UBSAN: 1 + VALGRIND: 0 + DEVELOPER: 1 + SLOW_MACHINE: 1 + TEST_DEBUG: 1 + PYTEST_OPTS: --test-group-random-seed=42 --timeout=1800 + needs: + - prebuild + strategy: + fail-fast: true + matrix: + include: + - NAME: ASan/UBSan (01/10) + PYTEST_OPTS: --test-group=1 --test-group-count=10 + - NAME: ASan/UBSan (02/10) + PYTEST_OPTS: --test-group=2 --test-group-count=10 + - NAME: ASan/UBSan (03/10) + PYTEST_OPTS: --test-group=3 --test-group-count=10 + - NAME: ASan/UBSan (04/10) + PYTEST_OPTS: --test-group=4 --test-group-count=10 + - NAME: ASan/UBSan (05/10) + PYTEST_OPTS: --test-group=5 --test-group-count=10 + - NAME: ASan/UBSan (06/10) + PYTEST_OPTS: --test-group=6 --test-group-count=10 + - NAME: ASan/UBSan (07/10) + PYTEST_OPTS: --test-group=7 --test-group-count=10 + - NAME: ASan/UBSan (08/10) + PYTEST_OPTS: --test-group=8 --test-group-count=10 + - NAME: ASan/UBSan (09/10) + PYTEST_OPTS: --test-group=9 --test-group-count=10 + - NAME: ASan/UBSan (10/10) + PYTEST_OPTS: --test-group=10 --test-group-count=10 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Python 3.7 + uses: actions/setup-python@v4 + with: + python-version: 3.7 + + - name: Install dependencies + run: | + bash -x .github/scripts/setup.sh + set -e + pip3 install --user pip wheel poetry + poetry export -o requirements.txt --with dev --without-hashes + python3 -m pip install -r requirements.txt + poetry install + + - name: Install bitcoind + run: .github/scripts/install-bitcoind.sh + + - name: Build + run: | + ./configure CC=clang + make -j $(nproc) + + - name: Test + run: | + poetry run pytest tests/ -vvv -n 3 ${PYTEST_OPTS} ${{ matrix.PYTEST_OPTS }} + gather: # A dummy task that depends on the full matrix of tests, and # signals successful completion. Used for the PR status to pass diff --git a/.github/workflows/ci_build.yml b/.github/workflows/ci_build.yml index 7683c539d4ae..71e51cabb837 100644 --- a/.github/workflows/ci_build.yml +++ b/.github/workflows/ci_build.yml @@ -5,6 +5,7 @@ on: [push, pull_request] jobs: test: runs-on: ubuntu-latest + timeout-minutes: 120 strategy: fail-fast: false matrix: diff --git a/.github/workflows/macos.yaml b/.github/workflows/macos.yaml index bb8157bcfcac..9fea1e6ebbd3 100644 --- a/.github/workflows/macos.yaml +++ b/.github/workflows/macos.yaml @@ -6,10 +6,10 @@ jobs: smoke-test: name: Smoke Test macOS runs-on: macos-latest + timeout-minutes: 120 env: DEVELOPER: 1 VALGRIND: 0 - EXPERIMENTAL_FEATURES: 1 COMPAT: 0 strategy: fail-fast: true @@ -21,8 +21,8 @@ jobs: run: | export PATH="/usr/local/opt:/Users/runner/.local/bin:/Users/runner/Library/Python/3.10/bin:$PATH" - export BITCOIN_VERSION=0.20.1 - brew install wget autoconf automake libtool python@3.10 gmp gnu-sed gettext libsodium + export BITCOIN_VERSION=25.0 + brew install wget autoconf automake libtool python@3.10 gnu-sed gettext libsodium ( cd /tmp/ @@ -41,7 +41,6 @@ jobs: env: VALGRIND: ${{ matrix.VALGRIND }} DEVELOPER: ${{ matrix.DEVELOPER }} - EXPERIMENTAL_FEATURES: ${{ matrix.EXPERIMENTAL_FEATURES }} COMPILER: ${{ matrix.COMPILER }} COMPAT: ${{ matrix.COMPAT }} PYTEST_PAR: ${{ matrix.PYTEST_PAR }} diff --git a/.github/workflows/prototest.yaml b/.github/workflows/prototest.yaml index dc2461d07c7e..786e24375f4f 100644 --- a/.github/workflows/prototest.yaml +++ b/.github/workflows/prototest.yaml @@ -9,7 +9,7 @@ jobs: proto-test: name: Protocol Test Config runs-on: ubuntu-22.04 - timeout-minutes: 300 + timeout-minutes: 120 strategy: fail-fast: true matrix: @@ -29,7 +29,6 @@ jobs: -e TARGET_HOST=${{ matrix.TARGET_HOST }} \ -e VALGRIND=${{ matrix.valgrind }} \ -e DEVELOPER=1 \ - -e EXPERIMENTAL_FEATURES=1 \ -e COMPAT=0 \ -e PYTEST_PAR=2 \ -e PYTEST_OPTS="--timeout=300" \ diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 3362867d9766..115a4fc28e33 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -14,6 +14,7 @@ jobs: deploy: name: Build and publish ${{ matrix.package }} 🐍 runs-on: ubuntu-20.04 + timeout-minutes: 120 strategy: fail-fast: true matrix: diff --git a/.github/workflows/rdme-docs-sync.yml b/.github/workflows/rdme-docs-sync.yml new file mode 100644 index 000000000000..826f104f83ac --- /dev/null +++ b/.github/workflows/rdme-docs-sync.yml @@ -0,0 +1,23 @@ +# This GitHub Actions workflow was auto-generated by the `rdme` cli on 2023-04-22T13:16:28.430Z +# You can view our full documentation here: https://docs.readme.com/docs/rdme +name: ReadMe GitHub Action 🦉 + +on: + push: + branches: + # This workflow will run every time you push code to the following branch: `master` + # Check out GitHub's docs for more info on configuring this: + # https://docs.github.com/actions/using-workflows/events-that-trigger-workflows + - master + +jobs: + rdme-docs: + runs-on: ubuntu-latest + steps: + - name: Check out repo 📚 + uses: actions/checkout@v3 + + - name: Run `docs` command 🚀 + uses: readmeio/rdme@v8 + with: + rdme: docs guides/ --key=${{ secrets.README_API_KEY }} --version=23.02 diff --git a/.gitignore b/.gitignore index 4c75b538d175..8d2e96ec68db 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,7 @@ bionic/ focal/ jammy/ release/ +.vscode/ + +# Ignore release verification Sha256Sums +SHA256SUMS-* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 52d90feb6b59..6e01161c764e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,7 +10,7 @@ build: curl -s -H "Authorization: token $GITHUB_STATUS_TOKEN" -X POST --data '{"state": "pending", "description": "Gitlab-CI is building the commit", "context": "gitlab-ci"}' - https://api.github.com/repos/ElementsProject/lightning/statuses/$CI_BUILD_REF || true + https://api.github.com/repos/ElementsProject/lightning/statuses/$CI_COMMIT_SHA || true script: - make - make -j 12 check @@ -27,7 +27,7 @@ update-status-fail: when: on_failure script: - >- - curl -s -H "Authorization: token $GITHUB_STATUS_TOKEN" -X POST --data '{"state": "failure", "description": "Gitlab-CI build failed, please contact @cdecker for details about build #$CI_BUILD_ID.", "context": "gitlab-ci"}' https://api.github.com/repos/ElementsProject/lightning/statuses/$CI_BUILD_REF || true + curl -s -H "Authorization: token $GITHUB_STATUS_TOKEN" -X POST --data '{"state": "failure", "description": "Gitlab-CI build failed, please contact @cdecker for details about build #$CI_JOB_ID.", "context": "gitlab-ci"}' https://api.github.com/repos/ElementsProject/lightning/statuses/$CI_COMMIT_SHA || true update-status-success: image: tutum/curl @@ -35,4 +35,4 @@ update-status-success: when: on_success script: - >- - curl -s -H "Authorization: token $GITHUB_STATUS_TOKEN" -X POST --data '{"state": "success", "description": "Gitlab-CI build succeeded.", "context": "gitlab-ci"}' https://api.github.com/repos/ElementsProject/lightning/statuses/$CI_BUILD_REF || true + curl -s -H "Authorization: token $GITHUB_STATUS_TOKEN" -X POST --data '{"state": "success", "description": "Gitlab-CI build succeeded.", "context": "gitlab-ci"}' https://api.github.com/repos/ElementsProject/lightning/statuses/$CI_COMMIT_SHA || true diff --git a/.gitmodules b/.gitmodules index 743f3a4c4375..6dae35a54444 100644 --- a/.gitmodules +++ b/.gitmodules @@ -17,7 +17,6 @@ [submodule "external/lnprototest"] path = external/lnprototest url = https://github.com/rustyrussell/lnprototest.git - branch = nifty/ripemd160-fallback [submodule "external/lowdown"] path = external/lowdown url = https://github.com/kristapsdz/lowdown.git diff --git a/.msggen.json b/.msggen.json index 311d64ee04d9..c9b81b5de838 100644 --- a/.msggen.json +++ b/.msggen.json @@ -28,6 +28,19 @@ "must-create": 0, "must-replace": 1 }, + "DecodeType": { + "bolt11 invoice": 3, + "bolt12 invoice": 1, + "bolt12 invoice_request": 2, + "bolt12 offer": 0, + "rune": 4 + }, + "DecodepayFallbacksType": { + "P2PKH": 0, + "P2SH": 1, + "P2WPKH": 2, + "P2WSH": 3 + }, "DelinvoiceStatus": { "expired": 1, "paid": 0, @@ -50,7 +63,8 @@ "ipv6": 2, "local socket": 0, "torv2": 3, - "torv3": 4 + "torv3": 4, + "websocket": 5 }, "GetrouteRouteStyle": { "tlv": 0 @@ -58,6 +72,14 @@ "KeysendStatus": { "complete": 0 }, + "ListclosedchannelsClosedchannelsClose_cause": { + "local": 1, + "onchain": 5, + "protocol": 4, + "remote": 3, + "unknown": 0, + "user": 2 + }, "ListforwardsForwardsStatus": { "failed": 3, "local_failed": 2, @@ -103,6 +125,77 @@ "failed": 2, "pending": 0 }, + "ListpeerchannelsChannelsCloser": { + "local": 0, + "remote": 1 + }, + "ListpeerchannelsChannelsHtlcsDirection": { + "in": 0, + "out": 1 + }, + "ListpeerchannelsChannelsHtlcsState": { + "RCVD_ADD_ACK_COMMIT": 3, + "RCVD_ADD_REVOCATION": 2, + "RCVD_REMOVE_ACK_REVOCATION": 9, + "RCVD_REMOVE_COMMIT": 6, + "RCVD_REMOVE_HTLC": 5, + "SENT_ADD_ACK_REVOCATION": 4, + "SENT_ADD_COMMIT": 1, + "SENT_ADD_HTLC": 0, + "SENT_REMOVE_ACK_COMMIT": 8, + "SENT_REMOVE_REVOCATION": 7 + }, + "ListpeerchannelsChannelsOpener": { + "local": 0, + "remote": 1 + }, + "ListpeerchannelsChannelsState": { + "AWAITING_UNILATERAL": 6, + "CHANNELD_AWAITING_LOCKIN": 1, + "CHANNELD_NORMAL": 2, + "CHANNELD_SHUTTING_DOWN": 3, + "CLOSINGD_COMPLETE": 5, + "CLOSINGD_SIGEXCHANGE": 4, + "DUALOPEND_AWAITING_LOCKIN": 10, + "DUALOPEND_OPEN_INIT": 9, + "FUNDING_SPEND_SEEN": 7, + "ONCHAIN": 8, + "OPENINGD": 0 + }, + "ListpeerchannelsChannelsState_changesCause": { + "local": 1, + "onchain": 5, + "protocol": 4, + "remote": 3, + "unknown": 0, + "user": 2 + }, + "ListpeerchannelsChannelsState_changesNew_state": { + "AWAITING_UNILATERAL": 6, + "CHANNELD_AWAITING_LOCKIN": 1, + "CHANNELD_NORMAL": 2, + "CHANNELD_SHUTTING_DOWN": 3, + "CLOSINGD_COMPLETE": 5, + "CLOSINGD_SIGEXCHANGE": 4, + "DUALOPEND_AWAITING_LOCKIN": 10, + "DUALOPEND_OPEN_INIT": 9, + "FUNDING_SPEND_SEEN": 7, + "ONCHAIN": 8, + "OPENINGD": 0 + }, + "ListpeerchannelsChannelsState_changesOld_state": { + "AWAITING_UNILATERAL": 6, + "CHANNELD_AWAITING_LOCKIN": 1, + "CHANNELD_NORMAL": 2, + "CHANNELD_SHUTTING_DOWN": 3, + "CLOSINGD_COMPLETE": 5, + "CLOSINGD_SIGEXCHANGE": 4, + "DUALOPEND_AWAITING_LOCKIN": 10, + "DUALOPEND_OPEN_INIT": 9, + "FUNDING_SPEND_SEEN": 7, + "ONCHAIN": 8, + "OPENINGD": 0 + }, "ListpeersPeersChannelsHtlcsDirection": { "in": 0, "out": 1 @@ -311,6 +404,147 @@ "Datastore.key[]": 1, "Datastore.string": 4 }, + "DecodeExtra": { + "Decode.extra[].data": 2, + "Decode.extra[].tag": 1 + }, + "DecodeFallbacks": { + "Decode.fallbacks[].warning_invoice_fallbacks_version_invalid": 1 + }, + "DecodeInvoice_fallbacks": { + "Decode.invoice_fallbacks[].address": 3, + "Decode.invoice_fallbacks[].hex": 2, + "Decode.invoice_fallbacks[].version": 1 + }, + "DecodeInvoice_pathsPath": { + "Decode.invoice_paths[].path[].blinded_node_id": 1, + "Decode.invoice_paths[].path[].encrypted_recipient_data": 2 + }, + "DecodeOffer_paths": { + "Decode.offer_paths[].blinding": 2, + "Decode.offer_paths[].first_node_id": 1, + "Decode.offer_paths[].path[]": 3 + }, + "DecodeOffer_recurrencePaywindow": { + "Decode.offer_recurrence.paywindow.proportional_amount": 3, + "Decode.offer_recurrence.paywindow.seconds_after": 2, + "Decode.offer_recurrence.paywindow.seconds_before": 1 + }, + "DecodeRequest": { + "Decode.string": 1 + }, + "DecodeResponse": { + "Decode.created_at": 60, + "Decode.currency_minor_unit": 8, + "Decode.description_hash": 64, + "Decode.expiry": 61, + "Decode.extra[]": 69, + "Decode.fallbacks[]": 59, + "Decode.hex": 75, + "Decode.invoice_amount_msat": 44, + "Decode.invoice_created_at": 41, + "Decode.invoice_fallbacks[]": 45, + "Decode.invoice_features": 46, + "Decode.invoice_node_id": 47, + "Decode.invoice_paths[]": 40, + "Decode.invoice_payment_hash": 43, + "Decode.invoice_recurrence_basetime": 48, + "Decode.invoice_relative_expiry": 42, + "Decode.invreq_amount_msat": 28, + "Decode.invreq_chain": 27, + "Decode.invreq_features": 29, + "Decode.invreq_metadata": 25, + "Decode.invreq_payer_id": 26, + "Decode.invreq_payer_note": 31, + "Decode.invreq_quantity": 30, + "Decode.invreq_recurrence_counter": 32, + "Decode.invreq_recurrence_start": 33, + "Decode.min_final_cltv_expiry": 65, + "Decode.offer_absolute_expiry": 14, + "Decode.offer_amount": 9, + "Decode.offer_amount_msat": 10, + "Decode.offer_chains[]": 4, + "Decode.offer_currency": 6, + "Decode.offer_description": 11, + "Decode.offer_features": 13, + "Decode.offer_id": 3, + "Decode.offer_issuer": 12, + "Decode.offer_metadata": 5, + "Decode.offer_node_id": 17, + "Decode.offer_paths[]": 16, + "Decode.offer_quantity_max": 15, + "Decode.offer_recurrence": 18, + "Decode.payee": 62, + "Decode.payment_hash": 63, + "Decode.payment_metadata": 67, + "Decode.payment_secret": 66, + "Decode.restrictions[]": 73, + "Decode.routes[][]": 68, + "Decode.string": 72, + "Decode.type": 1, + "Decode.unique_id": 70, + "Decode.unknown_invoice_request_tlvs[]": 34, + "Decode.unknown_invoice_tlvs[]": 49, + "Decode.unknown_offer_tlvs[]": 19, + "Decode.valid": 2, + "Decode.version": 71, + "Decode.warning_invalid_invoice_request_signature": 39, + "Decode.warning_invalid_invoice_signature": 58, + "Decode.warning_invalid_invreq_payer_note": 37, + "Decode.warning_invalid_offer_currency": 23, + "Decode.warning_invalid_offer_description": 21, + "Decode.warning_invalid_offer_issuer": 24, + "Decode.warning_missing_invoice_amount": 54, + "Decode.warning_missing_invoice_blindedpay": 51, + "Decode.warning_missing_invoice_created_at": 52, + "Decode.warning_missing_invoice_node_id": 56, + "Decode.warning_missing_invoice_paths": 50, + "Decode.warning_missing_invoice_payment_hash": 53, + "Decode.warning_missing_invoice_recurrence_basetime": 55, + "Decode.warning_missing_invoice_request_signature": 38, + "Decode.warning_missing_invoice_signature": 57, + "Decode.warning_missing_invreq_metadata": 35, + "Decode.warning_missing_invreq_payer_id": 36, + "Decode.warning_missing_offer_description": 22, + "Decode.warning_missing_offer_node_id": 20, + "Decode.warning_rune_invalid_utf8": 74, + "Decode.warning_unknown_offer_currency": 7 + }, + "DecodeRestrictions": { + "Decode.restrictions[].alternatives[]": 1, + "Decode.restrictions[].summary": 2 + }, + "DecodepayExtra": { + "DecodePay.extra[].data": 2, + "DecodePay.extra[].tag": 1 + }, + "DecodepayFallbacks": { + "DecodePay.fallbacks[].addr": 2, + "DecodePay.fallbacks[].hex": 3, + "DecodePay.fallbacks[].type": 1 + }, + "DecodepayRequest": { + "DecodePay.bolt11": 1, + "DecodePay.description": 2 + }, + "DecodepayResponse": { + "DecodePay.amount_msat": 5, + "DecodePay.created_at": 2, + "DecodePay.currency": 1, + "DecodePay.description": 8, + "DecodePay.description_hash": 9, + "DecodePay.expiry": 3, + "DecodePay.extra[]": 16, + "DecodePay.fallbacks[]": 14, + "DecodePay.features": 12, + "DecodePay.min_final_cltv_expiry": 10, + "DecodePay.payee": 4, + "DecodePay.payment_hash": 6, + "DecodePay.payment_metadata": 13, + "DecodePay.payment_secret": 11, + "DecodePay.routes[][]": 15, + "DecodePay.signature": 7 + }, "DeldatastoreRequest": { "DelDatastore.generation": 2, "DelDatastore.key": 3, @@ -357,6 +591,8 @@ }, "FeeratesPerkb": { "Feerates.perkb.delayed_to_us": 6, + "Feerates.perkb.estimates[]": 9, + "Feerates.perkb.floor": 10, "Feerates.perkb.htlc_resolution": 7, "Feerates.perkb.max_acceptable": 2, "Feerates.perkb.min_acceptable": 1, @@ -365,8 +601,15 @@ "Feerates.perkb.penalty": 8, "Feerates.perkb.unilateral_close": 5 }, + "FeeratesPerkbEstimates": { + "Feerates.perkb.estimates[].blockcount": 1, + "Feerates.perkb.estimates[].feerate": 2, + "Feerates.perkb.estimates[].smoothed_feerate": 3 + }, "FeeratesPerkw": { "Feerates.perkw.delayed_to_us": 6, + "Feerates.perkw.estimates[]": 9, + "Feerates.perkw.floor": 10, "Feerates.perkw.htlc_resolution": 7, "Feerates.perkw.max_acceptable": 2, "Feerates.perkw.min_acceptable": 1, @@ -375,6 +618,11 @@ "Feerates.perkw.penalty": 8, "Feerates.perkw.unilateral_close": 5 }, + "FeeratesPerkwEstimates": { + "Feerates.perkw.estimates[].blockcount": 1, + "Feerates.perkw.estimates[].feerate": 2, + "Feerates.perkw.estimates[].smoothed_feerate": 3 + }, "FeeratesRequest": { "Feerates.style": 1 }, @@ -564,6 +812,42 @@ "ListchannelsResponse": { "ListChannels.channels[]": 1 }, + "ListclosedchannelsClosedchannels": { + "ListClosedChannels.closedchannels[].alias": 4, + "ListClosedChannels.closedchannels[].channel_id": 2, + "ListClosedChannels.closedchannels[].channel_type": 8, + "ListClosedChannels.closedchannels[].close_cause": 24, + "ListClosedChannels.closedchannels[].closer": 6, + "ListClosedChannels.closedchannels[].final_to_us_msat": 19, + "ListClosedChannels.closedchannels[].funding_fee_paid_msat": 15, + "ListClosedChannels.closedchannels[].funding_fee_rcvd_msat": 16, + "ListClosedChannels.closedchannels[].funding_outnum": 13, + "ListClosedChannels.closedchannels[].funding_pushed_msat": 17, + "ListClosedChannels.closedchannels[].funding_txid": 12, + "ListClosedChannels.closedchannels[].last_commitment_fee_msat": 23, + "ListClosedChannels.closedchannels[].last_commitment_txid": 22, + "ListClosedChannels.closedchannels[].leased": 14, + "ListClosedChannels.closedchannels[].max_to_us_msat": 21, + "ListClosedChannels.closedchannels[].min_to_us_msat": 20, + "ListClosedChannels.closedchannels[].opener": 5, + "ListClosedChannels.closedchannels[].peer_id": 1, + "ListClosedChannels.closedchannels[].private": 7, + "ListClosedChannels.closedchannels[].short_channel_id": 3, + "ListClosedChannels.closedchannels[].total_htlcs_sent": 11, + "ListClosedChannels.closedchannels[].total_local_commitments": 9, + "ListClosedChannels.closedchannels[].total_msat": 18, + "ListClosedChannels.closedchannels[].total_remote_commitments": 10 + }, + "ListclosedchannelsClosedchannelsAlias": { + "ListClosedChannels.closedchannels[].alias.local": 1, + "ListClosedChannels.closedchannels[].alias.remote": 2 + }, + "ListclosedchannelsRequest": { + "ListClosedChannels.id": 1 + }, + "ListclosedchannelsResponse": { + "ListClosedChannels.closedchannels[]": 1 + }, "ListdatastoreDatastore": { "ListDatastore.datastore[].generation": 2, "ListDatastore.datastore[].hex": 3, @@ -600,6 +884,7 @@ }, "ListfundsChannels": { "ListFunds.channels[].amount_msat": 3, + "ListFunds.channels[].channel_id": 9, "ListFunds.channels[].connected": 6, "ListFunds.channels[].funding_output": 5, "ListFunds.channels[].funding_txid": 4, @@ -695,6 +980,111 @@ "ListpaysResponse": { "ListPays.pays[]": 1 }, + "ListpeerchannelsChannels": { + "ListPeerChannels.channels[].alias": 41, + "ListPeerChannels.channels[].channel_id": 9, + "ListPeerChannels.channels[].channel_type": 5, + "ListPeerChannels.channels[].close_to": 17, + "ListPeerChannels.channels[].close_to_addr": 53, + "ListPeerChannels.channels[].closer": 20, + "ListPeerChannels.channels[].dust_limit_msat": 29, + "ListPeerChannels.channels[].features[]": 21, + "ListPeerChannels.channels[].fee_base_msat": 27, + "ListPeerChannels.channels[].fee_proportional_millionths": 28, + "ListPeerChannels.channels[].feerate": 6, + "ListPeerChannels.channels[].funding": 22, + "ListPeerChannels.channels[].funding_outnum": 11, + "ListPeerChannels.channels[].funding_txid": 10, + "ListPeerChannels.channels[].htlcs[]": 52, + "ListPeerChannels.channels[].in_fulfilled_msat": 47, + "ListPeerChannels.channels[].in_offered_msat": 45, + "ListPeerChannels.channels[].in_payments_fulfilled": 46, + "ListPeerChannels.channels[].in_payments_offered": 44, + "ListPeerChannels.channels[].inflight[]": 16, + "ListPeerChannels.channels[].initial_feerate": 12, + "ListPeerChannels.channels[].last_feerate": 13, + "ListPeerChannels.channels[].max_accepted_htlcs": 40, + "ListPeerChannels.channels[].max_to_us_msat": 25, + "ListPeerChannels.channels[].max_total_htlc_in_msat": 30, + "ListPeerChannels.channels[].maximum_htlc_out_msat": 37, + "ListPeerChannels.channels[].min_to_us_msat": 24, + "ListPeerChannels.channels[].minimum_htlc_in_msat": 35, + "ListPeerChannels.channels[].minimum_htlc_out_msat": 36, + "ListPeerChannels.channels[].next_fee_step": 15, + "ListPeerChannels.channels[].next_feerate": 14, + "ListPeerChannels.channels[].opener": 19, + "ListPeerChannels.channels[].our_reserve_msat": 32, + "ListPeerChannels.channels[].our_to_self_delay": 39, + "ListPeerChannels.channels[].out_fulfilled_msat": 51, + "ListPeerChannels.channels[].out_offered_msat": 49, + "ListPeerChannels.channels[].out_payments_fulfilled": 50, + "ListPeerChannels.channels[].out_payments_offered": 48, + "ListPeerChannels.channels[].owner": 7, + "ListPeerChannels.channels[].peer_connected": 2, + "ListPeerChannels.channels[].peer_id": 1, + "ListPeerChannels.channels[].private": 18, + "ListPeerChannels.channels[].receivable_msat": 34, + "ListPeerChannels.channels[].scratch_txid": 4, + "ListPeerChannels.channels[].short_channel_id": 8, + "ListPeerChannels.channels[].spendable_msat": 33, + "ListPeerChannels.channels[].state": 3, + "ListPeerChannels.channels[].state_changes[]": 42, + "ListPeerChannels.channels[].status[]": 43, + "ListPeerChannels.channels[].their_reserve_msat": 31, + "ListPeerChannels.channels[].their_to_self_delay": 38, + "ListPeerChannels.channels[].to_us_msat": 23, + "ListPeerChannels.channels[].total_msat": 26 + }, + "ListpeerchannelsChannelsAlias": { + "ListPeerChannels.channels[].alias.local": 1, + "ListPeerChannels.channels[].alias.remote": 2 + }, + "ListpeerchannelsChannelsChannel_type": { + "ListPeerChannels.channels[].channel_type.bits[]": 1, + "ListPeerChannels.channels[].channel_type.names[]": 2 + }, + "ListpeerchannelsChannelsFeerate": { + "ListPeerChannels.channels[].feerate.perkb": 2, + "ListPeerChannels.channels[].feerate.perkw": 1 + }, + "ListpeerchannelsChannelsFunding": { + "ListPeerChannels.channels[].funding.fee_paid_msat": 4, + "ListPeerChannels.channels[].funding.fee_rcvd_msat": 5, + "ListPeerChannels.channels[].funding.local_funds_msat": 2, + "ListPeerChannels.channels[].funding.pushed_msat": 1, + "ListPeerChannels.channels[].funding.remote_funds_msat": 3 + }, + "ListpeerchannelsChannelsHtlcs": { + "ListPeerChannels.channels[].htlcs[].amount_msat": 3, + "ListPeerChannels.channels[].htlcs[].direction": 1, + "ListPeerChannels.channels[].htlcs[].expiry": 4, + "ListPeerChannels.channels[].htlcs[].id": 2, + "ListPeerChannels.channels[].htlcs[].local_trimmed": 6, + "ListPeerChannels.channels[].htlcs[].payment_hash": 5, + "ListPeerChannels.channels[].htlcs[].state": 8, + "ListPeerChannels.channels[].htlcs[].status": 7 + }, + "ListpeerchannelsChannelsInflight": { + "ListPeerChannels.channels[].inflight[].feerate": 3, + "ListPeerChannels.channels[].inflight[].funding_outnum": 2, + "ListPeerChannels.channels[].inflight[].funding_txid": 1, + "ListPeerChannels.channels[].inflight[].our_funding_msat": 5, + "ListPeerChannels.channels[].inflight[].scratch_txid": 6, + "ListPeerChannels.channels[].inflight[].total_funding_msat": 4 + }, + "ListpeerchannelsChannelsState_changes": { + "ListPeerChannels.channels[].state_changes[].cause": 4, + "ListPeerChannels.channels[].state_changes[].message": 5, + "ListPeerChannels.channels[].state_changes[].new_state": 3, + "ListPeerChannels.channels[].state_changes[].old_state": 2, + "ListPeerChannels.channels[].state_changes[].timestamp": 1 + }, + "ListpeerchannelsRequest": { + "ListPeerChannels.id": 1 + }, + "ListpeerchannelsResponse": { + "ListPeerChannels.channels[]": 1 + }, "ListpeersPeers": { "ListPeers.peers[].channels[]": 4, "ListPeers.peers[].connected": 2, @@ -702,6 +1092,7 @@ "ListPeers.peers[].id": 1, "ListPeers.peers[].log[]": 3, "ListPeers.peers[].netaddr[]": 5, + "ListPeers.peers[].num_channels": 8, "ListPeers.peers[].remote_addr": 7 }, "ListpeersPeersChannels": { @@ -904,6 +1295,21 @@ "PingResponse": { "Ping.totlen": 1 }, + "PreapproveinvoiceRequest": { + "PreApproveInvoice.bolt11": 1 + }, + "PreapprovekeysendRequest": { + "PreApproveKeysend.amount_msat": 3, + "PreApproveKeysend.destination": 1, + "PreApproveKeysend.payment_hash": 2 + }, + "SendcustommsgRequest": { + "SendCustomMsg.msg": 2, + "SendCustomMsg.node_id": 1 + }, + "SendcustommsgResponse": { + "SendCustomMsg.status": 1 + }, "SendonionFirst_hop": { "SendOnion.first_hop.amount_msat": 2, "SendOnion.first_hop.delay": 3, @@ -1006,6 +1412,12 @@ "SetchannelResponse": { "SetChannel.channels[]": 1 }, + "SigninvoiceRequest": { + "SignInvoice.invstring": 1 + }, + "SigninvoiceResponse": { + "SignInvoice.bolt11": 1 + }, "SignmessageRequest": { "SignMessage.message": 1 }, @@ -1143,5 +1555,3887 @@ "Withdraw.tx": 1, "Withdraw.txid": 2 } + }, + "model-field-versions": { + "AddGossip": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "AddGossip.message": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "AutoCleanInvoice": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "AutoCleanInvoice.cycle_seconds": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "AutoCleanInvoice.enabled": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "AutoCleanInvoice.expired_by": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CheckMessage": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "CheckMessage.message": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CheckMessage.pubkey": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CheckMessage.verified": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CheckMessage.zbase": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Close": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "Close.destination": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Close.fee_negotiation_step": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Close.feerange[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Close.force_lease_closed": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Close.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Close.tx": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Close.txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Close.type": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Close.unilateraltimeout": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Close.wrong_funding": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Connect": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "Connect.address": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Connect.address.address": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Connect.address.port": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Connect.address.socket": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Connect.address.type": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Connect.direction": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Connect.features": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Connect.host": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Connect.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Connect.port": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "CreateInvoice.amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.amount_received_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.bolt12": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.description": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.expires_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.invreq_payer_note": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.invstring": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.label": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.local_offer_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.paid_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.pay_index": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.payment_preimage": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.preimage": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateInvoice.status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateOnion": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "CreateOnion.assocdata": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateOnion.hops[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateOnion.hops[].payload": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateOnion.hops[].pubkey": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateOnion.onion": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateOnion.onion_size": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateOnion.session_key": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "CreateOnion.shared_secrets[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Datastore": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "Datastore.generation": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Datastore.hex": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Datastore.key": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Datastore.mode": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Datastore.string": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode": { + "added": "v23.05", + "deprecated": null + }, + "Decode.created_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.currency_minor_unit": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.description_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.expiry": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.extra[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.extra[].data": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.extra[].tag": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.fallbacks[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.fallbacks[].warning_invoice_fallbacks_version_invalid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.hex": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_created_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_fallbacks[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_fallbacks[].address": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_fallbacks[].hex": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_fallbacks[].version": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_features": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_node_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_paths[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_paths[].blinding": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_paths[].first_node_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_paths[].path[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_paths[].path[].blinded_node_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_paths[].path[].encrypted_recipient_data": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_paths[].payinfo": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_paths[].payinfo.cltv_expiry_delta": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_paths[].payinfo.features": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_paths[].payinfo.fee_base_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_paths[].payinfo.fee_proportional_millionths": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_recurrence_basetime": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invoice_relative_expiry": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invreq_amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invreq_chain": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invreq_features": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invreq_metadata": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invreq_payer_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invreq_payer_note": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invreq_quantity": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invreq_recurrence_counter": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.invreq_recurrence_start": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.min_final_cltv_expiry": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_absolute_expiry": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_amount": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_chains[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_currency": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_description": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_features": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_issuer": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_metadata": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_node_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_paths[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_paths[].blinding": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_paths[].first_node_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_paths[].path[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_paths[].path[].blinded_node_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_paths[].path[].encrypted_recipient_data": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_quantity_max": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_recurrence": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_recurrence.basetime": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_recurrence.limit": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_recurrence.paywindow": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_recurrence.paywindow.proportional_amount": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_recurrence.paywindow.seconds_after": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_recurrence.paywindow.seconds_before": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_recurrence.period": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_recurrence.start_any_period": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_recurrence.time_unit": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.offer_recurrence.time_unit_name": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.payee": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.payment_metadata": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.payment_secret": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.restrictions[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.restrictions[].alternatives[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.restrictions[].summary": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.routes[][]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.routes[][].cltv_expiry_delta": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.routes[][].fee_base_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.routes[][].fee_proportional_millionths": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.routes[][].pubkey": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.routes[][].short_channel_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.string": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.type": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.unique_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.unknown_invoice_request_tlvs[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.unknown_invoice_request_tlvs[].length": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.unknown_invoice_request_tlvs[].type": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.unknown_invoice_request_tlvs[].value": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.unknown_invoice_tlvs[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.unknown_invoice_tlvs[].length": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.unknown_invoice_tlvs[].type": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.unknown_invoice_tlvs[].value": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.unknown_offer_tlvs[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.unknown_offer_tlvs[].length": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.unknown_offer_tlvs[].type": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.unknown_offer_tlvs[].value": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.valid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.version": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_invalid_invoice_request_signature": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_invalid_invoice_signature": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_invalid_invreq_payer_note": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_invalid_offer_currency": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_invalid_offer_description": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_invalid_offer_issuer": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_missing_invoice_amount": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_missing_invoice_blindedpay": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_missing_invoice_created_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_missing_invoice_node_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_missing_invoice_paths": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_missing_invoice_payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_missing_invoice_recurrence_basetime": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_missing_invoice_request_signature": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_missing_invoice_signature": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_missing_invreq_metadata": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_missing_invreq_payer_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_missing_offer_description": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_missing_offer_node_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_rune_invalid_utf8": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Decode.warning_unknown_offer_currency": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay": { + "added": "v23.05", + "deprecated": null + }, + "DecodePay.amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.created_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.currency": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.description": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.description_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.expiry": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.extra[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.extra[].data": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.extra[].tag": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.fallbacks[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.fallbacks[].addr": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.fallbacks[].hex": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.fallbacks[].type": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.features": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.min_final_cltv_expiry": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.payee": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.payment_metadata": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.payment_secret": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.routes[][]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.routes[][].cltv_expiry_delta": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.routes[][].fee_base_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.routes[][].fee_proportional_millionths": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.routes[][].pubkey": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.routes[][].short_channel_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DecodePay.signature": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelDatastore": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "DelDatastore.generation": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelDatastore.hex": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelDatastore.key": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelDatastore.string": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelExpiredInvoice": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "DelExpiredInvoice.maxexpirytime": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelInvoice": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "DelInvoice.amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelInvoice.bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelInvoice.bolt12": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelInvoice.desconly": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelInvoice.description": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelInvoice.expires_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelInvoice.invreq_payer_note": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelInvoice.label": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelInvoice.local_offer_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelInvoice.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "DelInvoice.status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Disconnect": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "Disconnect.force": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Disconnect.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "Feerates.onchain_fee_estimates": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.onchain_fee_estimates.htlc_success_satoshis": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.onchain_fee_estimates.htlc_timeout_satoshis": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.onchain_fee_estimates.mutual_close_satoshis": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.onchain_fee_estimates.opening_channel_satoshis": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.onchain_fee_estimates.unilateral_close_satoshis": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.perkb": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.perkb.delayed_to_us": { + "added": "pre-v0.10.1", + "deprecated": "v23.05" + }, + "Feerates.perkb.estimates[]": { + "added": "v23.05", + "deprecated": false + }, + "Feerates.perkb.estimates[].blockcount": { + "added": "v23.05", + "deprecated": false + }, + "Feerates.perkb.estimates[].feerate": { + "added": "v23.05", + "deprecated": false + }, + "Feerates.perkb.estimates[].smoothed_feerate": { + "added": "v23.05", + "deprecated": false + }, + "Feerates.perkb.floor": { + "added": "v23.05", + "deprecated": false + }, + "Feerates.perkb.htlc_resolution": { + "added": "pre-v0.10.1", + "deprecated": "v23.05" + }, + "Feerates.perkb.max_acceptable": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.perkb.min_acceptable": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.perkb.mutual_close": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.perkb.opening": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.perkb.penalty": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.perkb.unilateral_close": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.perkw": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.perkw.delayed_to_us": { + "added": "pre-v0.10.1", + "deprecated": "v23.05" + }, + "Feerates.perkw.estimates[]": { + "added": "v23.05", + "deprecated": false + }, + "Feerates.perkw.estimates[].blockcount": { + "added": "v23.05", + "deprecated": false + }, + "Feerates.perkw.estimates[].feerate": { + "added": "v23.05", + "deprecated": false + }, + "Feerates.perkw.estimates[].smoothed_feerate": { + "added": "v23.05", + "deprecated": false + }, + "Feerates.perkw.floor": { + "added": "v23.05", + "deprecated": false + }, + "Feerates.perkw.htlc_resolution": { + "added": "pre-v0.10.1", + "deprecated": "v23.05" + }, + "Feerates.perkw.max_acceptable": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.perkw.min_acceptable": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.perkw.mutual_close": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.perkw.opening": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.perkw.penalty": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.perkw.unilateral_close": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.style": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Feerates.warning_missing_feerates": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "FundChannel.amount": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.announce": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.channel_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.close_to": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.compact_lease": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.feerate": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.minconf": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.mindepth": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.outnum": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.push_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.request_amt": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.reserve": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.tx": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundChannel.utxos[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "FundPsbt.change_outnum": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.estimated_final_weight": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.excess_as_change": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.excess_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.feerate": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.feerate_per_kw": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.locktime": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.min_witness_weight": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.minconf": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.psbt": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.reservations[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.reservations[].reserved": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.reservations[].reserved_to_block": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.reservations[].txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.reservations[].vout": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.reservations[].was_reserved": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.reserve": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.satoshi": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "FundPsbt.startweight": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "GetRoute.amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute.cltv": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute.exclude[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute.fromid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute.fuzzpercent": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute.maxhops": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute.riskfactor": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute.route[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute.route[].amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute.route[].channel": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute.route[].delay": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute.route[].direction": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute.route[].id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "GetRoute.route[].style": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "Getinfo.address[]": { + "added": "v23.02", + "deprecated": false + }, + "Getinfo.address[].address": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.address[].port": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.address[].type": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.alias": { + "added": "v0.12.0", + "deprecated": false + }, + "Getinfo.binding[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.binding[].address": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.binding[].port": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.binding[].socket": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.binding[].type": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.blockheight": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.color": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.fees_collected_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.lightning-dir": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.network": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.num_active_channels": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.num_inactive_channels": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.num_peers": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.num_pending_channels": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.our_features": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.our_features.channel": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.our_features.init": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.our_features.invoice": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.our_features.node": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.version": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.warning_bitcoind_sync": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Getinfo.warning_lightningd_sync": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "Invoice.amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.cltv": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.deschashonly": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.description": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.expires_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.expiry": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.exposeprivatechannels": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.fallbacks[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.label": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.payment_secret": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.preimage": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.warning_capacity": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.warning_deadends": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.warning_mpp": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.warning_offline": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Invoice.warning_private_unused": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "KeySend.amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.amount_sent_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.created_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.destination": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.exemptfee": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.extratlvs": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.label": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.maxdelay": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.maxfeepercent": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.parts": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.payment_preimage": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.retry_for": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.routehints": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "KeySend.warning_partial_completion": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "ListChannels.channels[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].active": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].base_fee_millisatoshi": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].channel_flags": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].delay": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].destination": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].direction": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].features": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].fee_per_millionth": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].htlc_maximum_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].htlc_minimum_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].last_update": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].message_flags": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].public": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].short_channel_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.channels[].source": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.destination": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.short_channel_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListChannels.source": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels": { + "added": "v23.05", + "deprecated": null + }, + "ListClosedChannels.closedchannels[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].alias": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].alias.local": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].alias.remote": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].channel_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].channel_type": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].channel_type.bits[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].channel_type.names[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].close_cause": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].closer": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].final_to_us_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].funding_fee_paid_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].funding_fee_rcvd_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].funding_outnum": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].funding_pushed_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].funding_txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].last_commitment_fee_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].last_commitment_txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].leased": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].max_to_us_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].min_to_us_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].opener": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].peer_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].private": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].short_channel_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].total_htlcs_sent": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].total_local_commitments": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].total_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.closedchannels[].total_remote_commitments": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListClosedChannels.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListDatastore": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "ListDatastore.datastore[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListDatastore.datastore[].generation": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListDatastore.datastore[].hex": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListDatastore.datastore[].key[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListDatastore.datastore[].string": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListDatastore.key": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListForwards": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "ListForwards.forwards[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListForwards.forwards[].fee_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListForwards.forwards[].in_channel": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListForwards.forwards[].in_htlc_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListForwards.forwards[].in_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListForwards.forwards[].out_channel": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListForwards.forwards[].out_htlc_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListForwards.forwards[].out_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListForwards.forwards[].received_time": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListForwards.forwards[].status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListForwards.forwards[].style": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListForwards.in_channel": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListForwards.out_channel": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListForwards.status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "ListFunds.channels[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.channels[].amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.channels[].channel_id": { + "added": "v23.05", + "deprecated": false + }, + "ListFunds.channels[].connected": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.channels[].funding_output": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.channels[].funding_txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.channels[].our_amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.channels[].peer_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.channels[].short_channel_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.channels[].state": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.outputs[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.outputs[].address": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.outputs[].amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.outputs[].blockheight": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.outputs[].output": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.outputs[].redeemscript": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.outputs[].reserved": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.outputs[].scriptpubkey": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.outputs[].status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.outputs[].txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListFunds.spent": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "ListInvoices.invoices[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invoices[].amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invoices[].amount_received_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invoices[].bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invoices[].bolt12": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invoices[].description": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invoices[].expires_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invoices[].invreq_payer_note": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invoices[].label": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invoices[].local_offer_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invoices[].paid_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invoices[].pay_index": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invoices[].payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invoices[].payment_preimage": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invoices[].status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.invstring": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.label": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.offer_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListInvoices.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListNodes": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "ListNodes.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListNodes.nodes[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListNodes.nodes[].addresses[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListNodes.nodes[].addresses[].address": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListNodes.nodes[].addresses[].port": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListNodes.nodes[].addresses[].type": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListNodes.nodes[].alias": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListNodes.nodes[].color": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListNodes.nodes[].features": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListNodes.nodes[].last_timestamp": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListNodes.nodes[].nodeid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "ListPays.bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.pays[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.pays[].bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.pays[].bolt12": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.pays[].completed_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.pays[].created_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.pays[].description": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.pays[].destination": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.pays[].erroronion": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.pays[].label": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.pays[].number_of_parts": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.pays[].payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.pays[].preimage": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.pays[].status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPays.status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeerChannels": { + "added": "v23.02", + "deprecated": null + }, + "ListPeerChannels.channels[]": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].alias": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].alias.local": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].alias.remote": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].channel_id": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].channel_type": { + "added": "v23.05", + "deprecated": false + }, + "ListPeerChannels.channels[].channel_type.bits[]": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].channel_type.names[]": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].close_to": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].close_to_addr": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].closer": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].dust_limit_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].features[]": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].fee_base_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].fee_proportional_millionths": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].feerate": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].feerate.perkb": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].feerate.perkw": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].funding": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].funding.fee_paid_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].funding.fee_rcvd_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].funding.local_funds_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].funding.pushed_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].funding.remote_funds_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].funding_outnum": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].funding_txid": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].htlcs[]": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].htlcs[].amount_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].htlcs[].direction": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].htlcs[].expiry": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].htlcs[].id": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].htlcs[].local_trimmed": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].htlcs[].payment_hash": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].htlcs[].state": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].htlcs[].status": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].in_fulfilled_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].in_offered_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].in_payments_fulfilled": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].in_payments_offered": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].inflight[]": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].inflight[].feerate": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].inflight[].funding_outnum": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].inflight[].funding_txid": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].inflight[].our_funding_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].inflight[].scratch_txid": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].inflight[].total_funding_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].initial_feerate": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].last_feerate": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].max_accepted_htlcs": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].max_to_us_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].max_total_htlc_in_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].maximum_htlc_out_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].min_to_us_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].minimum_htlc_in_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].minimum_htlc_out_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].next_fee_step": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].next_feerate": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].opener": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].our_reserve_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].our_to_self_delay": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].out_fulfilled_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].out_offered_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].out_payments_fulfilled": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].out_payments_offered": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].owner": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].peer_connected": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].peer_id": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].private": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].receivable_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].scratch_txid": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].short_channel_id": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].spendable_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].state": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].state_changes[]": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].state_changes[].cause": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].state_changes[].message": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].state_changes[].new_state": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].state_changes[].old_state": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].state_changes[].timestamp": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].status[]": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].their_reserve_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].their_to_self_delay": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].to_us_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.channels[].total_msat": { + "added": "v23.02", + "deprecated": false + }, + "ListPeerChannels.id": { + "added": "v23.02", + "deprecated": false + }, + "ListPeers": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "ListPeers.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.level": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[]": { + "added": "pre-v0.10.1", + "deprecated": "v23.02" + }, + "ListPeers.peers[].channels[].alias": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].alias.local": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].alias.remote": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].channel_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].close_to": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].close_to_addr": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].closer": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].dust_limit_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].features[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].fee_base_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].fee_proportional_millionths": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].feerate": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].feerate.perkb": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].feerate.perkw": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].funding": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].funding.fee_paid_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].funding.fee_rcvd_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].funding.local_funds_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].funding.pushed_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].funding.remote_funds_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].funding_outnum": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].funding_txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].htlcs[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].htlcs[].amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].htlcs[].direction": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].htlcs[].expiry": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].htlcs[].id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].htlcs[].local_trimmed": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].htlcs[].payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].htlcs[].state": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].htlcs[].status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].in_fulfilled_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].in_offered_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].in_payments_fulfilled": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].in_payments_offered": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].inflight[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].inflight[].feerate": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].inflight[].funding_outnum": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].inflight[].funding_txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].inflight[].our_funding_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].inflight[].scratch_txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].inflight[].total_funding_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].initial_feerate": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].last_feerate": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].max_accepted_htlcs": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].max_to_us_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].max_total_htlc_in_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].maximum_htlc_out_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].min_to_us_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].minimum_htlc_in_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].minimum_htlc_out_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].next_fee_step": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].next_feerate": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].opener": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].our_reserve_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].our_to_self_delay": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].out_fulfilled_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].out_offered_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].out_payments_fulfilled": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].out_payments_offered": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].owner": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].private": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].receivable_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].scratch_txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].short_channel_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].spendable_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].state": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].state_changes[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].state_changes[].cause": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].state_changes[].message": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].state_changes[].new_state": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].state_changes[].old_state": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].state_changes[].timestamp": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].status[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].their_reserve_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].their_to_self_delay": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].to_us_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].channels[].total_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].connected": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].features": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].log[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].log[].data": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].log[].log": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].log[].node_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].log[].num_skipped": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].log[].source": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].log[].time": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].log[].type": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].netaddr[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListPeers.peers[].num_channels": { + "added": "v23.02", + "deprecated": false + }, + "ListPeers.peers[].remote_addr": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "ListSendPays.bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].amount_sent_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].bolt12": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].created_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].description": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].destination": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].erroronion": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].groupid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].label": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].partid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].payment_preimage": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.payments[].status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListSendPays.status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "ListTransactions.transactions[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].blockheight": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].inputs[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].inputs[].channel": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].inputs[].index": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].inputs[].sequence": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].inputs[].txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].inputs[].type": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].locktime": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].outputs[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].outputs[].amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].outputs[].channel": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].outputs[].index": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].outputs[].scriptPubKey": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].outputs[].type": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].rawtx": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].txindex": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "ListTransactions.transactions[].version": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "NewAddr": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "NewAddr.addresstype": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "NewAddr.bech32": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "NewAddr.p2sh-segwit": { + "added": "pre-v0.10.1", + "deprecated": "v23.02" + }, + "Pay": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "Pay.amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.amount_sent_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.created_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.description": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.destination": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.exclude": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.exemptfee": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.label": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.localinvreqid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.maxdelay": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.maxfee": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.maxfeepercent": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.parts": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.payment_preimage": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.retry_for": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.riskfactor": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Pay.warning_partial_completion": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Ping": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "Ping.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Ping.len": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Ping.pongbytes": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Ping.totlen": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "PreApproveInvoice": { + "added": "v23.02", + "deprecated": null + }, + "PreApproveInvoice.bolt11": { + "added": "v23.02", + "deprecated": false + }, + "PreApproveKeysend": { + "added": "v23.02", + "deprecated": null + }, + "PreApproveKeysend.amount_msat": { + "added": "v23.02", + "deprecated": false + }, + "PreApproveKeysend.destination": { + "added": "v23.02", + "deprecated": false + }, + "PreApproveKeysend.payment_hash": { + "added": "v23.02", + "deprecated": false + }, + "SendCustomMsg": { + "added": "v0.10.1", + "deprecated": null + }, + "SendCustomMsg.msg": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendCustomMsg.node_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendCustomMsg.status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "SendOnion.amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.amount_sent_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.bolt12": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.created_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.destination": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.first_hop": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.first_hop.amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.first_hop.delay": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.first_hop.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.groupid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.label": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.localinvreqid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.message": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.onion": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.partid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.payment_preimage": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.shared_secrets[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendOnion.status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "SendPay.amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.amount_sent_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.bolt12": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.completed_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.created_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.destination": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.groupid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.label": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.localinvreqid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.message": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.partid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.payment_preimage": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.payment_secret": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.route[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.route[].amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.route[].channel": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.route[].delay": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.route[].id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPay.status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPsbt": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "SendPsbt.psbt": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPsbt.reserve": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPsbt.tx": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SendPsbt.txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "SetChannel.channels[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.channels[].channel_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.channels[].fee_base_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.channels[].fee_proportional_millionths": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.channels[].maximum_htlc_out_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.channels[].minimum_htlc_out_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.channels[].peer_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.channels[].short_channel_id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.channels[].warning_htlcmax_too_high": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.channels[].warning_htlcmin_too_low": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.enforcedelay": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.feebase": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.feeppm": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.htlcmax": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.htlcmin": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SetChannel.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SignInvoice": { + "added": "v23.02", + "deprecated": null + }, + "SignInvoice.bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SignInvoice.invstring": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SignMessage": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "SignMessage.message": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SignMessage.recid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SignMessage.signature": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SignMessage.zbase": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SignPsbt": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "SignPsbt.psbt": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SignPsbt.signed_psbt": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "SignPsbt.signonly[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Stop": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "TxDiscard": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "TxDiscard.txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "TxDiscard.unsigned_tx": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "TxPrepare": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "TxPrepare.feerate": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "TxPrepare.minconf": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "TxPrepare.outputs[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "TxPrepare.psbt": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "TxPrepare.txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "TxPrepare.unsigned_tx": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "TxPrepare.utxos[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "TxSend": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "TxSend.psbt": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "TxSend.tx": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "TxSend.txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "UtxoPsbt.change_outnum": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.estimated_final_weight": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.excess_as_change": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.excess_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.feerate": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.feerate_per_kw": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.locktime": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.min_witness_weight": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.psbt": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.reservations[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.reservations[].reserved": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.reservations[].reserved_to_block": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.reservations[].txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.reservations[].vout": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.reservations[].was_reserved": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.reserve": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.reservedok": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.satoshi": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.startweight": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "UtxoPsbt.utxos[]": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitAnyInvoice": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "WaitAnyInvoice.amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitAnyInvoice.amount_received_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitAnyInvoice.bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitAnyInvoice.bolt12": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitAnyInvoice.description": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitAnyInvoice.expires_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitAnyInvoice.label": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitAnyInvoice.lastpay_index": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitAnyInvoice.paid_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitAnyInvoice.pay_index": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitAnyInvoice.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitAnyInvoice.payment_preimage": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitAnyInvoice.status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitAnyInvoice.timeout": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitInvoice": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "WaitInvoice.amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitInvoice.amount_received_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitInvoice.bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitInvoice.bolt12": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitInvoice.description": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitInvoice.expires_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitInvoice.label": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitInvoice.paid_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitInvoice.pay_index": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitInvoice.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitInvoice.payment_preimage": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitInvoice.status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "WaitSendPay.amount_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay.amount_sent_msat": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay.bolt11": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay.bolt12": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay.completed_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay.created_at": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay.destination": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay.groupid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay.id": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay.label": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay.partid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay.payment_hash": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay.payment_preimage": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay.status": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "WaitSendPay.timeout": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Withdraw": { + "added": "pre-v0.10.1", + "deprecated": null + }, + "Withdraw.destination": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Withdraw.feerate": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Withdraw.minconf": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Withdraw.psbt": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Withdraw.satoshi": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Withdraw.tx": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Withdraw.txid": { + "added": "pre-v0.10.1", + "deprecated": false + }, + "Withdraw.utxos[]": { + "added": "pre-v0.10.1", + "deprecated": false + } } } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e341d0923a6..e16e8b8c048f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,285 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - + +## [23.05] - 2023-05-10: "Austin Texas Agreement(ATXA)" + +This release named by @instagibbs + +NOTE 1: This release contains breaking changes of the Great Msat migration started in v0.12.0, so "msat" fields are no longer strings with "msat" appended, but simply integers. + +### Added + + - Protocol: blinded payments are now supported by default (not just with `--experimental-onion-messages`) ([#6138]) + - Protocol: we now always double-check bitcoin addresses are correct (no memory errors!) before issuing them. ([#5708]) + - JSON-RPC: PSBTv2 support for `fundchannel_complete`, `openchannel_update`, `reserveinputs`, `sendpsbt`, `signpsbt`, `withdraw` and `unreserveinputs` parameter `psbt`, `openchannel_init` and `openchannel_bump` parameter `initialpsbt`, `openchannel_signed` parameter `signed_psbt` and `utxopsbt` parameter `utxopsbt` ([#5898]) + - Plugins: `commando-blacklist` new command to disable select runes. ([#6124]) + - Plugins: `commando-listrunes` new command to show issued runes. ([#6124]) + - JSON-RPC: `listclosedchannels` new command to show old, dead channels we previously had with peers. ([#5967]) + - JSON-RPC: `close`, `fundchannel`, `fundpsbt`, `multifundchannel`, `multiwithdraw`, `txprepare`, `upgradewallet`, `withdraw` now allow "minimum" and NN"blocks" as `feerate` (`feerange` for `close`). ([#6120]) + - JSON-RPC: `feerates` added `floor` field for current minimum feerate bitcoind will accept ([#6120]) + - JSON-RPC: `feerates` `estimates` array shows fee estimates by blockcount from underlying plugin (usually *bcli*). ([#6120]) + - Plugins: `estimatefees` can return explicit `fee_floor` and `feerates` by block number. ([#6120]) + - JSON-RPC: `listfunds` now has a `channel_id` field. ([#6029]) + - JSON-RPC: `listpeerchannels` now has `channel_type` field. ([#5967]) + - JSON-RPC: `sql` now includes `listclosedchannels`. ([#5967]) + - `pyln-client`: Improvements on the gossmap implementation ([#6012]) + - `hsmtool`: `makerune` new command to make a master rune for a node. ([#6097]) + - JSON-RPC: `setpsbtversion`: new command to aid debugging and compatibility ([#5898]) + - `grpc`: Added mapping for `listpeerchannels`, `listclosedchannels`, `decode` and `decodepay` RPC methods ([#6229]) + + +### Changed + + - `reckless`: Added support for node.js plugin installation ([#6158]) + - `reckless`: Added support for networks beyond bitcoin and regtest ([#6110]) + - JSON-RPC: elements network PSET now only supports PSETv2. ([#5898]) + - JSON-RPC: `close`, `fundchannel`, `fundpsbt`, `multifundchannel`, `multiwithdraw`, `txprepare`, `upgradewallet`, `withdraw` `feerate` (`feerange` for `close`) value *slow* is now 100 block-estimate, not half of 100-block estimate. ([#6120]) + - Protocol: spending unilateral close transactions now use dynamic fees based on deadlines (and RBF), instead of fixed fees. ([#6120]) + - Protocol: Allow slight overpaying, even with MPP, as spec now recommends. ([#6138]) + - `msggen`: The generated interfaces `cln-rpc` anc `cln-grpc` can now work with a range of versions rather than having to match the CLN version ([#6142]) + - `grpc`: The mTLS private keys are no longer group-readable ([#6075]) + + +### Deprecated + +Note: You should always set `allow-deprecated-apis=false` to test for changes. + + - JSON-RPC: `close`, `fundchannel`, `fundpsbt`, `multifundchannel`, `multiwithdraw`, `txprepare`, `upgradewallet`, `withdraw` `feerate` (`feerange` for `close`) expressed as, "delayed_to_us", "htlc_resolution", "max_acceptable" or "min_acceptable". Use explicit block counts or *slow*/*normal*/*urgent*/*minimum*. ([#6120]) + - Plugins: `estimatefees` returning feerates by name (e.g. "opening"); use `fee_floor` and `feerates`. ([#6120]) + - Protocol: Not setting `option_scid_alias` in `option_channel` `channel_type` for unannounced channels. ([#6136]) + + +### Removed + + - JSON-RPC: the "msat" suffix on millisatoshi fields, as deprecated in v0.12.0. ([#5986], [#6245]) + - JSON-RPC: all the non-msat-named millisatoshi fields deprecated in v0.12.0. ([#5986]) + - JSON-RPC: `listpeers`.`local_msat` and `listpeers`.`remote_msat` (deprecated v0.12.0) ([#5986]) + - JSON-RPC: `checkmessage` now always returns an error when the pubkey is not specified and it is unknown in the network graph (deprecated v0.12.0) ([#5986]) + - JSON-RPC: require the `"jsonrpc": "2.0"` property (requests without this deprecated in v0.10.2). ([#5986]) + + +### Fixed + + - Plugins: `bcli` now tells us the minimal possible feerate, such as with mempool congestion, rather than assuming 1 sat/vbyte. ([#6120]) + - `lightningd`: don't log gratuitous "Peer transient failure" message on first connection after restart. ([#6140]) + - `channeld`: no longer spin and spam logs when waiting for revoke_and_ack. ([#6107]) + - Plugin: `autoclean` now also cleans forwards with status `local_failed` ([#6109]) + - Protocol: we will upfront reject channel_open which asks for a zeroconf channel unless we are going to do a zerconf channel. ([#6136]) + - Protocol: We now correctly accept the `option_scid_alias` bit in `open_channel` `channel_type`. ([#6136]) + - JSON-RPC: `feerates` document correctly that urgent means 6 blocks (not 2), and give better feerate examples. ([#6170]) + - `wallet`: we no longer make txs below minrelaytxfee or mempoolminfee. ([#6073]) + - `delpay`: be more pedantic about delete logic by allowing delete payments by status directly on the database. ([#6115]) + - Plugins: `bookkeeper` onchain fees calculation was incorrect with PostgresQL. ([#6128]) + - `clnrs`: Fixed an issue converting routehints in keysend ([#6154]) + - Build: Compilation with upcoming gcc 13 ([#6184]) + + +### EXPERIMENTAL + + - fetchinvoice: fix: do not ignore the `quantity` field ([#6090]) + + +[#6120]: https://github.com/ElementsProject/lightning/pull/6120 +[#6138]: https://github.com/ElementsProject/lightning/pull/6138 +[#5967]: https://github.com/ElementsProject/lightning/pull/5967 +[#5898]: https://github.com/ElementsProject/lightning/pull/5898 +[#5986]: https://github.com/ElementsProject/lightning/pull/5986 +[#6245]: https://github.com/ElementsProject/lightning/pull/6245 +[#6136]: https://github.com/ElementsProject/lightning/pull/6136 +[#6128]: https://github.com/ElementsProject/lightning/pull/6128 +[#6154]: https://github.com/ElementsProject/lightning/pull/6154 +[#6029]: https://github.com/ElementsProject/lightning/pull/6029 +[#6075]: https://github.com/ElementsProject/lightning/pull/6075 +[#5708]: https://github.com/ElementsProject/lightning/pull/5708 +[#6124]: https://github.com/ElementsProject/lightning/pull/6124 +[#6012]: https://github.com/ElementsProject/lightning/pull/6012 +[#6090]: https://github.com/ElementsProject/lightning/pull/6090 +[#6142]: https://github.com/ElementsProject/lightning/pull/6142 +[#6140]: https://github.com/ElementsProject/lightning/pull/6140 +[#6097]: https://github.com/ElementsProject/lightning/pull/6097 +[#6170]: https://github.com/ElementsProject/lightning/pull/6170 +[#6107]: https://github.com/ElementsProject/lightning/pull/6107 +[#6110]: https://github.com/ElementsProject/lightning/pull/6110 +[#6073]: https://github.com/ElementsProject/lightning/pull/6073 +[#6115]: https://github.com/ElementsProject/lightning/pull/6115 +[#6109]: https://github.com/ElementsProject/lightning/pull/6109 +[#6158]: https://github.com/ElementsProject/lightning/pull/6158 +[#6184]: https://github.com/ElementsProject/lightning/pull/6184 +[#6229]: https://github.com/ElementsProject/lightning/pull/6229 + + +## [23.02.2] - 2023-03-14: "CBDC Backing Layer III" + + +### Added + + - JSON-RPC: Restore `pay` for a bolt11 which uses a `description_hash`, without setting `description` (still deprecated, but the world is not ready) [ + +[#6092]: https://github.com/ElementsProject/lightning/pull/6092 + + +## [23.02.1] - 2023-03-10: "CBDC Backing Layer II" + +This release named by @whitslack + +### Added + + +### Changed + + - gossipd: Revert zombification change, keep all gossip for now. ([#6069]) + + +### Deprecated + +Note: You should always set `allow-deprecated-apis=false` to test for changes. + + +### Removed + + +### Fixed + + - Plugins: `sql` nodes table now gets refreshed when gossip changes. ([#6068]) + - connectd: Fixed a crash on new connections. ([#6070]) + - wallet: Don't crash on broken database migrations. ([#6071]) + + +### EXPERIMENTAL + + - `experimental-peer-storage`: only send to peers which support it. ([#6072]) + + +[#6068]: https://github.com/ElementsProject/lightning/pull/6068 +[#6069]: https://github.com/ElementsProject/lightning/pull/6069 +[#6070]: https://github.com/ElementsProject/lightning/pull/6070 +[#6071]: https://github.com/ElementsProject/lightning/pull/6071 +[#6072]: https://github.com/ElementsProject/lightning/pull/6072 + + +## [23.02] - 2023-03-01: "CBDC Backing Layer" + +This release named by @whitslack + +NOTE 1: This release contains breaking protocol changes to dual-funding and + offers, making them incompatible with previous releases. +NOTE 2: Periodic pruning of channels now keeps track of them as 'zombies.' This + behavior is in line with the lightning specification but results in + fewer nodes and channels listed by `listnodes`/`listpeers`. These + channels will resume as soon as the missing side broadcasts a recent + channel update. + + +### Added + + - Plugins: `sql` plugin command to perform server-side complex queries. ([#5679]) + - JSON-RPC: `preapprovekeysend`: New command to preapprove payment details with an HSM. ([#5821]) + - JSON-RPC: `preapproveinvoice`: New command to preapprove a BOLT11 invoice with an HSM. ([#5821]) + - JSON-RPC: `listpeerchannels`: New command to return information on direct channels with our peers. ([#5825]) + - JSON-RPC: `signinvoice`: New command to sign a BOLT11 invoice. ([#5697]) + - JSON-RPC: `upgradewallet`: New command to sweep all p2sh-wrapped outputs to a native segwit output. ([#5670]) + - JSON-RPC: `fundpsbt` option `nonwrapped` filters out p2sh wrapped inputs. ([#5670]) + - JSON-RPC: `listpeers` output now has `num_channels` as `channels` is deprecated (see `listpeerchannels`). ([#5968]) + - JSON-RPC: `listchannels` added a `direction` field (0 or 1) as per gossip specification. ([#5679]) + - cli: `--commando=peerid:rune` (or `-c peerid:rune`) as convenient shortcut for running commando commands. ([#5866]) + - Plugins: `commando` now supports `filter` as a parameter (for send and receive). ([#5866]) + - Config: Added config option `announce-addr-discovered-port` to set custom port for IP discovery. ([#5842]) + - Config: Added config switch `announce-addr-discovered`: on/off/auto ([#5841]) + - doc: we now annotate what versions JSON field additions and deprecations happenened. ([#5867]) + - SECURITY.md: Where to send sensitive bug reports, and dev GPG fingerprints. ([#5960]) + + +### Changed + + - JSON-RPC: `sendcustommsg` can now be called by a plugin from within the `peer_connected` hook. ([#5361]) + - JSON-RPC: `getinfo` `address` array is always present (though may be empty.) ([#5904]) + - postgres: Ordering of HTLCs in `listhtlcs` are now ordered by time of creation. ([#5863]) + + +### Deprecated + +Note: You should always set `allow-deprecated-apis=false` to test for changes. + + - Config: The --disable-ip-discovery config switch: use `announce-addr-discovered`. ([#5841]) + - JSON-RPC: `newaddr`: `addresstype` `p2sh-segwit` (use default, or `bech32`.) ([#5751]) + - JSON-RPC: `listpeers` `channels` array: use `listpeerchannels`. ([#5825]) + - plugins: `commando` JSON commands without an `id` (see doc/lightningd-rpc.7.md for how to construct a good id field). ([#5866]) + + +### Removed + + - JSON-RPC: `sendpay` `route` argument `style` "legacy" (deprecated v0.11.0) ([#5747]) + - JSON-RPC: `close` `destination` no longer allows p2pkh or p2sh addresses. (deprecated v0.11.0) ([#5747]) + - JSON-RPC: `fundpsbt`/`utxopsbt` `reserve` must be a number, not bool. (deprecated v0.11.0) ([#5747]) + - JSON-RPC: `invoice` `expiry` no longer allowed to be a string with suffix, use an integer number of seconds. (deprecated v0.11.0) ([#5747]) + - JSON-RPC: `pay` for a bolt11 which uses a `description_hash`, without setting `description`. (deprecated v0.11.0) ([#5747]) + + +### Fixed + + - gossip: We removed a warning for old `node_announcement` that was causing LND peers to disconnect ([#5925]) + - gossip: We removed a warning for malformed `channel_update` that was causing LND peers to disconnect ([#5897]) + - cli: accepts long paths as options ([#5883]) + - JSON-RPC: `getinfo` `blockheight` no longer sits on 0 while we sync with bitcoind the first time. ([#5963]) + - keysend: Keysend would strip even allowed extra TLV types before resolving, this is no longer the case. ([#6031]) + - lightningd: we no longer stack multiple reconnection attempts if connections fail. ([#5946]) + - Plugins: `pay` uses the correct local channel for payments when there are multiple available (not just always the first!) ([#5947]) + - Pruned channels are more reliably restored. ([#5839]) + - `delpay`: Actually delete the specified payment (mainly found by `autoclean`). ([#6043]) + - pay: Don't assert() on malformed BOLT11 strings. ([#5891]) + - gossmap: Fixed `FATAL SIGNAL 11` on gossmap node announcement parsing. ([#6005]) + - channeld no longer retains dead HTLCs in memory. ([#5882]) + - database: Correctly identity official release versions for database upgrade. ([#5880]) + - Plugins: `commando` now responds to remote JSON calls with the correct JSON `id` field. ([#5866]) + - JSON-RPC: `datastore` handles escapes in `string` parameter correctly. ([#5994]) + - JSON-RPC: `sendpay` now can send to a short-channel-id alias for the first hop. ([#5846]) + - topology: Fixed memleak in `listchannels` ([#5865]) + + +### EXPERIMENTAL + + - Protocol: Peer Storage: Distribute your encrypted backup to your peers, which can be retrieved to recover funds upon complete dataloss. ([#5361]) + - Protocol: `offers` breaking blinded payments change (total_amount_sat required, update_add_tlvs fix, Eclair compat.) ([#5892]) + - Protocol: Dual-funding spec changed in incompatible ways, won't work with old versions (but maybe soon with Eclair!!) ([#5956]) + - Experimental-Dual-Fund: Open failures don't disconnect, but instead fail the opening process. ([#5767]) + - JSON-RPC: `listtransactions` `channel` and `type` field removed at top level. ([#5679]) + + +[#5825]: https://github.com/ElementsProject/lightning/pull/5825 +[#5882]: https://github.com/ElementsProject/lightning/pull/5882 +[#5839]: https://github.com/ElementsProject/lightning/pull/5839 +[#5892]: https://github.com/ElementsProject/lightning/pull/5892 +[#5751]: https://github.com/ElementsProject/lightning/pull/5751 +[#5963]: https://github.com/ElementsProject/lightning/pull/5963 +[#5891]: https://github.com/ElementsProject/lightning/pull/5891 +[#5747]: https://github.com/ElementsProject/lightning/pull/5747 +[#5670]: https://github.com/ElementsProject/lightning/pull/5670 +[#5846]: https://github.com/ElementsProject/lightning/pull/5846 +[#5880]: https://github.com/ElementsProject/lightning/pull/5880 +[#5866]: https://github.com/ElementsProject/lightning/pull/5866 +[#5697]: https://github.com/ElementsProject/lightning/pull/5697 +[#5867]: https://github.com/ElementsProject/lightning/pull/5867 +[#5883]: https://github.com/ElementsProject/lightning/pull/5883 +[#5960]: https://github.com/ElementsProject/lightning/pull/5960 +[#5679]: https://github.com/ElementsProject/lightning/pull/5679 +[#5821]: https://github.com/ElementsProject/lightning/pull/5821 +[#5946]: https://github.com/ElementsProject/lightning/pull/5946 +[#5968]: https://github.com/ElementsProject/lightning/pull/5968 +[#5947]: https://github.com/ElementsProject/lightning/pull/5947 +[#5863]: https://github.com/ElementsProject/lightning/pull/5863 +[#5925]: https://github.com/ElementsProject/lightning/pull/5925 +[#5361]: https://github.com/ElementsProject/lightning/pull/5361 +[#5767]: https://github.com/ElementsProject/lightning/pull/5767 +[#5841]: https://github.com/ElementsProject/lightning/pull/5841 +[#5865]: https://github.com/ElementsProject/lightning/pull/5865 +[#5842]: https://github.com/ElementsProject/lightning/pull/5842 +[#5956]: https://github.com/ElementsProject/lightning/pull/5956 +[#5897]: https://github.com/ElementsProject/lightning/pull/5897 +[#5904]: https://github.com/ElementsProject/lightning/pull/5904 +[#5994]: https://github.com/ElementsProject/lightning/pull/5994 +[#6005]: https://github.com/ElementsProject/lightning/pull/6005 + ## [22.11.1] - 2022-12-09: "Alameda Yield Generator II" @@ -2116,6 +2392,9 @@ There predate the BOLT specifications, and are only of vague historic interest: 6. [0.5.1] - 2016-10-21 7. [0.5.2] - 2016-11-21: "Bitcoin Savings & Trust Daily Interest II" +[23.05]: https://github.com/ElementsProject/lightning/releases/tag/v23.05 +[23.02.1]: https://github.com/ElementsProject/lightning/releases/tag/v23.02.1 +[23.02]: https://github.com/ElementsProject/lightning/releases/tag/v23.02 [0.12.0]: https://github.com/ElementsProject/lightning/releases/tag/v0.12.0 [0.11.2]: https://github.com/ElementsProject/lightning/releases/tag/v0.11.2 [0.11.1]: https://github.com/ElementsProject/lightning/releases/tag/v0.11.1 diff --git a/Cargo.lock b/Cargo.lock index 06f85d1d87df..c69dda74bb6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,24 +4,24 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" [[package]] name = "asn1-rs" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf6690c370453db30743b373a60ba498fc0d6d83b11f4abfd87a84a075db5dd4" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -41,7 +41,7 @@ checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "synstructure", ] @@ -53,39 +53,40 @@ checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "async-stream" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", + "pin-project-lite", ] [[package]] name = "async-stream-impl" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "async-trait" -version = "0.1.60" +version = "0.1.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] @@ -96,9 +97,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.1" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08b108ad2665fa3f6e6a517c3d80ec3e77d224c47d605167aefaa5d7ef97fa48" +checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" dependencies = [ "async-trait", "axum-core", @@ -118,16 +119,15 @@ dependencies = [ "serde", "sync_wrapper", "tower", - "tower-http", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b8558f5a0581152dc94dcd289132a1d377494bdeafcd41869b3258e3e2ad92" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" dependencies = [ "async-trait", "bytes", @@ -146,6 +146,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + [[package]] name = "bech32" version = "0.9.1" @@ -181,21 +187,21 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -205,7 +211,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cln-grpc" -version = "0.1.2" +version = "0.1.3" dependencies = [ "anyhow", "bitcoin", @@ -220,7 +226,7 @@ dependencies = [ [[package]] name = "cln-grpc-plugin" -version = "0.1.1" +version = "0.1.2" dependencies = [ "anyhow", "cln-grpc", @@ -235,7 +241,7 @@ dependencies = [ [[package]] name = "cln-plugin" -version = "0.1.2" +version = "0.1.4" dependencies = [ "anyhow", "bytes", @@ -252,7 +258,7 @@ dependencies = [ [[package]] name = "cln-rpc" -version = "0.1.2" +version = "0.1.3" dependencies = [ "anyhow", "bitcoin", @@ -269,15 +275,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" +checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "der-parser" -version = "8.1.0" +version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d4bc9b0db0a0df9ae64634ac5bdefb7afcb534e182275ca0beadbe486701c1" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" dependencies = [ "asn1-rs", "displaydoc", @@ -289,20 +295,20 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "env_logger" @@ -319,13 +325,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.2.8" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -340,9 +346,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] @@ -361,9 +367,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "futures" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -376,9 +382,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -386,15 +392,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -403,38 +409,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -450,9 +456,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" dependencies = [ "cfg-if", "libc", @@ -461,9 +467,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.15" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" dependencies = [ "bytes", "fnv", @@ -486,9 +492,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -499,6 +505,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hex" version = "0.4.3" @@ -507,9 +519,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "http" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", @@ -527,12 +539,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "http-range-header" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" - [[package]] name = "httparse" version = "1.8.0" @@ -553,9 +559,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.23" +version = "0.14.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" dependencies = [ "bytes", "futures-channel", @@ -589,9 +595,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown", @@ -608,24 +614,25 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.3" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ + "hermit-abi 0.3.1", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "is-terminal" -version = "0.4.2" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.1", "io-lifetimes", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -639,15 +646,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" dependencies = [ "wasm-bindgen", ] @@ -660,24 +667,21 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "log" -version = "0.4.17" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" [[package]] name = "matchit" @@ -693,9 +697,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minimal-lexical" @@ -705,14 +709,13 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "mio" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -723,9 +726,9 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "nom" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -767,7 +770,7 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] @@ -782,17 +785,17 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" [[package]] name = "pem" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" dependencies = [ - "base64", + "base64 0.13.1", ] [[package]] @@ -803,9 +806,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "petgraph" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", "indexmap", @@ -813,22 +816,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] @@ -851,28 +854,28 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "prettyplease" -version = "0.1.22" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8992a85d8e93a28bdf76137db888d3874e3b230dee5ed8bebac4c9f7617773" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" dependencies = [ "proc-macro2", - "syn", + "syn 1.0.109", ] [[package]] name = "proc-macro2" -version = "1.0.49" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.11.5" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c01db6702aa05baa3f57dec92b8eeeeb4cb19e894e73996b32a4093289e54592" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ "bytes", "prost-derive", @@ -880,9 +883,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.11.5" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5320c680de74ba083512704acb90fe00f28f79207286a848e730c45dd73ed6" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" dependencies = [ "bytes", "heck", @@ -895,39 +898,38 @@ dependencies = [ "prost", "prost-types", "regex", - "syn", + "syn 1.0.109", "tempfile", "which", ] [[package]] name = "prost-derive" -version = "0.11.5" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8842bad1a5419bca14eac663ba798f6bc19c413c2fdceb5f3ba3b0932d96720" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "prost-types" -version = "0.11.5" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "017f79637768cde62820bc2d4fe0e45daaa027755c323ad077767c6c5f173091" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" dependencies = [ - "bytes", "prost", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] @@ -977,18 +979,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.7.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" dependencies = [ "aho-corasick", "memchr", @@ -997,18 +999,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "ring" @@ -1036,23 +1029,23 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.5" +version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "rustls" -version = "0.20.7" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring", @@ -1062,24 +1055,24 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64", + "base64 0.21.2", ] [[package]] name = "rustversion" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "sct" @@ -1093,9 +1086,9 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9512ffd81e3a3503ed401f79c33168b9148c75038956039166cd750eaa037c3" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" dependencies = [ "bitcoin_hashes", "secp256k1-sys", @@ -1113,29 +1106,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.151" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.151" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", @@ -1144,18 +1137,18 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] [[package]] name = "socket2" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -1169,9 +1162,20 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ "proc-macro2", "quote", @@ -1180,9 +1184,9 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "synstructure" @@ -1192,58 +1196,57 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "unicode-xid", ] [[package]] name = "tempfile" -version = "3.3.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "libc", "redox_syscall", - "remove_dir_all", - "winapi", + "rustix", + "windows-sys 0.45.0", ] [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "time" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" dependencies = [ "itoa", "serde", @@ -1253,35 +1256,34 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" dependencies = [ "time-core", ] [[package]] name = "tokio" -version = "1.23.1" +version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38a54aca0c15d014013256222ba0ebed095673f89345dd79119d912eb561b7a8" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg", "bytes", "libc", - "memchr", "mio", "num_cpus", "pin-project-lite", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1296,13 +1298,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] @@ -1318,9 +1320,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", @@ -1329,9 +1331,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", @@ -1350,7 +1352,7 @@ dependencies = [ "async-stream", "async-trait", "axum", - "base64", + "base64 0.13.1", "bytes", "futures-core", "futures-util", @@ -1385,7 +1387,7 @@ dependencies = [ "proc-macro2", "prost-build", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1408,25 +1410,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tower-http" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" -dependencies = [ - "bitflags", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-range-header", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - [[package]] name = "tower-layer" version = "0.3.2" @@ -1446,7 +1429,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1454,20 +1436,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", ] @@ -1484,15 +1466,15 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-xid" @@ -1524,9 +1506,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1534,24 +1516,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.18", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1559,28 +1541,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" dependencies = [ "js-sys", "wasm-bindgen", @@ -1598,9 +1580,9 @@ dependencies = [ [[package]] name = "which" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ "either", "libc", @@ -1640,60 +1622,135 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "x509-parser" @@ -1702,7 +1759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" dependencies = [ "asn1-rs", - "base64", + "base64 0.13.1", "data-encoding", "der-parser", "lazy_static", @@ -1716,9 +1773,9 @@ dependencies = [ [[package]] name = "yasna" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aed2e7a52e3744ab4d0c05c20aa065258e84c49fd4226f5191b2ed29712710b4" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ "time", ] diff --git a/Dockerfile b/Dockerfile index 4cd3c6ae2cec..ace01d6040f7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -86,6 +86,7 @@ RUN apt-get install -y --no-install-recommends unzip tclsh \ && make \ && make install && cd .. && rm sqlite-src-3290000.zip && rm -rf sqlite-src-3290000 +USER root RUN wget -q https://gmplib.org/download/gmp/gmp-6.1.2.tar.xz \ && tar xvf gmp-6.1.2.tar.xz \ && cd gmp-6.1.2 \ @@ -105,10 +106,10 @@ RUN git clone --recursive /tmp/lightning . && \ ARG DEVELOPER=1 ENV PYTHON_VERSION=3 -RUN curl -sSL https://install.python-poetry.org | python3 - \ - && pip3 install -U pip \ - && pip3 install -U wheel \ - && /root/.local/bin/poetry install +RUN curl -sSL https://install.python-poetry.org | python3 - +RUN pip3 install -U pip +RUN pip3 install -U wheel +RUN /root/.local/bin/poetry install RUN ./configure --prefix=/tmp/lightning_install --enable-static && \ make DEVELOPER=${DEVELOPER} && \ diff --git a/LICENSE b/LICENSE index 15ef029efec9..11c6e6960ffc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ Note: the modules in the ccan/ directory have their own licenses, but the rest of the code is covered by the following (BSD-MIT) license: - Copyright Rusty Russell (Blockstream) 2015-2022. + Copyright Rusty Russell (Blockstream) 2015-2023. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index a740c3e983cb..8e03c449af25 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ CCANDIR := ccan # Where we keep the BOLT RFCs BOLTDIR := ../bolts/ -DEFAULT_BOLTVERSION := f32c6ddb5f11b431c9bb4f501cdec604172a90de +DEFAULT_BOLTVERSION := c4c5a8e5fb30b1b99fa5bb0aba7d0b6b4c831ee5 # Can be overridden on cmdline. BOLTVERSION := $(DEFAULT_BOLTVERSION) @@ -43,20 +43,6 @@ VG=VALGRIND=1 valgrind -q --error-exitcode=7 VG_TEST_ARGS = --track-origins=yes --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all endif -SANITIZER_FLAGS := - -ifneq ($(ASAN),0) -SANITIZER_FLAGS += -fsanitize=address -endif - -ifneq ($(UBSAN),0) -SANITIZER_FLAGS += -fsanitize=undefined -endif - -ifneq ($(FUZZING), 0) -SANITIZER_FLAGS += -fsanitize=fuzzer-no-link -endif - ifeq ($(DEVELOPER),1) DEV_CFLAGS=-DCCAN_TAKE_DEBUG=1 -DCCAN_TAL_DEBUG=1 -DCCAN_JSON_OUT_DEBUG=1 else @@ -256,7 +242,7 @@ LIBRARY_PATH := /usr/local/lib endif CPPFLAGS += -DBINTOPKGLIBEXECDIR="\"$(shell sh tools/rel.sh $(bindir) $(pkglibexecdir))\"" -CFLAGS = $(CPPFLAGS) $(CWARNFLAGS) $(CDEBUGFLAGS) $(COPTFLAGS) -I $(CCANDIR) $(EXTERNAL_INCLUDE_FLAGS) -I . -I$(CPATH) $(SQLITE3_CFLAGS) $(POSTGRES_INCLUDE) $(FEATURES) $(COVFLAGS) $(DEV_CFLAGS) -DSHACHAIN_BITS=48 -DJSMN_PARENT_LINKS $(PIE_CFLAGS) $(COMPAT_CFLAGS) -DBUILD_ELEMENTS=1 +CFLAGS = $(CPPFLAGS) $(CWARNFLAGS) $(CDEBUGFLAGS) $(COPTFLAGS) -I $(CCANDIR) $(EXTERNAL_INCLUDE_FLAGS) -I . -I$(CPATH) $(SQLITE3_CFLAGS) $(POSTGRES_INCLUDE) $(FEATURES) $(COVFLAGS) $(DEV_CFLAGS) -DSHACHAIN_BITS=48 -DJSMN_PARENT_LINKS $(PIE_CFLAGS) $(COMPAT_CFLAGS) $(CSANFLAGS) -DBUILD_ELEMENTS=1 # If CFLAGS is already set in the environment of make (to whatever value, it # does not matter) then it would export it to subprocesses with the above value @@ -268,16 +254,15 @@ unexport CFLAGS # We can get configurator to run a different compile cmd to cross-configure. CONFIGURATOR_CC := $(CC) -LDFLAGS += $(PIE_LDFLAGS) $(SANITIZER_FLAGS) $(COPTFLAGS) -CFLAGS += $(SANITIZER_FLAGS) +LDFLAGS += $(PIE_LDFLAGS) $(CSANFLAGS) $(COPTFLAGS) ifeq ($(STATIC),1) # For MacOS, Jacob Rapoport changed this to: -# -L/usr/local/lib -Wl,-lgmp -lsqlite3 -lz -Wl,-lm -lpthread -ldl $(COVFLAGS) +# -L/usr/local/lib -lsqlite3 -lz -Wl,-lm -lpthread -ldl $(COVFLAGS) # But that doesn't static link. -LDLIBS = -L$(CPATH) -Wl,-dn -lgmp $(SQLITE3_LDLIBS) -lz -Wl,-dy -lm -lpthread -ldl $(COVFLAGS) +LDLIBS = -L$(CPATH) -Wl,-dn $(SQLITE3_LDLIBS) -lz -Wl,-dy -lm -lpthread -ldl $(COVFLAGS) else -LDLIBS = -L$(CPATH) -lm -lgmp $(SQLITE3_LDLIBS) -lz $(COVFLAGS) +LDLIBS = -L$(CPATH) -lm $(SQLITE3_LDLIBS) -lz $(COVFLAGS) endif # If we have the postgres client library we need to link against it as well @@ -306,14 +291,6 @@ config.vars: %.o: %.c @$(call VERBOSE, "cc $<", $(CC) $(CFLAGS) -c -o $@ $<) -# '_exp' inserted before _wiregen.[ch] to demark experimental -# spec-derived headers, which are *not* committed into git. -ifeq ($(EXPERIMENTAL_FEATURES),1) -EXP := _exp -else -EXP := -endif - # tools/update-mocks.sh does nasty recursive make, must not do this! ifeq ($(SUPPRESS_GENERATION),1) SHA256STAMP_CHANGED = false @@ -424,6 +401,16 @@ PKGLIBEXEC_PROGRAMS = \ lightningd/lightning_openingd \ lightningd/lightning_websocketd +mkdocs.yml: $(MANPAGES:=.md) + @$(call VERBOSE, "genidx $@", \ + find doc -maxdepth 1 -name '*\.[0-9]\.md' | \ + cut -b 5- | LC_ALL=C sort | \ + sed 's/\(.*\)\.\(.*\).*\.md/- "\1": "\1.\2.md"/' | \ + python3 devtools/blockreplace.py mkdocs.yml manpages --language=yml --indent " " \ + ) + + + # Don't delete these intermediaries. .PRECIOUS: $(ALL_GEN_HEADERS) $(ALL_GEN_SOURCES) @@ -472,6 +459,13 @@ else PYTHONPATH=$(MY_CHECK_PYTHONPATH) TEST_DEBUG=1 DEVELOPER=$(DEVELOPER) VALGRIND=$(VALGRIND) $(PYTEST) tests/ $(PYTEST_OPTS) endif +check-fuzz: $(ALL_FUZZ_TARGETS) +ifneq ($(FUZZING),0) + @tests/fuzz/check-fuzz.sh +else + @echo "fuzzing is not enabled: first run './configure --enable-fuzzing'" +endif + # Keep includes in alpha order. check-src-include-order/%: % @if [ "$$(grep '^#include' < $<)" != "$$(grep '^#include' < $< | $(SORT))" ]; then echo "$<:1: includes out of order"; grep '^#include' < $<; echo VERSUS; grep '^#include' < $< | $(SORT); exit 1; fi @@ -589,11 +583,12 @@ CHECK_GEN_ALL = \ $(ALL_GEN_HEADERS) \ $(ALL_GEN_SOURCES) \ wallet/statements_gettextgen.po \ - .msggen.json + .msggen.json \ + doc/index.rst check-gen-updated: $(CHECK_GEN_ALL) @echo "Checking for generated files being changed by make" - git diff --exit-code HEAD $? + git diff --exit-code HEAD coverage/coverage.info: check pytest mkdir coverage || true @@ -724,11 +719,11 @@ pyln-release-%: cd contrib/pyln-$* && $(MAKE) prod-release # These must both be enabled for update-mocks -ifeq ($(DEVELOPER)$(EXPERIMENTAL_FEATURES),11) +ifeq ($(DEVELOPER),1) update-mocks: $(ALL_TEST_PROGRAMS:%=update-mocks/%.c) else update-mocks: - @echo Need DEVELOPER=1 and EXPERIMENTAL_FEATURES=1 to regenerate mocks >&2; exit 1 + @echo Need DEVELOPER=1 to regenerate mocks >&2; exit 1 endif $(ALL_TEST_PROGRAMS:%=update-mocks/%.c): $(ALL_GEN_HEADERS) $(EXTERNAL_LIBS) libccan.a ccan/ccan/cdump/tools/cdump-enumstr config.vars @@ -808,8 +803,7 @@ install: install-program install-data # phase. If you get a missing file/executable while testing on CI it # is likely missing from this variable. TESTBINS = \ - target/${RUST_PROFILE}/examples/cln-rpc-getinfo \ - target/${RUST_PROFILE}/examples/cln-plugin-startup \ + $(CLN_PLUGIN_EXAMPLES) \ tests/plugins/test_libplugin \ tests/plugins/test_selfdisable_after_getmanifest \ tools/hsmtool diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000000..a56ee308c423 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,24 @@ +# Security Policy + +## Supported Versions + +We have a 3 month release cycle, and the last two versions are supported. + +## Reporting a Vulnerability + +To report security issues send an email to rusty@rustcorp.com.au, or +security@bockstream.com (not for support). + +## Signatures For Releases + +The following keys may be used to communicate sensitive information to +developers, and to validate signatures on releases: + +| Name | Fingerprint | +|------|-------------| +| Rusty Russell | 15EE 8D6C AB0E 7F0C F999 BFCB D920 0E6C D1AD B8F1 | +| Christian Decker | B731 AAC5 21B0 1385 9313 F674 A26D 6D9F E088 ED58 | +| Lisa Neigut | 30DE 693A E0DE 9E37 B3E7 EB6B BFF0 F678 10C1 EED1 | +| Alex Myers | 0437 4E42 789B BBA9 462E 4767 F3BF 63F2 7474 36AB | + +You can import a key by running the following command with that individual’s fingerprint: `gpg --keyserver hkps://keys.openpgp.org --recv-keys ""` Ensure that you put quotes around fingerprints containing spaces. diff --git a/bitcoin/feerate.c b/bitcoin/feerate.c index fc73423940db..7788ebb2d3ba 100644 --- a/bitcoin/feerate.c +++ b/bitcoin/feerate.c @@ -1,8 +1,12 @@ #include "config.h" +#include #include u32 feerate_from_style(u32 feerate, enum feerate_style style) { + /* Make sure it's called somewhere! */ + assert(feerate_floor_check() == FEERATE_FLOOR); + switch (style) { case FEERATE_PER_KSIPA: return feerate; diff --git a/bitcoin/feerate.h b/bitcoin/feerate.h index 43bec21181d5..cab1e95e258c 100644 --- a/bitcoin/feerate.h +++ b/bitcoin/feerate.h @@ -39,7 +39,7 @@ enum feerate_style { FEERATE_PER_KBYTE }; -static inline u32 feerate_floor(void) +static inline u32 feerate_floor_check(void) { /* Assert that bitcoind will see this as above minRelayTxFee */ BUILD_ASSERT(FEERATE_BITCOIND_SEES(FEERATE_FLOOR, MINIMUM_TX_WEIGHT) diff --git a/bitcoin/psbt.c b/bitcoin/psbt.c index 13692c50b9f7..446edf67a126 100644 --- a/bitcoin/psbt.c +++ b/bitcoin/psbt.c @@ -17,46 +17,24 @@ static void psbt_destroy(struct wally_psbt *psbt) wally_psbt_free(psbt); } -static struct wally_psbt *init_psbt(const tal_t *ctx, size_t num_inputs, size_t num_outputs) +struct wally_psbt *create_psbt(const tal_t *ctx, size_t num_inputs, size_t num_outputs, u32 locktime) { - int wally_err; + const u32 init_flags = is_elements(chainparams) ? WALLY_PSBT_INIT_PSET : 0; struct wally_psbt *psbt; + int wally_err; tal_wally_start(); - if (is_elements(chainparams)) - wally_err = wally_psbt_elements_init_alloc(0, num_inputs, num_outputs, 0, &psbt); - else - wally_err = wally_psbt_init_alloc(0, num_inputs, num_outputs, 0, &psbt); + wally_err = wally_psbt_init_alloc(2, num_inputs, num_outputs, 0, init_flags, &psbt); assert(wally_err == WALLY_OK); + wally_psbt_set_fallback_locktime(psbt, locktime); + /* By default we are modifying them internally; allow it */ + wally_psbt_set_tx_modifiable_flags(psbt, WALLY_PSBT_TXMOD_INPUTS | WALLY_PSBT_TXMOD_OUTPUTS); tal_add_destructor(psbt, psbt_destroy); tal_wally_end_onto(ctx, psbt, struct wally_psbt); return psbt; } -struct wally_psbt *create_psbt(const tal_t *ctx, size_t num_inputs, size_t num_outputs, u32 locktime) -{ - int wally_err; - struct wally_tx *wtx; - struct wally_psbt *psbt; - - tal_wally_start(); - if (wally_tx_init_alloc(WALLY_TX_VERSION_2, locktime, num_inputs, num_outputs, &wtx) != WALLY_OK) - abort(); - /* wtx is freed below */ - tal_wally_end(NULL); - - psbt = init_psbt(ctx, num_inputs, num_outputs); - - tal_wally_start(); - wally_err = wally_psbt_set_global_tx(psbt, wtx); - assert(wally_err == WALLY_OK); - tal_wally_end(psbt); - - wally_tx_free(wtx); - return psbt; -} - struct wally_psbt *clone_psbt(const tal_t *ctx, struct wally_psbt *psbt) { struct wally_psbt *clone; @@ -72,17 +50,17 @@ struct wally_psbt *new_psbt(const tal_t *ctx, const struct wally_tx *wtx) struct wally_psbt *psbt; int wally_err; - psbt = init_psbt(ctx, wtx->num_inputs, wtx->num_outputs); + psbt = create_psbt(ctx, wtx->num_inputs, wtx->num_outputs, wtx->locktime); tal_wally_start(); - /* Set directly: avoids psbt checks for non-NULL scripts/witnesses */ - wally_err = wally_tx_clone_alloc(wtx, 0, &psbt->tx); - assert(wally_err == WALLY_OK); - /* Inputs/outs are pre-allocated above, 'add' them as empty dummies */ - psbt->num_inputs = wtx->num_inputs; - psbt->num_outputs = wtx->num_outputs; + + /* locktime and modifiable flags are set in create_psbt */ + wally_psbt_set_tx_version(psbt, wtx->version); for (size_t i = 0; i < wtx->num_inputs; i++) { + wally_err = wally_psbt_add_tx_input_at(psbt, i, 0, &wtx->inputs[i]); + assert(wally_err == WALLY_OK); + /* add these scripts + witnesses to the psbt */ if (wtx->inputs[i].script) { wally_err = @@ -90,24 +68,19 @@ struct wally_psbt *new_psbt(const tal_t *ctx, const struct wally_tx *wtx) wtx->inputs[i].script, wtx->inputs[i].script_len); assert(wally_err == WALLY_OK); - - /* Clear out script sig data */ - psbt->tx->inputs[i].script_len = 0; - tal_free(psbt->tx->inputs[i].script); - psbt->tx->inputs[i].script = NULL; } if (wtx->inputs[i].witness) { wally_err = wally_psbt_input_set_final_witness(&psbt->inputs[i], wtx->inputs[i].witness); assert(wally_err == WALLY_OK); - - /* Delete the witness data */ - wally_tx_witness_stack_free(psbt->tx->inputs[i].witness); - psbt->tx->inputs[i].witness = NULL; } } + for (size_t i = 0; i < wtx->num_outputs; i++) { + wally_psbt_add_tx_output_at(psbt, i, 0, &wtx->outputs[i]); + } + tal_wally_end(psbt); return psbt; } @@ -128,7 +101,7 @@ struct wally_psbt_input *psbt_add_input(struct wally_psbt *psbt, int wally_err; tal_wally_start(); - wally_err = wally_psbt_add_input_at(psbt, insert_at, flags, input); + wally_err = wally_psbt_add_tx_input_at(psbt, insert_at, flags, input); assert(wally_err == WALLY_OK); tal_wally_end(psbt); return &psbt->inputs[insert_at]; @@ -168,7 +141,7 @@ struct wally_psbt_input *psbt_append_input(struct wally_psbt *psbt, abort(); } - wally_err = wally_psbt_add_input_at(psbt, input_num, flags, tx_in); + wally_err = wally_psbt_add_tx_input_at(psbt, input_num, flags, tx_in); assert(wally_err == WALLY_OK); wally_tx_input_free(tx_in); tal_wally_end(psbt); @@ -204,7 +177,7 @@ struct wally_psbt_output *psbt_add_output(struct wally_psbt *psbt, int wally_err; tal_wally_start(); - wally_err = wally_psbt_add_output_at(psbt, insert_at, 0, output); + wally_err = wally_psbt_add_tx_output_at(psbt, insert_at, 0, output); assert(wally_err == WALLY_OK); tal_wally_end(psbt); return &psbt->outputs[insert_at]; @@ -214,13 +187,9 @@ struct wally_psbt_output *psbt_append_output(struct wally_psbt *psbt, const u8 *script, struct amount_sat amount) { - struct wally_psbt_output *out; - struct wally_tx_output *tx_out = wally_tx_output(NULL, script, amount); - - out = psbt_add_output(psbt, tx_out, psbt->tx->num_outputs); - wally_tx_output_free(tx_out); - return out; + return psbt_insert_output(psbt, script, amount, psbt->num_outputs); } + struct wally_psbt_output *psbt_insert_output(struct wally_psbt *psbt, const u8 *script, struct amount_sat amount, @@ -264,7 +233,7 @@ void psbt_input_add_pubkey(struct wally_psbt *psbt, size_t in, pubkey_to_der(pk_der, pubkey); tal_wally_start(); - wally_err = wally_psbt_input_add_keypath_item(&psbt->inputs[in], + wally_err = wally_psbt_input_keypath_add(&psbt->inputs[in], pk_der, sizeof(pk_der), fingerprint, sizeof(fingerprint), empty_path, ARRAY_SIZE(empty_path)); @@ -361,7 +330,7 @@ void psbt_elements_input_set_asset(struct wally_psbt *psbt, size_t in, tal_wally_start(); if (asset->value > 0) - if (wally_psbt_input_set_value(&psbt->inputs[in], + if (wally_psbt_input_set_amount(&psbt->inputs[in], asset->value) != WALLY_OK) abort(); @@ -375,7 +344,6 @@ void psbt_elements_input_set_asset(struct wally_psbt *psbt, size_t in, void psbt_elements_normalize_fees(struct wally_psbt *psbt) { - struct amount_asset asset; size_t fee_output_idx = psbt->num_outputs; if (!is_elements(chainparams)) @@ -383,15 +351,15 @@ void psbt_elements_normalize_fees(struct wally_psbt *psbt) /* Elements requires that every input value is accounted for, * including the fees */ - struct amount_sat total_in = AMOUNT_SAT(0), val; + struct amount_sat total_fee = AMOUNT_SAT(0), val; for (size_t i = 0; i < psbt->num_inputs; i++) { val = psbt_input_get_amount(psbt, i); - if (!amount_sat_add(&total_in, total_in, val)) + if (!amount_sat_add(&total_fee, total_fee, val)) return; } for (size_t i = 0; i < psbt->num_outputs; i++) { - asset = wally_tx_output_get_amount(&psbt->tx->outputs[i]); - if (elements_wtx_output_is_fee(psbt->tx, i)) { + struct amount_asset output_amount = wally_psbt_output_get_amount(&psbt->outputs[i]); + if (elements_psbt_output_is_fee(psbt, i)) { if (fee_output_idx == psbt->num_outputs) { fee_output_idx = i; continue; @@ -401,40 +369,47 @@ void psbt_elements_normalize_fees(struct wally_psbt *psbt) psbt_rm_output(psbt, i--); continue; } - if (!amount_asset_is_main(&asset)) + if (!amount_asset_is_main(&output_amount)) continue; - if (!amount_sat_sub(&total_in, total_in, - amount_asset_to_sat(&asset))) + if (!amount_sat_sub(&total_fee, total_fee, + amount_asset_to_sat(&output_amount))) return; } - if (amount_sat_eq(total_in, AMOUNT_SAT(0))) + if (amount_sat_eq(total_fee, AMOUNT_SAT(0))) return; /* We need to add a fee output */ if (fee_output_idx == psbt->num_outputs) { - psbt_append_output(psbt, NULL, total_in); + psbt_append_output(psbt, NULL, total_fee); } else { - u64 sats = total_in.satoshis; /* Raw: wally API */ - struct wally_tx_output *out = &psbt->tx->outputs[fee_output_idx]; - if (wally_tx_confidential_value_from_satoshi( - sats, out->value, out->value_len) != WALLY_OK) - return; + int ret; + u64 sats = total_fee.satoshis; /* Raw: wally API */ + struct wally_psbt_output *out = &psbt->outputs[fee_output_idx]; + ret = wally_psbt_output_set_amount(out, sats); + assert(ret == WALLY_OK); } } +void wally_psbt_input_get_txid(const struct wally_psbt_input *in, + struct bitcoin_txid *txid) +{ + BUILD_ASSERT(sizeof(struct bitcoin_txid) == sizeof(in->txhash)); + memcpy(txid, in->txhash, sizeof(struct bitcoin_txid)); +} + bool psbt_has_input(const struct wally_psbt *psbt, const struct bitcoin_outpoint *outpoint) { for (size_t i = 0; i < psbt->num_inputs; i++) { struct bitcoin_txid in_txid; - struct wally_tx_input *in = &psbt->tx->inputs[i]; + const struct wally_psbt_input *in = &psbt->inputs[i]; if (outpoint->n != in->index) continue; - wally_tx_input_get_txid(in, &in_txid); + wally_psbt_input_get_txid(in, &in_txid); if (bitcoin_txid_eq(&outpoint->txid, &in_txid)) return true; } @@ -452,7 +427,7 @@ struct amount_sat psbt_input_get_amount(const struct wally_psbt *psbt, assert(amount_asset_is_main(&amt_asset)); val = amount_asset_to_sat(&amt_asset); } else if (psbt->inputs[in].utxo) { - int idx = psbt->tx->inputs[in].index; + int idx = psbt->inputs[in].index; struct wally_tx *prev_tx = psbt->inputs[in].utxo; val = amount_sat(prev_tx->outputs[idx].satoshi); } else @@ -466,7 +441,7 @@ struct amount_sat psbt_output_get_amount(const struct wally_psbt *psbt, { struct amount_asset asset; assert(out < psbt->num_outputs); - asset = wally_tx_output_get_amount(&psbt->tx->outputs[out]); + asset = wally_psbt_output_get_amount(&psbt->outputs[out]); assert(amount_asset_is_main(&asset)); return amount_asset_to_sat(&asset); } @@ -505,7 +480,7 @@ u8 *psbt_make_key(const tal_t *ctx, u8 key_subtype, const u8 *key_data) *** */ u8 *key = tal_arr(ctx, u8, 0); - add_type(&key, PSBT_PROPRIETARY_TYPE); + add_type(&key, WALLY_PSBT_PROPRIETARY_TYPE); add_varint(&key, strlen(LIGHTNING_PROPRIETARY_PREFIX)); add(&key, LIGHTNING_PROPRIETARY_PREFIX, strlen(LIGHTNING_PROPRIETARY_PREFIX)); @@ -616,9 +591,11 @@ bool psbt_finalize(struct wally_psbt *psbt) for (size_t i = 0; i < psbt->num_inputs; i++) { struct wally_psbt_input *input = &psbt->inputs[i]; struct wally_tx_witness_stack *stack; + const struct wally_map_item *iws; - if (!is_anchor_witness_script(input->witness_script, - input->witness_script_len)) + iws = wally_map_get_integer(&input->psbt_fields, /* PSBT_IN_WITNESS_SCRIPT */ 0x05); + if (!iws || !is_to_remote_anchored_witness_script(iws->value, + iws->value_len)) continue; if (input->signatures.num_items != 1) @@ -643,12 +620,12 @@ bool psbt_finalize(struct wally_psbt *psbt) input->signatures.items[0].value, input->signatures.items[0].value_len); wally_tx_witness_stack_add(stack, - input->witness_script, - input->witness_script_len); + iws->value, + iws->value_len); wally_psbt_input_set_final_witness(input, stack); } - ok = (wally_psbt_finalize(psbt) == WALLY_OK); + ok = (wally_psbt_finalize(psbt, 0 /* flags */) == WALLY_OK); tal_wally_end(psbt); return ok && psbt_is_finalized(psbt); @@ -662,7 +639,7 @@ struct wally_tx *psbt_final_tx(const tal_t *ctx, const struct wally_psbt *psbt) return NULL; tal_wally_start(); - if (wally_psbt_extract(psbt, &wtx) == WALLY_OK) + if (wally_psbt_extract(psbt, /* flags */ 0, &wtx) == WALLY_OK) tal_add_destructor(wtx, wally_tx_destroy); else wtx = NULL; @@ -679,7 +656,7 @@ struct wally_psbt *psbt_from_b64(const tal_t *ctx, char *str = tal_strndup(tmpctx, b64, b64len); tal_wally_start(); - if (wally_psbt_from_base64(str, &psbt) == WALLY_OK) + if (wally_psbt_from_base64(str, /* flags */ 0, &psbt) == WALLY_OK) tal_add_destructor(psbt, psbt_destroy); else psbt = NULL; @@ -713,7 +690,9 @@ const u8 *psbt_get_bytes(const tal_t *ctx, const struct wally_psbt *psbt, return NULL; } - wally_psbt_get_length(psbt, 0, &len); + if (wally_psbt_get_length(psbt, 0, &len) != WALLY_OK) { + abort(); + } bytes = tal_arr(ctx, u8, len); if (wally_psbt_to_bytes(psbt, 0, bytes, len, bytes_written) != WALLY_OK || @@ -730,7 +709,7 @@ struct wally_psbt *psbt_from_bytes(const tal_t *ctx, const u8 *bytes, struct wally_psbt *psbt; tal_wally_start(); - if (wally_psbt_from_bytes(bytes, byte_len, &psbt) == WALLY_OK) + if (wally_psbt_from_bytes(bytes, byte_len, /* flags */ 0, &psbt) == WALLY_OK) tal_add_destructor(psbt, psbt_destroy); else psbt = NULL; @@ -741,12 +720,24 @@ struct wally_psbt *psbt_from_bytes(const tal_t *ctx, const u8 *bytes, void towire_wally_psbt(u8 **pptr, const struct wally_psbt *psbt) { + struct wally_psbt *psbt_copy; + /* Let's include the PSBT bytes */ size_t bytes_written; - const u8 *pbt_bytes = psbt_get_bytes(NULL, psbt, &bytes_written); + const u8 *psbt_bytes = psbt_get_bytes(NULL, psbt, &bytes_written); + + /* When sending to other processes, set to v0 for compat */ + psbt_copy = psbt_from_bytes(NULL, psbt_bytes, bytes_written); + tal_free(psbt_bytes); + if (!is_elements(chainparams)) + psbt_set_version(psbt_copy, 0); + + const u8 *psbt_bytes_copy = psbt_get_bytes(NULL, psbt_copy, &bytes_written); + towire_u32(pptr, bytes_written); - towire_u8_array(pptr, pbt_bytes, bytes_written); - tal_free(pbt_bytes); + towire_u8_array(pptr, psbt_bytes_copy, bytes_written); + tal_free(psbt_bytes_copy); + tal_free(psbt_copy); } struct wally_psbt *fromwire_wally_psbt(const tal_t *ctx, @@ -777,41 +768,29 @@ struct wally_psbt *fromwire_wally_psbt(const tal_t *ctx, tal_free(tmpbuf); #endif + /* Internally we always operate on v2 */ + psbt_set_version(psbt, 2); + return psbt; } -/* This only works on a non-final psbt because we're ALL SEGWIT! */ void psbt_txid(const tal_t *ctx, - const struct wally_psbt *psbt, struct bitcoin_txid *txid, + const struct wally_psbt *psbt, + struct bitcoin_txid *txid, struct wally_tx **wtx) { struct wally_tx *tx; + int wally_err; + assert(psbt->version == 2); - /* You can *almost* take txid of global tx. But @niftynei thought - * about this far more than me and pointed out that P2SH - * inputs would not be represented, so here we go. */ + /* We rely on wally extractor to fill out all txid-related fields including scriptSigs */ tal_wally_start(); - wally_tx_clone_alloc(psbt->tx, 0, &tx); - - for (size_t i = 0; i < tx->num_inputs; i++) { - if (psbt->inputs[i].final_scriptsig) { - wally_tx_set_input_script(tx, i, - psbt->inputs[i].final_scriptsig, - psbt->inputs[i].final_scriptsig_len); - } else if (psbt->inputs[i].redeem_script) { - u8 *script; - - /* P2SH requires push of the redeemscript, from libwally src */ - script = tal_arr(tmpctx, u8, 0); - script_push_bytes(&script, - psbt->inputs[i].redeem_script, - psbt->inputs[i].redeem_script_len); - wally_tx_set_input_script(tx, i, script, tal_bytelen(script)); - } - } - tal_wally_end_onto(ctx, tx, struct wally_tx); + wally_err = wally_psbt_extract(psbt, WALLY_PSBT_EXTRACT_NON_FINAL, &tx); + assert(wally_err == WALLY_OK); + wally_err = wally_tx_get_txid(tx, txid->shad.sha.u.u8, sizeof(txid->shad.sha.u.u8)); + assert(wally_err == WALLY_OK); + tal_wally_end(ctx); - wally_txid(tx, txid); if (wtx) *wtx = tx; else @@ -832,9 +811,9 @@ struct amount_sat psbt_compute_fee(const struct wally_psbt *psbt) } for (size_t i = 0; i < psbt->num_outputs; i++) { - asset = wally_tx_output_get_amount(&psbt->tx->outputs[i]); + asset = wally_psbt_output_get_amount(&psbt->outputs[i]); if (!amount_asset_is_main(&asset) - || elements_wtx_output_is_fee(psbt->tx, i)) + || elements_psbt_output_is_fee(psbt, i)) continue; ok = amount_sat_sub(&fee, fee, amount_asset_to_sat(&asset)); @@ -844,3 +823,93 @@ struct amount_sat psbt_compute_fee(const struct wally_psbt *psbt) return fee; } + +bool wally_psbt_input_spends(const struct wally_psbt_input *input, + const struct bitcoin_outpoint *outpoint) +{ + /* Useful, as tx_part can have some NULL inputs */ + if (!input) + return false; + BUILD_ASSERT(sizeof(outpoint->txid) == sizeof(input->txhash)); + if (input->index != outpoint->n) + return false; + if (memcmp(&outpoint->txid, input->txhash, sizeof(outpoint->txid)) != 0) + return false; + return true; +} + +void wally_psbt_input_get_outpoint(const struct wally_psbt_input *in, + struct bitcoin_outpoint *outpoint) +{ + BUILD_ASSERT(sizeof(struct bitcoin_txid) == sizeof(in->txhash)); + memcpy(&outpoint->txid, in->txhash, sizeof(struct bitcoin_txid)); + outpoint->n = in->index; +} + +const u8 *wally_psbt_output_get_script(const tal_t *ctx, + const struct wally_psbt_output *output) +{ + if (output->script == NULL) { + /* This can happen for coinbase transactions, pegin + * transactions, and elements fee outputs */ + return NULL; + } + + return tal_dup_arr(ctx, u8, output->script, output->script_len, 0); +} + +/* FIXME(cdecker) Make the caller pass in a reference to amount_asset, and + * return false if unintelligible/encrypted. (WARN UNUSED). */ +struct amount_asset +wally_psbt_output_get_amount(const struct wally_psbt_output *output) +{ + struct amount_asset amount; + size_t asset_out; + + if (chainparams->is_elements) { + if (wally_psbt_output_get_asset(output, amount.asset + 1, sizeof(amount.asset) - 1, &asset_out) != WALLY_OK) { + amount.value = 0; + return amount; + } + assert(asset_out == 32); + amount.asset[0] = 0x01; /* explicit */ + /* We currently only support explicit value + * asset tags, others are confidential, so + * don't even try to assign a value to it. */ + if (output->has_amount == true) { + amount.value = output->amount; + } else { + amount.value = 0; + } + } else { + /* Do not assign amount.asset, we should never touch it in + * non-elements scenarios. */ + if (output->has_amount) { + amount.value = output->amount; + } else { + abort(); + } + } + + return amount; +} + +bool elements_psbt_output_is_fee(const struct wally_psbt *psbt, size_t outnum) +{ + assert(outnum < psbt->num_outputs); + return chainparams->is_elements && + psbt->outputs[outnum].script_len == 0; +} + +bool psbt_set_version(struct wally_psbt *psbt, u32 version) +{ + bool ok; + + tal_wally_start(); + ok = wally_psbt_set_version(psbt, 0, version) == WALLY_OK; + if (ok && version == 2) { + ok &= wally_psbt_set_tx_modifiable_flags(psbt, WALLY_PSBT_TXMOD_INPUTS | WALLY_PSBT_TXMOD_OUTPUTS) == WALLY_OK; + } + tal_wally_end(psbt); + return ok; +} diff --git a/bitcoin/psbt.h b/bitcoin/psbt.h index 53ff1c4cef29..18b0351dae26 100644 --- a/bitcoin/psbt.h +++ b/bitcoin/psbt.h @@ -29,7 +29,7 @@ struct wally_psbt *create_psbt(const tal_t *ctx, size_t num_inputs, size_t num_o /* * new_psbt - Create a PSBT, using the passed in tx - * as the global_tx + * as the locktime/inputs/output psbt fields * * @ctx - allocation context * @wtx - global_tx starter kit @@ -228,6 +228,33 @@ struct amount_sat psbt_compute_fee(const struct wally_psbt *psbt); bool psbt_has_input(const struct wally_psbt *psbt, const struct bitcoin_outpoint *outpoint); +/* wally_psbt_input_spends - Returns true if PSBT input spends given outpoint + * + * @input - psbt input + * @outpoint - outpoint + */ +bool wally_psbt_input_spends(const struct wally_psbt_input *input, + const struct bitcoin_outpoint *outpoint); + +void wally_psbt_input_get_outpoint(const struct wally_psbt_input *in, + struct bitcoin_outpoint *outpoint); + +const u8 *wally_psbt_output_get_script(const tal_t *ctx, + const struct wally_psbt_output *output); + +void wally_psbt_input_get_txid(const struct wally_psbt_input *in, + struct bitcoin_txid *txid); + +struct amount_asset +wally_psbt_output_get_amount(const struct wally_psbt_output *output); + +/* psbt_set_version - Returns false if there was any issue with the PSBT. + * Returns true if it was a well-formed PSET and treats it as a no-op + */ +bool psbt_set_version(struct wally_psbt *psbt, u32 version); + +bool elements_psbt_output_is_fee(const struct wally_psbt *psbt, size_t outnum); + struct wally_psbt *psbt_from_b64(const tal_t *ctx, const char *b64, size_t b64len); diff --git a/bitcoin/script.c b/bitcoin/script.c index 68a26dd5bc9e..a127ce96c004 100644 --- a/bitcoin/script.c +++ b/bitcoin/script.c @@ -329,9 +329,9 @@ u8 *scriptpubkey_witness_raw(const tal_t *ctx, u8 version, * OP_CHECKSIGVERIFY MAX(1, lease_end - blockheight) OP_CHECKSEQUENCEVERIFY */ -u8 *anchor_to_remote_redeem(const tal_t *ctx, - const struct pubkey *remote_key, - u32 csv_lock) +u8 *bitcoin_wscript_to_remote_anchored(const tal_t *ctx, + const struct pubkey *remote_key, + u32 csv_lock) { u8 *script = tal_arr(ctx, u8, 0); add_push_key(&script, remote_key); @@ -339,11 +339,11 @@ u8 *anchor_to_remote_redeem(const tal_t *ctx, add_number(&script, csv_lock); add_op(&script, OP_CHECKSEQUENCEVERIFY); - assert(is_anchor_witness_script(script, tal_bytelen(script))); + assert(is_to_remote_anchored_witness_script(script, tal_bytelen(script))); return script; } -bool is_anchor_witness_script(const u8 *script, size_t script_len) +bool is_to_remote_anchored_witness_script(const u8 *script, size_t script_len) { size_t len = 34 + 1 + 1 + 1; /* With option_will_fund, the pushbytes can be up to 2 bytes more @@ -884,5 +884,7 @@ bool scripteq(const u8 *s1, const u8 *s2) if (tal_count(s1) != tal_count(s2)) return false; + if (tal_count(s1) == 0) + return true; return memcmp(s1, s2, tal_count(s1)) == 0; } diff --git a/bitcoin/script.h b/bitcoin/script.h index 89f225ae860f..a00f12cc2425 100644 --- a/bitcoin/script.h +++ b/bitcoin/script.h @@ -64,9 +64,9 @@ u8 *scriptpubkey_witness_raw(const tal_t *ctx, u8 version, const u8 *wprog, size_t wprog_size); /* To-remotekey with csv max(lease_expiry - blockheight, 1) delay. */ -u8 *anchor_to_remote_redeem(const tal_t *ctx, - const struct pubkey *remote_key, - u32 csv_lock); +u8 *bitcoin_wscript_to_remote_anchored(const tal_t *ctx, + const struct pubkey *remote_key, + u32 csv_lock); /* Create a witness which spends the 2of2. */ u8 **bitcoin_witness_2of2(const tal_t *ctx, @@ -156,8 +156,8 @@ bool is_p2wpkh(const u8 *script, struct bitcoin_address *addr); /* Is this one of the four above script types? */ bool is_known_scripttype(const u8 *script); -/* Is this an anchor witness script? */ -bool is_anchor_witness_script(const u8 *script, size_t script_len); +/* Is this a to-remote witness script (used for option_anchor_outputs)? */ +bool is_to_remote_anchored_witness_script(const u8 *script, size_t script_len); /* Are these two scripts equal? */ bool scripteq(const u8 *s1, const u8 *s2); diff --git a/bitcoin/test/run-bitcoin_block_from_hex.c b/bitcoin/test/run-bitcoin_block_from_hex.c index 4c910f8b85d8..0495e5af12c2 100644 --- a/bitcoin/test/run-bitcoin_block_from_hex.c +++ b/bitcoin/test/run-bitcoin_block_from_hex.c @@ -24,12 +24,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, @@ -63,18 +69,15 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } -/* Generated stub for is_anchor_witness_script */ -bool is_anchor_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED) -{ fprintf(stderr, "is_anchor_witness_script called!\n"); abort(); } +/* Generated stub for is_to_remote_anchored_witness_script */ +bool is_to_remote_anchored_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED) +{ fprintf(stderr, "is_to_remote_anchored_witness_script called!\n"); abort(); } /* Generated stub for pubkey_to_der */ void pubkey_to_der(u8 der[PUBKEY_CMPR_LEN] UNNEEDED, const struct pubkey *key UNNEEDED) { fprintf(stderr, "pubkey_to_der called!\n"); abort(); } /* Generated stub for pubkey_to_hash160 */ void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED) { fprintf(stderr, "pubkey_to_hash160 called!\n"); abort(); } -/* Generated stub for script_push_bytes */ -void script_push_bytes(u8 **scriptp UNNEEDED, const void *mem UNNEEDED, size_t len UNNEEDED) -{ fprintf(stderr, "script_push_bytes called!\n"); abort(); } /* Generated stub for scriptpubkey_p2wsh */ u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED) { fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); } diff --git a/bitcoin/test/run-psbt-from-tx.c b/bitcoin/test/run-psbt-from-tx.c index 5aefcb9ede3c..9fe77ea4f992 100644 --- a/bitcoin/test/run-psbt-from-tx.c +++ b/bitcoin/test/run-psbt-from-tx.c @@ -23,12 +23,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, @@ -44,18 +50,15 @@ struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED) void fromwire_sha256_double(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sha256_double *sha256d UNNEEDED) { fprintf(stderr, "fromwire_sha256_double called!\n"); abort(); } -/* Generated stub for is_anchor_witness_script */ -bool is_anchor_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED) -{ fprintf(stderr, "is_anchor_witness_script called!\n"); abort(); } +/* Generated stub for is_to_remote_anchored_witness_script */ +bool is_to_remote_anchored_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED) +{ fprintf(stderr, "is_to_remote_anchored_witness_script called!\n"); abort(); } /* Generated stub for pubkey_to_der */ void pubkey_to_der(u8 der[PUBKEY_CMPR_LEN] UNNEEDED, const struct pubkey *key UNNEEDED) { fprintf(stderr, "pubkey_to_der called!\n"); abort(); } /* Generated stub for pubkey_to_hash160 */ void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED) { fprintf(stderr, "pubkey_to_hash160 called!\n"); abort(); } -/* Generated stub for script_push_bytes */ -void script_push_bytes(u8 **scriptp UNNEEDED, const void *mem UNNEEDED, size_t len UNNEEDED) -{ fprintf(stderr, "script_push_bytes called!\n"); abort(); } /* Generated stub for scriptpubkey_p2wsh */ u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED) { fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); } @@ -105,7 +108,8 @@ int main(int argc, char *argv[]) /* Witness/scriptsig data is saved down into psbt */ assert(tx2->psbt->num_inputs == 1); - assert(tx2->psbt->inputs[0].final_scriptsig_len > 0); + const struct wally_map_item *final_scriptsig = wally_map_get_integer(&tx2->psbt->inputs[0].psbt_fields, /* PSBT_IN_FINAL_SCRIPTSIG */ 0x07); + assert(final_scriptsig->value_len > 0); assert(tx2->psbt->inputs[0].final_witness != NULL); common_shutdown(); diff --git a/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c b/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c index b387279c2ba0..582461423359 100644 --- a/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c +++ b/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c @@ -24,9 +24,15 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, @@ -38,6 +44,9 @@ struct amount_asset amount_sat_to_asset(struct amount_sat *sat UNNEEDED, const u /* Generated stub for amount_tx_fee */ struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED) { fprintf(stderr, "amount_tx_fee called!\n"); abort(); } +/* Generated stub for clone_psbt */ +struct wally_psbt *clone_psbt(const tal_t *ctx UNNEEDED, struct wally_psbt *psbt UNNEEDED) +{ fprintf(stderr, "clone_psbt called!\n"); abort(); } /* Generated stub for fromwire */ const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED) { fprintf(stderr, "fromwire called!\n"); abort(); } @@ -81,10 +90,6 @@ struct wally_psbt_input *psbt_append_input(struct wally_psbt *psbt UNNEEDED, const u8 *input_wscript UNNEEDED, const u8 *redeemscript UNNEEDED) { fprintf(stderr, "psbt_append_input called!\n"); abort(); } -/* Generated stub for psbt_elements_input_set_asset */ -void psbt_elements_input_set_asset(struct wally_psbt *psbt UNNEEDED, size_t in UNNEEDED, - struct amount_asset *asset UNNEEDED) -{ fprintf(stderr, "psbt_elements_input_set_asset called!\n"); abort(); } /* Generated stub for psbt_final_tx */ struct wally_tx *psbt_final_tx(const tal_t *ctx UNNEEDED, const struct wally_psbt *psbt UNNEEDED) { fprintf(stderr, "psbt_final_tx called!\n"); abort(); } diff --git a/bitcoin/test/run-tx-encode.c b/bitcoin/test/run-tx-encode.c index e84b4e5a0863..d99c838a496c 100644 --- a/bitcoin/test/run-tx-encode.c +++ b/bitcoin/test/run-tx-encode.c @@ -25,12 +25,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, @@ -64,18 +70,15 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u8_array */ void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } -/* Generated stub for is_anchor_witness_script */ -bool is_anchor_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED) -{ fprintf(stderr, "is_anchor_witness_script called!\n"); abort(); } +/* Generated stub for is_to_remote_anchored_witness_script */ +bool is_to_remote_anchored_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED) +{ fprintf(stderr, "is_to_remote_anchored_witness_script called!\n"); abort(); } /* Generated stub for pubkey_to_der */ void pubkey_to_der(u8 der[PUBKEY_CMPR_LEN] UNNEEDED, const struct pubkey *key UNNEEDED) { fprintf(stderr, "pubkey_to_der called!\n"); abort(); } /* Generated stub for pubkey_to_hash160 */ void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED) { fprintf(stderr, "pubkey_to_hash160 called!\n"); abort(); } -/* Generated stub for script_push_bytes */ -void script_push_bytes(u8 **scriptp UNNEEDED, const void *mem UNNEEDED, size_t len UNNEEDED) -{ fprintf(stderr, "script_push_bytes called!\n"); abort(); } /* Generated stub for scriptpubkey_p2wsh */ u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED) { fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); } diff --git a/bitcoin/tx.c b/bitcoin/tx.c index 7d575196c729..c48d255faee8 100644 --- a/bitcoin/tx.c +++ b/bitcoin/tx.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -94,6 +95,15 @@ int bitcoin_tx_add_output(struct bitcoin_tx *tx, const u8 *script, return i; } +void bitcoin_tx_remove_output(struct bitcoin_tx *tx, size_t outnum) +{ + int ret; + ret = wally_tx_remove_output(tx->wtx, outnum); + assert(ret == WALLY_OK); + ret = wally_psbt_remove_output(tx->psbt, outnum); + assert(ret == WALLY_OK); +} + bool elements_wtx_output_is_fee(const struct wally_tx *tx, int outnum) { assert(outnum < tx->num_outputs); @@ -180,7 +190,36 @@ static int elements_tx_add_fee_output(struct bitcoin_tx *tx) void bitcoin_tx_set_locktime(struct bitcoin_tx *tx, u32 locktime) { tx->wtx->locktime = locktime; - tx->psbt->tx->locktime = locktime; + tx->psbt->fallback_locktime = locktime; + tx->psbt->has_fallback_locktime = true; +} + +/* FIXME Stolen from psbt_append_input; export? */ +static struct wally_tx_input *wally_tx_input_from_outpoint_sequence(const struct bitcoin_outpoint *outpoint, + u32 sequence) +{ + struct wally_tx_input *tx_in; + if (chainparams->is_elements) { + if (wally_tx_elements_input_init_alloc(outpoint->txid.shad.sha.u.u8, + sizeof(outpoint->txid.shad.sha.u.u8), + outpoint->n, + sequence, NULL, 0, + NULL, + NULL, 0, + NULL, 0, NULL, 0, + NULL, 0, NULL, 0, + NULL, 0, NULL, + &tx_in) != WALLY_OK) + abort(); + } else { + if (wally_tx_input_init_alloc(outpoint->txid.shad.sha.u.u8, + sizeof(outpoint->txid.shad.sha.u.u8), + outpoint->n, + sequence, NULL, 0, NULL, + &tx_in) != WALLY_OK) + abort(); + } + return tx_in; } int bitcoin_tx_add_input(struct bitcoin_tx *tx, @@ -191,6 +230,7 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx, { int wally_err; int input_num = tx->wtx->num_inputs; + struct wally_tx_input *tx_input; psbt_append_input(tx->psbt, outpoint, sequence, scriptSig, @@ -205,9 +245,11 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx, scriptPubkey, amount); tal_wally_start(); + tx_input = wally_tx_input_from_outpoint_sequence(outpoint, sequence); wally_err = wally_tx_add_input(tx->wtx, - &tx->psbt->tx->inputs[input_num]); + tx_input); assert(wally_err == WALLY_OK); + wally_tx_input_free(tx_input); /* scriptsig isn't actually stored in psbt input, so add that now */ wally_tx_set_input_script(tx->wtx, input_num, @@ -215,12 +257,10 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx, tal_wally_end(tx->wtx); if (is_elements(chainparams)) { - struct amount_asset asset; /* FIXME: persist asset tags */ - asset = amount_sat_to_asset(&amount, + amount_sat_to_asset(&amount, chainparams->fee_asset_tag); /* FIXME: persist nonces */ - psbt_elements_input_set_asset(tx->psbt, input_num, &asset); } return input_num; } @@ -258,10 +298,6 @@ void bitcoin_tx_output_set_amount(struct bitcoin_tx *tx, int outnum, assert(ret == WALLY_OK); } else { output->satoshi = satoshis; - - /* update the global tx for the psbt also */ - output = &tx->psbt->tx->outputs[outnum]; - output->satoshi = satoshis; } } @@ -291,14 +327,16 @@ u8 *bitcoin_tx_output_get_witscript(const tal_t *ctx, const struct bitcoin_tx *t int outnum) { struct wally_psbt_output *out; + const struct wally_map_item *output_witness_script; assert(outnum < tx->psbt->num_outputs); out = &tx->psbt->outputs[outnum]; - if (out->witness_script_len == 0) + output_witness_script = wally_map_get_integer(&out->psbt_fields, /* PSBT_OUT_WITNESS_SCRIPT */ 0x01); + if (output_witness_script->value_len == 0) return NULL; - return tal_dup_arr(ctx, u8, out->witness_script, out->witness_script_len, 0); + return tal_dup_arr(ctx, u8, output_witness_script->value, output_witness_script->value_len, 0); } struct amount_asset bitcoin_tx_output_get_amount(const struct bitcoin_tx *tx, @@ -536,18 +574,21 @@ void bitcoin_tx_finalize(struct bitcoin_tx *tx) struct bitcoin_tx *bitcoin_tx_with_psbt(const tal_t *ctx, struct wally_psbt *psbt STEALS) { + size_t locktime; + wally_psbt_get_locktime(psbt, &locktime); struct bitcoin_tx *tx = bitcoin_tx(ctx, chainparams, - psbt->tx->num_inputs, - psbt->tx->num_outputs, - psbt->tx->locktime); + psbt->num_inputs, + psbt->num_outputs, + locktime); wally_tx_free(tx->wtx); psbt_finalize(psbt); tx->wtx = psbt_final_tx(tx, psbt); if (!tx->wtx) { tal_wally_start(); - if (wally_tx_clone_alloc(psbt->tx, 0, &tx->wtx) != WALLY_OK) + if (wally_psbt_extract(psbt, WALLY_PSBT_EXTRACT_NON_FINAL, &tx->wtx) != WALLY_OK) { tx->wtx = NULL; + } tal_wally_end_onto(tx, tx->wtx, struct wally_tx); if (!tx->wtx) return tal_free(tx); @@ -559,6 +600,30 @@ struct bitcoin_tx *bitcoin_tx_with_psbt(const tal_t *ctx, struct wally_psbt *psb return tx; } +struct bitcoin_tx *clone_bitcoin_tx(const tal_t *ctx, + const struct bitcoin_tx *tx) +{ + struct bitcoin_tx *newtx; + + if (taken(tx)) + return cast_const(struct bitcoin_tx *, tal_steal(ctx, tx)); + + newtx = tal(ctx, struct bitcoin_tx); + + newtx->chainparams = tx->chainparams; + + tal_wally_start(); + if (wally_tx_clone_alloc(tx->wtx, 0, &newtx->wtx) != WALLY_OK) + newtx->wtx = NULL; + tal_wally_end_onto(newtx, newtx->wtx, struct wally_tx); + if (!newtx->wtx) + return tal_free(newtx); + + newtx->psbt = clone_psbt(newtx, tx->psbt); + tal_add_destructor(newtx, bitcoin_tx_destroy); + return newtx; +} + static struct wally_tx *pull_wtx(const tal_t *ctx, const u8 **cursor, size_t *max) @@ -668,7 +733,7 @@ bool bitcoin_txid_to_hex(const struct bitcoin_txid *txid, return hex_encode(&rev, sizeof(rev), hexstr, hexstr_len); } -static char *fmt_bitcoin_tx(const tal_t *ctx, const struct bitcoin_tx *tx) +char *fmt_bitcoin_tx(const tal_t *ctx, const struct bitcoin_tx *tx) { u8 *lin = linearize_tx(ctx, tx); char *s = tal_hex(ctx, lin); @@ -924,3 +989,14 @@ struct amount_sat change_amount(struct amount_sat excess, u32 feerate_perkw, return excess; } + +u32 tx_feerate(const struct bitcoin_tx *tx) +{ + struct amount_sat fee = bitcoin_tx_compute_fee(tx); + + /* Fee should not overflow! */ + if (!amount_sat_mul(&fee, fee, 1000)) + abort(); + + return amount_sat_div(fee, bitcoin_tx_weight(tx)).satoshis; /* Raw: txfee */ +} diff --git a/bitcoin/tx.h b/bitcoin/tx.h index cb0903ccf40d..8bb62c50e1fb 100644 --- a/bitcoin/tx.h +++ b/bitcoin/tx.h @@ -69,6 +69,10 @@ struct bitcoin_tx *bitcoin_tx(const tal_t *ctx, varint_t input_count, varint_t output_count, u32 nlocktime); +/* Make a (deep) copy */ +struct bitcoin_tx *clone_bitcoin_tx(const tal_t *ctx, + const struct bitcoin_tx *tx TAKES); + /* This takes a raw bitcoin tx in hex. */ struct bitcoin_tx *bitcoin_tx_from_hex(const tal_t *ctx, const char *hex, size_t hexlen); @@ -100,6 +104,9 @@ int bitcoin_tx_add_output(struct bitcoin_tx *tx, const u8 *script, const u8 *wscript, struct amount_sat amount); +/* Remove one output. */ +void bitcoin_tx_remove_output(struct bitcoin_tx *tx, size_t outnum); + /* Set the locktime for a transaction */ void bitcoin_tx_set_locktime(struct bitcoin_tx *tx, u32 locktime); @@ -266,6 +273,12 @@ static inline size_t elements_tx_overhead(const struct chainparams *chainparams, */ struct amount_sat bitcoin_tx_compute_fee(const struct bitcoin_tx *tx); +/** + * Calculate the feerate for this transaction (in perkw) +*/ +u32 tx_feerate(const struct bitcoin_tx *tx); + + /* * Calculate the fees for this transaction, given a pre-computed input balance. * @@ -285,6 +298,7 @@ void towire_bitcoin_tx(u8 **pptr, const struct bitcoin_tx *tx); void towire_bitcoin_outpoint(u8 **pptr, const struct bitcoin_outpoint *outp); void fromwire_bitcoin_outpoint(const u8 **cursor, size_t *max, struct bitcoin_outpoint *outp); +char *fmt_bitcoin_tx(const tal_t *ctx, const struct bitcoin_tx *tx); /* Various weights of transaction parts. */ size_t bitcoin_tx_core_weight(size_t num_inputs, size_t num_outputs); diff --git a/ccan/README b/ccan/README index 17f9a28d1668..7f367f1cf58e 100644 --- a/ccan/README +++ b/ccan/README @@ -1,3 +1,3 @@ CCAN imported from http://ccodearchive.net. -CCAN version: init-2549-gba79e21b +CCAN version: init-2573-g882a1ac0 diff --git a/ccan/ccan/bitops/test/run.c b/ccan/ccan/bitops/test/run.c index 5dba932d4799..6bb3acf50371 100644 --- a/ccan/ccan/bitops/test/run.c +++ b/ccan/ccan/bitops/test/run.c @@ -10,7 +10,7 @@ int main(void) plan_tests(68 + 6 * (31 + 63)); for (i = 0; i < 32; i++) - ok1(bitops_ffs32(1 << i) == i+1); + ok1(bitops_ffs32(1U << i) == i+1); ok1(bitops_ffs32(0) == 0); for (i = 0; i < 64; i++) ok1(bitops_ffs64((uint64_t)1 << i) == i+1); @@ -25,19 +25,19 @@ int main(void) ok1(bitops_ffs64(0) == 0); for (i = 0; i < 32; i++) - ok1(bitops_clz32(1 << i) == 31 - i); + ok1(bitops_clz32(1U << i) == 31 - i); for (i = 0; i < 64; i++) ok1(bitops_clz64((uint64_t)1 << i) == 63 - i); /* Lower bits don't effect results */ for (i = 0; i < 32; i++) - ok1(bitops_clz32((1 << i) + (1 << i)-1) == 31 - i); + ok1(bitops_clz32((1U << i) + (1U << i)-1) == 31 - i); for (i = 0; i < 64; i++) ok1(bitops_clz64(((uint64_t)1 << i) + ((uint64_t)1 << i)-1) == 63 - i); for (i = 0; i < 32; i++) - ok1(bitops_ctz32(1 << i) == i); + ok1(bitops_ctz32(1U << i) == i); for (i = 0; i < 64; i++) ok1(bitops_ctz64((uint64_t)1 << i) == i); diff --git a/ccan/ccan/crypto/hmac_sha256/hmac_sha256.c b/ccan/ccan/crypto/hmac_sha256/hmac_sha256.c index 0392afe5c112..2238f9dc8fff 100644 --- a/ccan/ccan/crypto/hmac_sha256/hmac_sha256.c +++ b/ccan/ccan/crypto/hmac_sha256/hmac_sha256.c @@ -35,7 +35,8 @@ void hmac_sha256_init(struct hmac_sha256_ctx *ctx, * (e.g., if K is of length 20 bytes and B=64, then K will be * appended with 44 zero bytes 0x00) */ - memcpy(k_ipad, k, ksize); + if (ksize != 0) + memcpy(k_ipad, k, ksize); memset((char *)k_ipad + ksize, 0, HMAC_SHA256_BLOCKSIZE - ksize); /* diff --git a/ccan/ccan/htable/htable_type.h b/ccan/ccan/htable/htable_type.h index bb5ea086b731..0aacb7f33492 100644 --- a/ccan/ccan/htable/htable_type.h +++ b/ccan/ccan/htable/htable_type.h @@ -159,8 +159,7 @@ size_t seed, \ struct name##_iter *iter) \ { \ - /* Note &iter->i == NULL iff iter is NULL */ \ - return htable_pick(&ht->raw, seed, &iter->i); \ + return htable_pick(&ht->raw, seed, iter ? &iter->i : NULL); \ } \ static inline UNNEEDED type *name##_first(const struct name *ht, \ struct name##_iter *iter) \ diff --git a/ccan/ccan/ilog/ilog.h b/ccan/ccan/ilog/ilog.h index 9adbb8243f6c..32702b178567 100644 --- a/ccan/ccan/ilog/ilog.h +++ b/ccan/ccan/ilog/ilog.h @@ -120,7 +120,10 @@ int ilog64_nz(uint64_t _v) CONST_FUNCTION; #endif #ifdef builtin_ilog32_nz -#define ilog32(_v) (builtin_ilog32_nz(_v)&-!!(_v)) +/* This used to be builtin_ilog32_nz(_v)&-!!(_v), which means it zeroes out + * the undefined builtin_ilog32_nz(0) return. But clang UndefinedBehaviorSantizer + * complains, so do the branch: */ +#define ilog32(_v) ((_v) ? builtin_ilog32_nz(_v) : 0) #define ilog32_nz(_v) builtin_ilog32_nz(_v) #else #define ilog32_nz(_v) ilog32(_v) @@ -128,7 +131,7 @@ int ilog64_nz(uint64_t _v) CONST_FUNCTION; #endif /* builtin_ilog32_nz */ #ifdef builtin_ilog64_nz -#define ilog64(_v) (builtin_ilog64_nz(_v)&-!!(_v)) +#define ilog32(_v) ((_v) ? builtin_ilog32_nz(_v) : 0) #define ilog64_nz(_v) builtin_ilog64_nz(_v) #else #define ilog64_nz(_v) ilog64(_v) diff --git a/ccan/ccan/io/fdpass/_info b/ccan/ccan/io/fdpass/_info index ba09025aaf8e..0b10e8a8bbf4 100644 --- a/ccan/ccan/io/fdpass/_info +++ b/ccan/ccan/io/fdpass/_info @@ -32,12 +32,20 @@ * read_more, buf); * } * + * // Clean up allocation so -fsanitize=address doesn't see leak! + * static void free_buf(struct io_conn *c, struct buf *buf) + * { + * free(buf); + * } + * * // Child has received fd, start reading loop. * static struct io_plan *got_infd(struct io_conn *conn, int *infd) * { * struct buf *buf = calloc(1, sizeof(*buf)); + * struct io_conn *new_conn; * - * io_new_conn(NULL, *infd, read_more, buf); + * new_conn = io_new_conn(NULL, *infd, read_more, buf); + * io_set_finish(new_conn, free_buf, buf); * return io_close(conn); * } * // Child is receiving the fd to read into. diff --git a/ccan/ccan/mem/mem.h b/ccan/ccan/mem/mem.h index 19f69c038c67..20286dcbefd4 100644 --- a/ccan/ccan/mem/mem.h +++ b/ccan/ccan/mem/mem.h @@ -104,7 +104,7 @@ void *memcchr(void const *data, int c, size_t data_len); PURE_FUNCTION static inline bool memeq(const void *a, size_t al, const void *b, size_t bl) { - return al == bl && !memcmp(a, b, bl); + return al == bl && (al == 0 || !memcmp(a, b, bl)); } /** diff --git a/ccan/ccan/membuf/_info b/ccan/ccan/membuf/_info index bdcbce2b2f20..a859318c62ee 100644 --- a/ccan/ccan/membuf/_info +++ b/ccan/ccan/membuf/_info @@ -26,13 +26,16 @@ * * membuf_init(&charbuf, malloc(10), 10, membuf_realloc); * - * for (int i = 1; i < argc; i++) - * strcpy(membuf_add(&charbuf, strlen(argv[i])), argv[i]); + * for (int i = 1; i < argc; i++) { + * size_t len = strlen(argv[i]); + * memcpy(membuf_add(&charbuf, len), argv[i], len); + * } * * // This is dumb, we could do all at once, but shows technique. * while (membuf_num_elems(&charbuf) > 0) * printf("%c", *(char *)membuf_consume(&charbuf, 1)); * printf("\n"); + * free(membuf_cleanup(&charbuf)); * return 0; * } */ diff --git a/ccan/ccan/opt/helpers.c b/ccan/ccan/opt/helpers.c index 118e543602e0..df7ee6bb1f20 100644 --- a/ccan/ccan/opt/helpers.c +++ b/ccan/ccan/opt/helpers.c @@ -138,10 +138,11 @@ char *opt_set_floatval(const char *arg, float *f) return NULL; } -void opt_show_floatval(char buf[OPT_SHOW_LEN], const float *f) +bool opt_show_floatval(char *buf, size_t len, const float *f) { double d = *f; - opt_show_doubleval(buf, &d); + opt_show_doubleval(buf, len, &d); + return true; } char *opt_set_doubleval(const char *arg, double *d) @@ -160,9 +161,10 @@ char *opt_set_doubleval(const char *arg, double *d) return NULL; } -void opt_show_doubleval(char buf[OPT_SHOW_LEN], const double *d) +bool opt_show_doubleval(char *buf, size_t len, const double *d) { - snprintf(buf, OPT_SHOW_LEN, "%f", *d); + snprintf(buf, len, "%f", *d); + return true; } char *opt_inc_intval(int *i) @@ -196,52 +198,60 @@ char *opt_usage_and_exit(const char *extra) exit(0); } -void opt_show_bool(char buf[OPT_SHOW_LEN], const bool *b) +bool opt_show_bool(char *buf, size_t len, const bool *b) { - strncpy(buf, *b ? "true" : "false", OPT_SHOW_LEN); + strncpy(buf, *b ? "true" : "false", len); + return true; } -void opt_show_invbool(char buf[OPT_SHOW_LEN], const bool *b) +bool opt_show_invbool(char *buf, size_t len, const bool *b) { - strncpy(buf, *b ? "false" : "true", OPT_SHOW_LEN); + strncpy(buf, *b ? "false" : "true", len); + return true; } -void opt_show_charp(char buf[OPT_SHOW_LEN], char *const *p) +bool opt_show_charp(char *buf, size_t len, char *const *p) { - if (*p){ - size_t len = strlen(*p); + if (*p) { + size_t plen = strlen(*p); + if (len < 2) + return false; buf[0] = '"'; - if (len > OPT_SHOW_LEN - 2) - len = OPT_SHOW_LEN - 2; - strncpy(buf+1, *p, len); - buf[1+len] = '"'; - if (len < OPT_SHOW_LEN - 2) - buf[2+len] = '\0'; - } - else { - strncpy(buf, "(nil)", OPT_SHOW_LEN); + if (plen > len - 2) + plen = len - 2; + strncpy(buf+1, *p, plen); + buf[1+plen] = '"'; + if (plen < len - 2) + buf[2+plen] = '\0'; + return true; + } else { + return false; } } /* Show an integer value, various forms. */ -void opt_show_intval(char buf[OPT_SHOW_LEN], const int *i) +bool opt_show_intval(char *buf, size_t len, const int *i) { - snprintf(buf, OPT_SHOW_LEN, "%i", *i); + snprintf(buf, len, "%i", *i); + return true; } -void opt_show_uintval(char buf[OPT_SHOW_LEN], const unsigned int *ui) +bool opt_show_uintval(char *buf, size_t len, const unsigned int *ui) { - snprintf(buf, OPT_SHOW_LEN, "%u", *ui); + snprintf(buf, len, "%u", *ui); + return true; } -void opt_show_longval(char buf[OPT_SHOW_LEN], const long *l) +bool opt_show_longval(char *buf, size_t len, const long *l) { - snprintf(buf, OPT_SHOW_LEN, "%li", *l); + snprintf(buf, len, "%li", *l); + return true; } -void opt_show_ulongval(char buf[OPT_SHOW_LEN], const unsigned long *ul) +bool opt_show_ulongval(char *buf, size_t len, const unsigned long *ul) { - snprintf(buf, OPT_SHOW_LEN, "%lu", *ul); + snprintf(buf, len, "%lu", *ul); + return true; } /* a helper function that multiplies out an argument's kMGTPE suffix in the @@ -447,14 +457,14 @@ char * opt_set_uintval_si(const char *arg, unsigned int *u) are separate but essentially identical functions for signed and unsigned values, so that unsigned values greater than LLONG_MAX get suffixes. */ -static void show_llong_with_suffix(char buf[OPT_SHOW_LEN], long long ll, - const long long base) +static void show_llong_with_suffix(char *buf, size_t len, long long ll, + const long long base) { const char *suffixes = "kMGTPE"; int i; if (ll == 0){ /*zero is special because everything divides it (you'd get "0E")*/ - snprintf(buf, OPT_SHOW_LEN, "0"); + snprintf(buf, len, "0"); return; } for (i = 0; i < strlen(suffixes); i++){ @@ -464,19 +474,20 @@ static void show_llong_with_suffix(char buf[OPT_SHOW_LEN], long long ll, ll = tmp; } if (i == 0) - snprintf(buf, OPT_SHOW_LEN, "%"PRId64, (int64_t)ll); + snprintf(buf, len, "%"PRId64, (int64_t)ll); else - snprintf(buf, OPT_SHOW_LEN, "%"PRId64"%c", (int64_t)ll, suffixes[i - 1]); + snprintf(buf, len, "%"PRId64"%c", (int64_t)ll, suffixes[i - 1]); } -static void show_ullong_with_suffix(char buf[OPT_SHOW_LEN], unsigned long long ull, +static void show_ullong_with_suffix(char *buf, size_t len, + unsigned long long ull, const unsigned base) { const char *suffixes = "kMGTPE"; int i; if (ull == 0){ /*zero is special because everything divides it (you'd get "0E")*/ - snprintf(buf, OPT_SHOW_LEN, "0"); + snprintf(buf, len, "0"); return; } for (i = 0; i < strlen(suffixes); i++){ @@ -486,72 +497,84 @@ static void show_ullong_with_suffix(char buf[OPT_SHOW_LEN], unsigned long long u ull = tmp; } if (i == 0) - snprintf(buf, OPT_SHOW_LEN, "%"PRIu64, (uint64_t)ull); + snprintf(buf, len, "%"PRIu64, (uint64_t)ull); else - snprintf(buf, OPT_SHOW_LEN, "%"PRIu64"%c", (uint64_t)ull, suffixes[i - 1]); + snprintf(buf, len, "%"PRIu64"%c", (uint64_t)ull, suffixes[i - 1]); } /* _bi, signed */ -void opt_show_intval_bi(char buf[OPT_SHOW_LEN], const int *x) +bool opt_show_intval_bi(char *buf, size_t len, const int *x) { - show_llong_with_suffix(buf, *x, 1024); + show_llong_with_suffix(buf, len, *x, 1024); + return true; } -void opt_show_longval_bi(char buf[OPT_SHOW_LEN], const long *x) +bool opt_show_longval_bi(char *buf, size_t len, const long *x) { - show_llong_with_suffix(buf, *x, 1024); + show_llong_with_suffix(buf, len, *x, 1024); + return true; } -void opt_show_longlongval_bi(char buf[OPT_SHOW_LEN], const long long *x) +bool opt_show_longlongval_bi(char *buf, size_t len, const long long *x) { - show_llong_with_suffix(buf, *x, 1024); + show_llong_with_suffix(buf, len, *x, 1024); + return true; } /* _bi, unsigned */ -void opt_show_uintval_bi(char buf[OPT_SHOW_LEN], const unsigned int *x) +bool opt_show_uintval_bi(char *buf, size_t len, const unsigned int *x) { - show_ullong_with_suffix(buf, (unsigned long long) *x, 1024); + show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1024); + return true; } -void opt_show_ulongval_bi(char buf[OPT_SHOW_LEN], const unsigned long *x) +bool opt_show_ulongval_bi(char *buf, size_t len, const unsigned long *x) { - show_ullong_with_suffix(buf, (unsigned long long) *x, 1024); + show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1024); + return true; } -void opt_show_ulonglongval_bi(char buf[OPT_SHOW_LEN], const unsigned long long *x) +bool opt_show_ulonglongval_bi(char *buf, size_t len, const unsigned long long *x) { - show_ullong_with_suffix(buf, (unsigned long long) *x, 1024); + show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1024); + return true; } /* _si, signed */ -void opt_show_intval_si(char buf[OPT_SHOW_LEN], const int *x) +bool opt_show_intval_si(char *buf, size_t len, const int *x) { - show_llong_with_suffix(buf, (long long) *x, 1000); + show_llong_with_suffix(buf, len, (long long) *x, 1000); + return true; } -void opt_show_longval_si(char buf[OPT_SHOW_LEN], const long *x) +bool opt_show_longval_si(char *buf, size_t len, const long *x) { - show_llong_with_suffix(buf, (long long) *x, 1000); + show_llong_with_suffix(buf, len, (long long) *x, 1000); + return true; } -void opt_show_longlongval_si(char buf[OPT_SHOW_LEN], const long long *x) +bool opt_show_longlongval_si(char *buf, size_t len, const long long *x) { - show_llong_with_suffix(buf, *x, 1000); + show_llong_with_suffix(buf, len, *x, 1000); + return true; } /* _si, unsigned */ -void opt_show_uintval_si(char buf[OPT_SHOW_LEN], const unsigned int *x) +bool opt_show_uintval_si(char *buf, size_t len, const unsigned int *x) { - show_ullong_with_suffix(buf, (unsigned long long) *x, 1000); + show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1000); + return true; } -void opt_show_ulongval_si(char buf[OPT_SHOW_LEN], const unsigned long *x) +bool opt_show_ulongval_si(char *buf, size_t len, const unsigned long *x) { - show_ullong_with_suffix(buf, (unsigned long long) *x, 1000); + show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1000); + return true; } -void opt_show_ulonglongval_si(char buf[OPT_SHOW_LEN], const unsigned long long *x) +bool opt_show_ulonglongval_si(char *buf, size_t len, const unsigned long long *x) { - show_ullong_with_suffix(buf, (unsigned long long) *x, 1000); + show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1000); + return true; } diff --git a/ccan/ccan/opt/opt.c b/ccan/ccan/opt/opt.c index d376a598da93..9149374cb001 100644 --- a/ccan/ccan/opt/opt.c +++ b/ccan/ccan/opt/opt.c @@ -34,7 +34,7 @@ static const char *next_name(const char *names, unsigned *len) static const char *first_opt(unsigned *i, unsigned *len) { for (*i = 0; *i < opt_count; (*i)++) { - if (opt_table[*i].type == OPT_SUBTABLE) + if (opt_table[*i].type & OPT_SUBTABLE) continue; return first_name(opt_table[*i].names, len); } @@ -44,7 +44,7 @@ static const char *first_opt(unsigned *i, unsigned *len) static const char *next_opt(const char *p, unsigned *i, unsigned *len) { for (; *i < opt_count; (*i)++) { - if (opt_table[*i].type == OPT_SUBTABLE) + if (opt_table[*i].type & OPT_SUBTABLE) continue; if (!p) return first_name(opt_table[*i].names, len); @@ -114,10 +114,11 @@ static void check_opt(const struct opt_table *entry) { const char *p; unsigned len; + enum opt_type type = entry->type & (OPT_USER_MIN-1); - if (entry->type != OPT_HASARG && entry->type != OPT_NOARG - && entry->type != (OPT_EARLY|OPT_HASARG) - && entry->type != (OPT_EARLY|OPT_NOARG)) + if (type != OPT_HASARG && type != OPT_NOARG + && type != (OPT_EARLY|OPT_HASARG) + && type != (OPT_EARLY|OPT_NOARG)) failmsg("Option %s: unknown entry type %u", entry->names, entry->type); @@ -161,7 +162,7 @@ static void add_opt(const struct opt_table *entry) void _opt_register(const char *names, enum opt_type type, char *(*cb)(void *arg), char *(*cb_arg)(const char *optarg, void *arg), - void (*show)(char buf[OPT_SHOW_LEN], const void *arg), + bool (*show)(char *buf, size_t len, const void *arg), const void *arg, const char *desc) { struct opt_table opt; @@ -181,7 +182,7 @@ bool opt_unregister(const char *names) int found = -1, i; for (i = 0; i < opt_count; i++) { - if (opt_table[i].type == OPT_SUBTABLE) + if (opt_table[i].type & OPT_SUBTABLE) continue; if (strcmp(opt_table[i].names, names) == 0) found = i; @@ -203,7 +204,7 @@ void opt_register_table(const struct opt_table entry[], const char *desc) add_opt(&heading); } for (i = 0; entry[i].type != OPT_END; i++) { - if (entry[i].type == OPT_SUBTABLE) + if (entry[i].type & OPT_SUBTABLE) opt_register_table(subtable_of(&entry[i]), entry[i].desc); else { diff --git a/ccan/ccan/opt/opt.h b/ccan/ccan/opt/opt.h index 6f4b9dda8c85..e0331be26423 100644 --- a/ccan/ccan/opt/opt.h +++ b/ccan/ccan/opt/opt.h @@ -47,10 +47,11 @@ struct opt_table; * where "type" is the type of the @arg argument. The first argument to the * @cb is the argument found on the commandline. * - * Similarly, if @show is not NULL, it should be of type "void *show(char *, - * const type *)". It should write up to OPT_SHOW_LEN bytes into the first - * argument; unless it uses the entire OPT_SHOW_LEN bytes it should - * nul-terminate that buffer. + * Similarly, if @show is not NULL, it should be of type "bool show(char *, + * size_t len, const type *)". If there is no default, it should return false, + * otherwise it should write up to len bytes into the first argument and + * return true; unless it uses the entire len bytes it should nul-terminate that + * buffer. * * Any number of equivalent short or long options can be listed in @names, * separated by '|'. Short options are a single hyphen followed by a single @@ -429,40 +430,38 @@ void opt_usage_exit_fail(const char *msg, ...) NORETURN; */ extern const char opt_hidden[]; -/* Maximum length of arg to show in opt_usage */ -#define OPT_SHOW_LEN 80 - /* Standard helpers. You can write your own: */ /* Sets the @b to true. */ char *opt_set_bool(bool *b); /* Sets @b based on arg: (yes/no/true/false). */ char *opt_set_bool_arg(const char *arg, bool *b); -void opt_show_bool(char buf[OPT_SHOW_LEN], const bool *b); +bool opt_show_bool(char *buf, size_t len, const bool *b); /* The inverse */ char *opt_set_invbool(bool *b); -void opt_show_invbool(char buf[OPT_SHOW_LEN], const bool *b); +bool opt_show_invbool(char *buf, size_t len, const bool *b); /* Sets @b based on !arg: (yes/no/true/false). */ char *opt_set_invbool_arg(const char *arg, bool *b); /* Set a char *. */ char *opt_set_charp(const char *arg, char **p); -void opt_show_charp(char buf[OPT_SHOW_LEN], char *const *p); +/* If *p is NULL, this returns false (i.e. doesn't show a default) */ +bool opt_show_charp(char *buf, size_t len, char *const *p); /* Set an integer value, various forms. Sets to 1 on arg == NULL. */ char *opt_set_intval(const char *arg, int *i); -void opt_show_intval(char buf[OPT_SHOW_LEN], const int *i); +bool opt_show_intval(char *buf, size_t len, const int *i); char *opt_set_uintval(const char *arg, unsigned int *ui); -void opt_show_uintval(char buf[OPT_SHOW_LEN], const unsigned int *ui); +bool opt_show_uintval(char *buf, size_t len, const unsigned int *ui); char *opt_set_longval(const char *arg, long *l); -void opt_show_longval(char buf[OPT_SHOW_LEN], const long *l); +bool opt_show_longval(char *buf, size_t len, const long *l); char *opt_set_ulongval(const char *arg, unsigned long *ul); -void opt_show_ulongval(char buf[OPT_SHOW_LEN], const unsigned long *ul); +bool opt_show_ulongval(char *buf, size_t len, const unsigned long *ul); /* Set an floating point value, various forms. */ char *opt_set_floatval(const char *arg, float *f); -void opt_show_floatval(char buf[OPT_SHOW_LEN], const float *f); +bool opt_show_floatval(char *buf, size_t len, const float *f); char *opt_set_doubleval(const char *arg, double *d); -void opt_show_doubleval(char buf[OPT_SHOW_LEN], const double *d); +bool opt_show_doubleval(char *buf, size_t len, const double *d); /* the following setting functions accept k, M, G, T, P, or E suffixes, which multiplies the numeric value by the corresponding power of 1000 or 1024 @@ -482,19 +481,19 @@ char *opt_set_ulonglongval_bi(const char *arg, unsigned long long *ll); char *opt_set_ulonglongval_si(const char *arg, unsigned long long *ll); -void opt_show_intval_bi(char buf[OPT_SHOW_LEN], const int *x); -void opt_show_longval_bi(char buf[OPT_SHOW_LEN], const long *x); -void opt_show_longlongval_bi(char buf[OPT_SHOW_LEN], const long long *x); -void opt_show_uintval_bi(char buf[OPT_SHOW_LEN], const unsigned int *x); -void opt_show_ulongval_bi(char buf[OPT_SHOW_LEN], const unsigned long *x); -void opt_show_ulonglongval_bi(char buf[OPT_SHOW_LEN], const unsigned long long *x); +bool opt_show_intval_bi(char *buf, size_t len, const int *x); +bool opt_show_longval_bi(char *buf, size_t len, const long *x); +bool opt_show_longlongval_bi(char *buf, size_t len, const long long *x); +bool opt_show_uintval_bi(char *buf, size_t len, const unsigned int *x); +bool opt_show_ulongval_bi(char *buf, size_t len, const unsigned long *x); +bool opt_show_ulonglongval_bi(char *buf, size_t len, const unsigned long long *x); -void opt_show_intval_si(char buf[OPT_SHOW_LEN], const int *x); -void opt_show_longval_si(char buf[OPT_SHOW_LEN], const long *x); -void opt_show_longlongval_si(char buf[OPT_SHOW_LEN], const long long *x); -void opt_show_uintval_si(char buf[OPT_SHOW_LEN], const unsigned int *x); -void opt_show_ulongval_si(char buf[OPT_SHOW_LEN], const unsigned long *x); -void opt_show_ulonglongval_si(char buf[OPT_SHOW_LEN], const unsigned long long *x); +bool opt_show_intval_si(char *buf, size_t len, const int *x); +bool opt_show_longval_si(char *buf, size_t len, const long *x); +bool opt_show_longlongval_si(char *buf, size_t len, const long long *x); +bool opt_show_uintval_si(char *buf, size_t len, const unsigned int *x); +bool opt_show_ulongval_si(char *buf, size_t len, const unsigned long *x); +bool opt_show_ulonglongval_si(char *buf, size_t len, const unsigned long long *x); @@ -509,6 +508,30 @@ char *opt_version_and_exit(const char *version); /* Display usage string to stdout, exit(0). */ char *opt_usage_and_exit(const char *extra); +/** + * opt_find_long: low-level access to the parser + * @arg: string of form 'arg' or 'arg=val'. + * @optarg: set to `val` of present in arg, otherwise NULL. Can be NULL. + * + * Returns NULL if option is unknown. Sets *@optarg to NULL if + * there's no '='. + */ +struct opt_table *opt_find_long(const char *arg, const char **optarg); + +/** + * opt_find_short: low-level access to the parser + * @arg: character representing short option + * + * Returns NULL if option is unknown. + */ +struct opt_table *opt_find_short(char arg); + +/* opt_type bits reserved for users to play with (ignored!). + * You can set bits in type e.g. (1<type & OPT_NOARG) { if (optarg) return parse_err(errlog, argv[0], o, len, "doesn't allow an argument"); - if ((opt_table[i].type & OPT_EARLY) == is_early) - problem = opt_table[i].cb(opt_table[i].u.arg); + if ((ot->type & OPT_EARLY) == is_early) + problem = ot->cb(ot->u.arg); } else { if (!optarg) { /* Swallow any short options as optarg, eg -afile */ @@ -117,9 +158,8 @@ int parse_one(int *argc, char *argv[], enum opt_type is_early, unsigned *offset, if (!optarg) return parse_err(errlog, argv[0], o, len, "requires an argument"); - if ((opt_table[i].type & OPT_EARLY) == is_early) - problem = opt_table[i].cb_arg(optarg, - opt_table[i].u.arg); + if ((ot->type & OPT_EARLY) == is_early) + problem = ot->cb_arg(optarg, ot->u.arg); } if (problem) { diff --git a/ccan/ccan/opt/test/run-add_desc.c b/ccan/ccan/opt/test/run-add_desc.c index b559c7f74768..03e6986dd191 100644 --- a/ccan/ccan/opt/test/run-add_desc.c +++ b/ccan/ccan/opt/test/run-add_desc.c @@ -4,15 +4,24 @@ #include #include -static void show_10(char buf[OPT_SHOW_LEN], const void *arg UNNEEDED) +static bool show_10(char *buf, size_t len, const void *arg UNNEEDED) { memset(buf, 'X', 10); buf[10] = '\0'; + return true; } -static void show_max(char buf[OPT_SHOW_LEN], const void *arg UNNEEDED) +static bool show_10_false(char *buf, size_t len, const void *arg UNNEEDED) +{ + memset(buf, 'X', 10); + buf[10] = '\0'; + return false; +} + +static bool show_max(char *buf, size_t len, const void *arg UNNEEDED) { memset(buf, 'X', OPT_SHOW_LEN); + return true; } /* Test add_desc helper. */ @@ -22,7 +31,7 @@ int main(void) char *ret; size_t len, max; - plan_tests(30); + plan_tests(32); opt.show = NULL; opt.names = "01234"; @@ -113,6 +122,14 @@ int main(void) " (default: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...)\n") == 0); free(ret); len = max = 0; + /* With show function which fails doesn't print. */ + opt.show = show_10_false; + ret = add_desc(NULL, &len, &max, 7, 41, &opt); + ok1(len < max); + ret[len] = '\0'; + ok1(strcmp(ret, "01234 0123456789 0\n") == 0); + free(ret); len = max = 0; + /* With added " ". Fits, just. */ opt.show = NULL; opt.type = OPT_HASARG; diff --git a/ccan/ccan/opt/test/run-correct-reporting.c b/ccan/ccan/opt/test/run-correct-reporting.c index 8534f291ac3e..0c4f6c869397 100644 --- a/ccan/ccan/opt/test/run-correct-reporting.c +++ b/ccan/ccan/opt/test/run-correct-reporting.c @@ -10,7 +10,7 @@ int main(int argc, char *argv[]) { - plan_tests(12); + plan_tests(14); /* --aaa without args. */ opt_register_arg("-a|--aaa", test_arg, NULL, "aaa", ""); @@ -42,6 +42,10 @@ int main(int argc, char *argv[]) free(err_output); err_output = NULL; + opt_register_noarg("-d", test_noarg, NULL, ""); + ok1(!parse_args(&argc, &argv, "-dc", NULL)); + ok1(strstr(err_output, ": -c: requires an argument")); + /* parse_args allocates argv */ free(argv); return exit_status(); diff --git a/ccan/ccan/opt/test/run-helpers.c b/ccan/ccan/opt/test/run-helpers.c index 0a08a85f7aa3..9aa41fe8db62 100644 --- a/ccan/ccan/opt/test/run-helpers.c +++ b/ccan/ccan/opt/test/run-helpers.c @@ -476,26 +476,26 @@ int main(int argc, char *argv[]) char buf[OPT_SHOW_LEN+2] = { 0 }; buf[OPT_SHOW_LEN] = '!'; i = -77; - opt_show_intval_bi(buf, &i); + opt_show_intval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "-77") == 0); i = 0; - opt_show_intval_bi(buf, &i); + opt_show_intval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "0") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 77; - opt_show_intval_bi(buf, &i); + opt_show_intval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "77") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = -1234 * k; - opt_show_intval_bi(buf, &i); + opt_show_intval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "-1234k") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 500 * M; - opt_show_intval_bi(buf, &i); + opt_show_intval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "500M") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 1024 * M; - opt_show_intval_bi(buf, &i); + opt_show_intval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "1G") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -506,27 +506,27 @@ int main(int argc, char *argv[]) char buf[OPT_SHOW_LEN+2] = { 0 }; buf[OPT_SHOW_LEN] = '!'; i = -77; - opt_show_longval_bi(buf, &i); + opt_show_longval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "-77") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 77; - opt_show_longval_bi(buf, &i); + opt_show_longval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "77") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = -1 * k; - opt_show_longval_bi(buf, &i); + opt_show_longval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "-1k") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 500 * M; - opt_show_longval_bi(buf, &i); + opt_show_longval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "500M") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 1024 * M; - opt_show_longval_bi(buf, &i); + opt_show_longval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "1G") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 0; - opt_show_longval_bi(buf, &i); + opt_show_longval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "0") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -537,23 +537,23 @@ int main(int argc, char *argv[]) char buf[OPT_SHOW_LEN+2] = { 0 }; buf[OPT_SHOW_LEN] = '!'; i = -7777; - opt_show_longlongval_bi(buf, &i); + opt_show_longlongval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "-7777") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 7777; - opt_show_longlongval_bi(buf, &i); + opt_show_longlongval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "7777") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = -10240000 * k; - opt_show_longlongval_bi(buf, &i); + opt_show_longlongval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "-10000M") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 5 * P; - opt_show_longlongval_bi(buf, &i); + opt_show_longlongval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "5P") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 1024 * P; - opt_show_longlongval_bi(buf, &i); + opt_show_longlongval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "1E") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -564,19 +564,19 @@ int main(int argc, char *argv[]) char buf[OPT_SHOW_LEN+2] = { 0 }; buf[OPT_SHOW_LEN] = '!'; i = 77; - opt_show_uintval_bi(buf, &i); + opt_show_uintval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "77") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 1234 * k; - opt_show_uintval_bi(buf, &i); + opt_show_uintval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "1234k") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 500 * M; - opt_show_uintval_bi(buf, &i); + opt_show_uintval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "500M") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 1024 * M; - opt_show_uintval_bi(buf, &i); + opt_show_uintval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "1G") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -587,23 +587,23 @@ int main(int argc, char *argv[]) char buf[OPT_SHOW_LEN+2] = { 0 }; buf[OPT_SHOW_LEN] = '!'; i = 77; - opt_show_ulongval_bi(buf, &i); + opt_show_ulongval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "77") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = k; - opt_show_ulongval_bi(buf, &i); + opt_show_ulongval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "1k") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 500 * M; - opt_show_ulongval_bi(buf, &i); + opt_show_ulongval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "500M") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 1024 * M; - opt_show_ulongval_bi(buf, &i); + opt_show_ulongval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "1G") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 0; - opt_show_ulongval_bi(buf, &i); + opt_show_ulongval_bi(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "0") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -614,19 +614,19 @@ int main(int argc, char *argv[]) char buf[OPT_SHOW_LEN+2] = { 0 }; buf[OPT_SHOW_LEN] = '!'; i = 7777; - opt_show_ulonglongval_bi(buf, (unsigned long long *)&i); + opt_show_ulonglongval_bi(buf, OPT_SHOW_LEN, (unsigned long long *)&i); ok1(strcmp(buf, "7777") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 10240000 * k; - opt_show_ulonglongval_bi(buf, (unsigned long long *)&i); + opt_show_ulonglongval_bi(buf, OPT_SHOW_LEN, (unsigned long long *)&i); ok1(strcmp(buf, "10000M") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 5 * P; - opt_show_ulonglongval_bi(buf, (unsigned long long *)&i); + opt_show_ulonglongval_bi(buf, OPT_SHOW_LEN, (unsigned long long *)&i); ok1(strcmp(buf, "5P") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 1024 * P; - opt_show_ulonglongval_bi(buf, (unsigned long long *)&i); + opt_show_ulonglongval_bi(buf, OPT_SHOW_LEN, (unsigned long long *)&i); ok1(strcmp(buf, "1E") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -860,26 +860,26 @@ int main(int argc, char *argv[]) char buf[OPT_SHOW_LEN+2] = { 0 }; buf[OPT_SHOW_LEN] = '!'; i = -77; - opt_show_intval_si(buf, &i); + opt_show_intval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "-77") == 0); i = 0; - opt_show_intval_si(buf, &i); + opt_show_intval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "0") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 77; - opt_show_intval_si(buf, &i); + opt_show_intval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "77") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = -1234 * k; - opt_show_intval_si(buf, &i); + opt_show_intval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "-1234k") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 500 * M; - opt_show_intval_si(buf, &i); + opt_show_intval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "500M") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 1000 * M; - opt_show_intval_si(buf, &i); + opt_show_intval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "1G") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -890,27 +890,27 @@ int main(int argc, char *argv[]) char buf[OPT_SHOW_LEN+2] = { 0 }; buf[OPT_SHOW_LEN] = '!'; i = -77; - opt_show_longval_si(buf, &i); + opt_show_longval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "-77") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 77; - opt_show_longval_si(buf, &i); + opt_show_longval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "77") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = -1 * k; - opt_show_longval_si(buf, &i); + opt_show_longval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "-1k") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 500 * M; - opt_show_longval_si(buf, &i); + opt_show_longval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "500M") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 1000 * M; - opt_show_longval_si(buf, &i); + opt_show_longval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "1G") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 0; - opt_show_longval_si(buf, &i); + opt_show_longval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "0") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -921,23 +921,23 @@ int main(int argc, char *argv[]) char buf[OPT_SHOW_LEN+2] = { 0 }; buf[OPT_SHOW_LEN] = '!'; i = -7777; - opt_show_longlongval_si(buf, &i); + opt_show_longlongval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "-7777") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 7777; - opt_show_longlongval_si(buf, &i); + opt_show_longlongval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "7777") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = -10240000 * k; - opt_show_longlongval_si(buf, &i); + opt_show_longlongval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "-10240M") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 5 * P; - opt_show_longlongval_si(buf, &i); + opt_show_longlongval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "5P") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 2000 * P; - opt_show_longlongval_si(buf, &i); + opt_show_longlongval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "2E") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -948,19 +948,19 @@ int main(int argc, char *argv[]) char buf[OPT_SHOW_LEN+2] = { 0 }; buf[OPT_SHOW_LEN] = '!'; i = 77; - opt_show_uintval_si(buf, &i); + opt_show_uintval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "77") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 1234 * k; - opt_show_uintval_si(buf, &i); + opt_show_uintval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "1234k") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 500 * M; - opt_show_uintval_si(buf, &i); + opt_show_uintval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "500M") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 1000 * M; - opt_show_uintval_si(buf, &i); + opt_show_uintval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "1G") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -971,23 +971,23 @@ int main(int argc, char *argv[]) char buf[OPT_SHOW_LEN+2] = { 0 }; buf[OPT_SHOW_LEN] = '!'; i = 77; - opt_show_ulongval_si(buf, &i); + opt_show_ulongval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "77") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = k; - opt_show_ulongval_si(buf, &i); + opt_show_ulongval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "1k") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 500 * M; - opt_show_ulongval_si(buf, &i); + opt_show_ulongval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "500M") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 1024 * M; - opt_show_ulongval_si(buf, &i); + opt_show_ulongval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "1024M") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 0; - opt_show_ulongval_si(buf, &i); + opt_show_ulongval_si(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "0") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -998,19 +998,19 @@ int main(int argc, char *argv[]) char buf[OPT_SHOW_LEN+2] = { 0 }; buf[OPT_SHOW_LEN] = '!'; i = 7777; - opt_show_ulonglongval_si(buf, (unsigned long long *)&i); + opt_show_ulonglongval_si(buf, OPT_SHOW_LEN, (unsigned long long *)&i); ok1(strcmp(buf, "7777") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 10240000 * k; - opt_show_ulonglongval_si(buf, (unsigned long long *)&i); + opt_show_ulonglongval_si(buf, OPT_SHOW_LEN, (unsigned long long *)&i); ok1(strcmp(buf, "10240M") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 5 * P; - opt_show_ulonglongval_si(buf, (unsigned long long *)&i); + opt_show_ulonglongval_si(buf, OPT_SHOW_LEN, (unsigned long long *)&i); ok1(strcmp(buf, "5P") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 1000 * P; - opt_show_ulonglongval_si(buf, (unsigned long long *)&i); + opt_show_ulonglongval_si(buf, OPT_SHOW_LEN, (unsigned long long *)&i); ok1(strcmp(buf, "1E") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -1090,12 +1090,12 @@ int main(int argc, char *argv[]) buf[OPT_SHOW_LEN] = '!'; b = true; - opt_show_bool(buf, &b); + opt_show_bool(buf, OPT_SHOW_LEN, &b); ok1(strcmp(buf, "true") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); b = false; - opt_show_bool(buf, &b); + opt_show_bool(buf, OPT_SHOW_LEN, &b); ok1(strcmp(buf, "false") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -1107,12 +1107,12 @@ int main(int argc, char *argv[]) buf[OPT_SHOW_LEN] = '!'; b = true; - opt_show_invbool(buf, &b); + opt_show_invbool(buf, OPT_SHOW_LEN, &b); ok1(strcmp(buf, "false") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); b = false; - opt_show_invbool(buf, &b); + opt_show_invbool(buf, OPT_SHOW_LEN, &b); ok1(strcmp(buf, "true") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -1126,14 +1126,14 @@ int main(int argc, char *argv[]) /* Short test. */ p = str; strcpy(p, "short"); - opt_show_charp(buf, &p); + opt_show_charp(buf, OPT_SHOW_LEN, &p); ok1(strcmp(buf, "\"short\"") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); /* Truncate test. */ memset(p, 'x', OPT_SHOW_LEN*2); p[OPT_SHOW_LEN*2-1] = '\0'; - opt_show_charp(buf, &p); + opt_show_charp(buf, OPT_SHOW_LEN, &p); ok1(buf[0] == '"'); ok1(buf[OPT_SHOW_LEN-1] == '"'); ok1(buf[OPT_SHOW_LEN] == '!'); @@ -1147,12 +1147,12 @@ int main(int argc, char *argv[]) buf[OPT_SHOW_LEN] = '!'; i = -77; - opt_show_intval(buf, &i); + opt_show_intval(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "-77") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); i = 77; - opt_show_intval(buf, &i); + opt_show_intval(buf, OPT_SHOW_LEN, &i); ok1(strcmp(buf, "77") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -1164,7 +1164,7 @@ int main(int argc, char *argv[]) buf[OPT_SHOW_LEN] = '!'; ui = 4294967295U; - opt_show_uintval(buf, &ui); + opt_show_uintval(buf, OPT_SHOW_LEN, &ui); ok1(strcmp(buf, "4294967295") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -1176,7 +1176,7 @@ int main(int argc, char *argv[]) buf[OPT_SHOW_LEN] = '!'; l = 1234567890L; - opt_show_longval(buf, &l); + opt_show_longval(buf, OPT_SHOW_LEN, &l); ok1(strcmp(buf, "1234567890") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -1188,7 +1188,7 @@ int main(int argc, char *argv[]) buf[OPT_SHOW_LEN] = '!'; ul = 4294967295UL; - opt_show_ulongval(buf, &ul); + opt_show_ulongval(buf, OPT_SHOW_LEN, &ul); ok1(strcmp(buf, "4294967295") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -1200,12 +1200,12 @@ int main(int argc, char *argv[]) buf[OPT_SHOW_LEN] = '!'; f = -77.5; - opt_show_floatval(buf, &f); + opt_show_floatval(buf, OPT_SHOW_LEN, &f); ok1(strcmp(buf, "-77.500000") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); f = 77.5; - opt_show_floatval(buf, &f); + opt_show_floatval(buf, OPT_SHOW_LEN, &f); ok1(strcmp(buf, "77.500000") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } @@ -1217,12 +1217,12 @@ int main(int argc, char *argv[]) buf[OPT_SHOW_LEN] = '!'; d = -77; - opt_show_doubleval(buf, &d); + opt_show_doubleval(buf, OPT_SHOW_LEN, &d); ok1(strcmp(buf, "-77.000000") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); d = 77; - opt_show_doubleval(buf, &d); + opt_show_doubleval(buf, OPT_SHOW_LEN, &d); ok1(strcmp(buf, "77.000000") == 0); ok1(buf[OPT_SHOW_LEN] == '!'); } diff --git a/ccan/ccan/opt/test/run-set_alloc.c b/ccan/ccan/opt/test/run-set_alloc.c index 1dbb351bedf4..2d7410ae2285 100644 --- a/ccan/ccan/opt/test/run-set_alloc.c +++ b/ccan/ccan/opt/test/run-set_alloc.c @@ -59,8 +59,8 @@ static void *reallocfn(void *ptr, size_t size) static void freefn(void *ptr) { free_count++; - free(ptr); *find_ptr(ptr) = NULL; + free(ptr); } int main(int argc, char *argv[]) diff --git a/ccan/ccan/opt/test/run-userbits.c b/ccan/ccan/opt/test/run-userbits.c new file mode 100644 index 000000000000..7f102f08ec0b --- /dev/null +++ b/ccan/ccan/opt/test/run-userbits.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include +#include "utils.h" + +int main(int argc, char *argv[]) +{ + const char *myname = argv[0]; + + plan_tests(28); + + opt_register_noarg("-a", test_noarg, NULL, "All"); + opt_register_noarg("--aaa", test_noarg, NULL, "AAAAll"); + opt_register_arg("-b|--bbb", test_arg, NULL, "bbb", "AAAAAAll"); + + ok1(strcmp(opt_table[0].names, "-a") == 0); + ok1(opt_table[0].type == OPT_NOARG); + ok1(strcmp(opt_table[1].names, "--aaa") == 0); + ok1(opt_table[1].type == OPT_NOARG); + ok1(strcmp(opt_table[2].names, "-b|--bbb") == 0); + ok1(opt_table[2].type == OPT_HASARG); + + opt_table[0].type |= (1 << OPT_USER_START); + opt_table[1].type |= ((1 << OPT_USER_END)-1) - ((1 << OPT_USER_START)-1); + opt_table[2].type |= (1 << OPT_USER_END); + + /* Should all work fine! */ + ok1(parse_args(&argc, &argv, "-a", NULL)); + ok1(argc == 1); + ok1(argv[0] == myname); + ok1(test_cb_called == 1); + + ok1(parse_args(&argc, &argv, "--aaa", NULL)); + ok1(argc == 1); + ok1(argv[0] == myname); + ok1(test_cb_called == 2); + + /* This one needs an arg. */ + ok1(parse_args(&argc, &argv, "-b", NULL) == false); + ok1(test_cb_called == 2); + ok1(parse_args(&argc, &argv, "-b", "bbb", NULL)); + ok1(argc == 1); + ok1(argv[0] == myname); + ok1(argv[1] == NULL); + ok1(test_cb_called == 3); + + ok1(parse_args(&argc, &argv, "--bbb", "bbb", NULL)); + ok1(argc == 1); + ok1(argv[0] == myname); + ok1(argv[1] == NULL); + ok1(test_cb_called == 4); + + /* parse_args allocates argv */ + free(argv); + return exit_status(); +} diff --git a/ccan/ccan/opt/test/utils.c b/ccan/ccan/opt/test/utils.c index 2ff04884ebdc..61199fb4676d 100644 --- a/ccan/ccan/opt/test/utils.c +++ b/ccan/ccan/opt/test/utils.c @@ -21,9 +21,10 @@ char *test_arg(const char *optarg, const char *arg) return NULL; } -void show_arg(char buf[OPT_SHOW_LEN], const char *arg) +bool show_arg(char *buf, size_t len, const char *arg) { - strncpy(buf, arg, OPT_SHOW_LEN); + strncpy(buf, arg, len); + return true; } char *err_output = NULL; diff --git a/ccan/ccan/opt/test/utils.h b/ccan/ccan/opt/test/utils.h index 12cf0b753e99..3ada62d117c0 100644 --- a/ccan/ccan/opt/test/utils.h +++ b/ccan/ccan/opt/test/utils.h @@ -13,7 +13,7 @@ void reset_options(void); extern unsigned int test_cb_called; char *test_noarg(void *arg); char *test_arg(const char *optarg, const char *arg); -void show_arg(char buf[OPT_SHOW_LEN], const char *arg); +bool show_arg(char *buf, size_t len, const char *arg); extern struct opt_table short_table[]; extern struct opt_table long_table[]; diff --git a/ccan/ccan/opt/usage.c b/ccan/ccan/opt/usage.c index 12f44a48752e..568e4661d809 100644 --- a/ccan/ccan/opt/usage.c +++ b/ccan/ccan/opt/usage.c @@ -20,6 +20,9 @@ const char opt_hidden[1]; #define MIN_DESC_WIDTH 40 #define MIN_TOTAL_WIDTH 50 +/* Maximum length of arg to show in opt_usage */ +#define OPT_SHOW_LEN 80 + static unsigned int get_columns(void) { int ws_col = 0; @@ -72,7 +75,8 @@ static size_t consume_words(const char *words, size_t maxlen, size_t *prefix, } } - *start = (words[oldlen - 1] == '\n'); + if (oldlen != 0) + *start = (words[oldlen - 1] == '\n'); return oldlen; } @@ -147,20 +151,20 @@ static char *add_desc(char *base, size_t *len, size_t *max, if (opt->show) { char buf[OPT_SHOW_LEN + sizeof("...")]; strcpy(buf + OPT_SHOW_LEN, "..."); - opt->show(buf, opt->u.arg); + if (opt->show(buf, OPT_SHOW_LEN, opt->u.arg)) { + /* If it doesn't fit on this line, indent. */ + if (off + strlen(" (default: ") + strlen(buf) + strlen(")") + > width) { + base = add_indent(base, len, max, indent); + } else { + /* Remove \n. */ + (*len)--; + } - /* If it doesn't fit on this line, indent. */ - if (off + strlen(" (default: ") + strlen(buf) + strlen(")") - > width) { - base = add_indent(base, len, max, indent); - } else { - /* Remove \n. */ - (*len)--; + base = add_str(base, len, max, " (default: "); + base = add_str(base, len, max, buf); + base = add_str(base, len, max, ")\n"); } - - base = add_str(base, len, max, " (default: "); - base = add_str(base, len, max, buf); - base = add_str(base, len, max, ")\n"); } return base; } @@ -181,10 +185,10 @@ char *opt_usage(const char *argv0, const char *extra) size_t l; if (opt_table[i].desc == opt_hidden) continue; - if (opt_table[i].type == OPT_SUBTABLE) + if (opt_table[i].type & OPT_SUBTABLE) continue; l = strlen(opt_table[i].names); - if (opt_table[i].type == OPT_HASARG + if ((opt_table[i].type & OPT_HASARG) && !strchr(opt_table[i].names, ' ') && !strchr(opt_table[i].names, '=')) l += strlen(" "); @@ -220,7 +224,7 @@ char *opt_usage(const char *argv0, const char *extra) for (i = 0; i < opt_count; i++) { if (opt_table[i].desc == opt_hidden) continue; - if (opt_table[i].type == OPT_SUBTABLE) { + if (opt_table[i].type & OPT_SUBTABLE) { ret = add_str(ret, &len, &max, opt_table[i].desc); ret = add_str(ret, &len, &max, ":\n"); continue; diff --git a/ccan/ccan/rbuf/rbuf.c b/ccan/ccan/rbuf/rbuf.c index d8d658d37a39..cc10cf3d7f25 100644 --- a/ccan/ccan/rbuf/rbuf.c +++ b/ccan/ccan/rbuf/rbuf.c @@ -74,9 +74,11 @@ char *rbuf_read_str(struct rbuf *rbuf, char term) ssize_t r = 0; size_t prev = 0; - while (!(p = memchr(membuf_elems(&rbuf->m) + prev, - term, - membuf_num_elems(&rbuf->m) - prev))) { + /* memchr(NULL, ..., 0) is illegal. FML. */ + while (membuf_num_elems(&rbuf->m) == prev + || !(p = memchr(membuf_elems(&rbuf->m) + prev, + term, + membuf_num_elems(&rbuf->m) - prev))) { prev += r; r = get_more(rbuf); if (r < 0) diff --git a/ccan/ccan/tal/tal.c b/ccan/ccan/tal/tal.c index 2d05dd93f73b..1230d8cacafc 100644 --- a/ccan/ccan/tal/tal.c +++ b/ccan/ccan/tal/tal.c @@ -28,7 +28,8 @@ enum prop_type { struct tal_hdr { struct list_node list; - struct prop_hdr *prop; + /* Use is_prop_hdr tell if this is a struct prop_hdr or string! */ + char *prop; /* XOR with TAL_PTR_OBFUSTICATOR */ intptr_t parent_child; size_t bytelen; @@ -36,7 +37,8 @@ struct tal_hdr { struct prop_hdr { enum prop_type type; - struct prop_hdr *next; + /* Use is_prop_hdr to tell if this is a struct prop_hdr or string! */ + char *next; }; struct children { @@ -72,7 +74,7 @@ static struct { struct tal_hdr hdr; struct children c; } null_parent = { { { &null_parent.hdr.list, &null_parent.hdr.list }, - &null_parent.c.hdr, TAL_PTR_OBFUSTICATOR, 0 }, + (char *)&null_parent.c.hdr, TAL_PTR_OBFUSTICATOR, 0 }, { { CHILDREN, NULL }, &null_parent.hdr, { { &null_parent.c.children.n, @@ -123,9 +125,11 @@ void tal_cleanup(void) } /* We carefully start all real properties with a zero byte. */ -static bool is_literal(const struct prop_hdr *prop) +static struct prop_hdr *is_prop_hdr(const char *ptr) { - return ((char *)prop)[0] != 0; + if (*ptr != 0) + return NULL; + return (struct prop_hdr *)ptr; } #ifndef NDEBUG @@ -174,8 +178,11 @@ static struct tal_hdr *to_tal_hdr(const void *ctx) check_bounds(ignore_destroying_bit(t->parent_child)); check_bounds(t->list.next); check_bounds(t->list.prev); - if (t->prop && !is_literal(t->prop)) - check_bounds(t->prop); + if (t->prop) { + struct prop_hdr *p = is_prop_hdr(t->prop); + if (p) + check_bounds(p); + } return t; } @@ -215,13 +222,12 @@ static void notify(const struct tal_hdr *ctx, enum tal_notify_type type, const void *info, int saved_errno) { - const struct prop_hdr *p; + const char *ptr; + const struct prop_hdr *p; - for (p = ctx->prop; p; p = p->next) { + for (ptr = ctx->prop; ptr && (p = is_prop_hdr(ptr)) != NULL; ptr = p->next) { struct notifier *n; - if (is_literal(p)) - break; if (p->type != NOTIFIER) continue; n = (struct notifier *)p; @@ -255,29 +261,54 @@ static void *allocate(size_t size) return ret; } -static struct prop_hdr **find_property_ptr(const struct tal_hdr *t, - enum prop_type type) +/* Returns a pointer to the pointer: can cast (*ret) to a (struct prop_ptr *) */ +static char **find_property_ptr(struct tal_hdr *t, enum prop_type type) { - struct prop_hdr **p; + char **ptr; + struct prop_hdr *p; - for (p = (struct prop_hdr **)&t->prop; *p; p = &(*p)->next) { - if (is_literal(*p)) { - if (type == NAME) - return p; - break; - } - if ((*p)->type == type) - return p; - } - return NULL; + /* NAME is special, as it can be a literal: see find_name_property */ + assert(type != NAME); + for (ptr = &t->prop; *ptr; ptr = &p->next) { + if (!is_prop_hdr(*ptr)) + break; + p = (struct prop_hdr *)*ptr; + if (p->type == type) + return ptr; + } + return NULL; +} + +/* This is special: + * NULL - not found + * *literal: true - char **, pointer to literal pointer. + * *literal: false - struct prop_hdr **, pointer to header ptr. + */ +static char **find_name_property(struct tal_hdr *t, bool *literal) +{ + char **ptr; + struct prop_hdr *p; + + for (ptr = &t->prop; *ptr; ptr = &p->next) { + if (!is_prop_hdr(*ptr)) { + *literal = true; + return ptr; + } + p = (struct prop_hdr *)*ptr; + if (p->type == NAME) { + *literal = false; + return ptr; + } + } + return NULL; } -static void *find_property(const struct tal_hdr *parent, enum prop_type type) +static void *find_property(struct tal_hdr *parent, enum prop_type type) { - struct prop_hdr **p = find_property_ptr(parent, type); + char **ptr = find_property_ptr(parent, type); - if (p) - return *p; + if (ptr) + return (struct prop_hdr *)*ptr; return NULL; } @@ -287,7 +318,7 @@ static void init_property(struct prop_hdr *hdr, { hdr->type = type; hdr->next = parent->prop; - parent->prop = hdr; + parent->prop = (char *)hdr; } static struct notifier *add_notifier_property(struct tal_hdr *t, @@ -321,17 +352,20 @@ static enum tal_notify_type del_notifier_property(struct tal_hdr *t, bool match_extra_arg, void *extra_arg) { - struct prop_hdr **p; + char **ptr; + struct prop_hdr *p; - for (p = (struct prop_hdr **)&t->prop; *p; p = &(*p)->next) { + for (ptr = &t->prop; *ptr; ptr = &p->next) { struct notifier *n; enum tal_notify_type types; - if (is_literal(*p)) + p = is_prop_hdr(*ptr); + if (!p) break; - if ((*p)->type != NOTIFIER) + + if (p->type != NOTIFIER) continue; - n = (struct notifier *)*p; + n = (struct notifier *)p; if (n->u.notifyfn != fn) continue; @@ -341,8 +375,8 @@ static enum tal_notify_type del_notifier_property(struct tal_hdr *t, && extra_arg != EXTRA_ARG(n)) continue; - *p = (*p)->next; - freefn(n); + *ptr = p->next; + freefn(p); return types & ~(NOTIFY_IS_DESTRUCTOR|NOTIFY_EXTRA_ARG); } return 0; @@ -388,7 +422,8 @@ static bool add_child(struct tal_hdr *parent, struct tal_hdr *child) static void del_tree(struct tal_hdr *t, const tal_t *orig, int saved_errno) { - struct prop_hdr **prop, *p, *next; + struct prop_hdr *prop; + char *ptr, *next; assert(!taken(from_tal_hdr(t))); @@ -402,10 +437,10 @@ static void del_tree(struct tal_hdr *t, const tal_t *orig, int saved_errno) notify(t, TAL_NOTIFY_FREE, (tal_t *)orig, saved_errno); /* Now free children and groups. */ - prop = find_property_ptr(t, CHILDREN); + prop = find_property(t, CHILDREN); if (prop) { struct tal_hdr *i; - struct children *c = (struct children *)*prop; + struct children *c = (struct children *)prop; while ((i = list_top(&c->children, struct tal_hdr, list))) { list_del(&i->list); @@ -414,9 +449,9 @@ static void del_tree(struct tal_hdr *t, const tal_t *orig, int saved_errno) } /* Finally free our properties. */ - for (p = t->prop; p && !is_literal(p); p = next) { - next = p->next; - freefn(p); + for (ptr = t->prop; ptr && (prop = is_prop_hdr(ptr)); ptr = next) { + next = prop->next; + freefn(ptr); } freefn(t); } @@ -590,25 +625,34 @@ bool tal_del_destructor2_(const tal_t *ctx, void (*destroy)(void *me, void *arg) bool tal_set_name_(tal_t *ctx, const char *name, bool literal) { struct tal_hdr *t = debug_tal(to_tal_hdr(ctx)); - struct prop_hdr **prop = find_property_ptr(t, NAME); + bool was_literal; + char **nptr; /* Get rid of any old name */ - if (prop) { - struct name *oldname = (struct name *)*prop; - if (is_literal(&oldname->hdr)) - *prop = NULL; - else { - *prop = oldname->hdr.next; + nptr = find_name_property(t, &was_literal); + if (nptr) { + if (was_literal) + *nptr = NULL; + else { + struct name *oldname; + + oldname = (struct name *)*nptr; + *nptr = oldname->hdr.next; freefn(oldname); - } + } } if (literal && name[0]) { - struct prop_hdr **p; + char **ptr; + struct prop_hdr *prop; /* Append literal. */ - for (p = &t->prop; *p && !is_literal(*p); p = &(*p)->next); - *p = (struct prop_hdr *)name; + for (ptr = &t->prop; *ptr; ptr = &prop->next) { + prop = is_prop_hdr(*ptr); + if (!prop) + break; + } + *ptr = (char *)name; } else if (!add_name_property(t, name)) return false; @@ -620,15 +664,16 @@ bool tal_set_name_(tal_t *ctx, const char *name, bool literal) const char *tal_name(const tal_t *t) { - struct name *n; + char **nptr; + bool literal; - n = find_property(debug_tal(to_tal_hdr(t)), NAME); - if (!n) + nptr = find_name_property(debug_tal(to_tal_hdr(t)), &literal); + if (!nptr) return NULL; + if (literal) + return *nptr; - if (is_literal(&n->hdr)) - return (const char *)n; - return n->name; + return ((struct name *)(*nptr))->name; } size_t tal_bytelen(const tal_t *ptr) @@ -803,7 +848,7 @@ void *tal_dup_(const tal_t *ctx, const void *p, size_t size, } ret = tal_alloc_arr_(ctx, size, n + extra, false, label); - if (ret) + if (ret && p) memcpy(ret, p, nbytes); return ret; } @@ -832,36 +877,38 @@ void tal_set_backend(void *(*alloc_fn)(size_t size), static void dump_node(unsigned int indent, const struct tal_hdr *t) { unsigned int i; - const struct prop_hdr *p; + const struct prop_hdr *prop; + const char *ptr; for (i = 0; i < indent; i++) fprintf(stderr, " "); fprintf(stderr, "%p len=%zu", t, t->bytelen); - for (p = t->prop; p; p = p->next) { + for (ptr = t->prop; ptr; ptr = prop->next) { struct children *c; struct name *n; struct notifier *no; - if (is_literal(p)) { - fprintf(stderr, " \"%s\"", (const char *)p); + prop = is_prop_hdr(ptr); + if (!prop) { + fprintf(stderr, " \"%s\"", ptr); break; } - switch (p->type) { + switch (prop->type) { case CHILDREN: - c = (struct children *)p; + c = (struct children *)prop; fprintf(stderr, " CHILDREN(%p):parent=%p,children={%p,%p}", - p, c->parent, + prop, c->parent, c->children.n.prev, c->children.n.next); break; case NAME: - n = (struct name *)p; - fprintf(stderr, " NAME(%p):%s", p, n->name); + n = (struct name *)prop; + fprintf(stderr, " NAME(%p):%s", prop, n->name); break; case NOTIFIER: - no = (struct notifier *)p; - fprintf(stderr, " NOTIFIER(%p):fn=%p", p, no->u.notifyfn); + no = (struct notifier *)prop; + fprintf(stderr, " NOTIFIER(%p):fn=%p", prop, no->u.notifyfn); break; default: - fprintf(stderr, " **UNKNOWN(%p):%i**", p, p->type); + fprintf(stderr, " **UNKNOWN(%p):%i**", prop, prop->type); } } fprintf(stderr, "\n"); @@ -873,7 +920,7 @@ static void tal_dump_(unsigned int level, const struct tal_hdr *t) dump_node(level, t); - children = find_property(t, CHILDREN); + children = find_property((struct tal_hdr *)t, CHILDREN); if (children) { struct tal_hdr *i; @@ -904,7 +951,8 @@ static bool check_err(struct tal_hdr *t, const char *errorstr, static bool check_node(struct children *parent_child, struct tal_hdr *t, const char *errorstr) { - struct prop_hdr *p; + struct prop_hdr *prop; + char *p; struct name *name = NULL; struct children *children = NULL; @@ -914,23 +962,24 @@ static bool check_node(struct children *parent_child, if (ignore_destroying_bit(t->parent_child) != parent_child) return check_err(t, errorstr, "incorrect parent"); - for (p = t->prop; p; p = p->next) { - if (is_literal(p)) { + for (p = t->prop; p; p = prop->next) { + prop = is_prop_hdr(p); + if (!prop) { if (name) return check_err(t, errorstr, "has extra literal"); break; } - if (!in_bounds(p)) + if (!in_bounds(prop)) return check_err(t, errorstr, "has bad property pointer"); - switch (p->type) { + switch (prop->type) { case CHILDREN: if (children) return check_err(t, errorstr, "has two child nodes"); - children = (struct children *)p; + children = (struct children *)prop; break; case NOTIFIER: break; @@ -938,7 +987,7 @@ static bool check_node(struct children *parent_child, if (name) return check_err(t, errorstr, "has two names"); - name = (struct name *)p; + name = (struct name *)prop; break; default: return check_err(t, errorstr, "has unknown property"); diff --git a/ccan/ccan/tal/test/run-notifier.c b/ccan/ccan/tal/test/run-notifier.c index 150f00adae9e..47e436408cbe 100644 --- a/ccan/ccan/tal/test/run-notifier.c +++ b/ccan/ccan/tal/test/run-notifier.c @@ -13,8 +13,8 @@ static void *my_realloc(void *old, size_t size) void *new = realloc(old, size); if (new == old) { void *p = malloc(size); - memcpy(p, old, size); - free(old); + memcpy(p, new, size); + free(new); new = p; } return new; diff --git a/ccan/ccan/tcon/test/compile_fail-container1.c b/ccan/ccan/tcon/test/compile_fail-container1.c index 44645a7ec6d4..ed1d3e206acd 100644 --- a/ccan/ccan/tcon/test/compile_fail-container1.c +++ b/ccan/ccan/tcon/test/compile_fail-container1.c @@ -25,7 +25,7 @@ struct info_tcon { int main(void) { struct info_tcon info; - struct outer ovar; + struct outer ovar = { 0, { 0 } }; #ifdef FAIL #if !HAVE_TYPEOF #error We cannot detect type problems without HAVE_TYPEOF diff --git a/ccan/ccan/tcon/test/compile_fail-container1w.c b/ccan/ccan/tcon/test/compile_fail-container1w.c index 19ba5bdcc915..a03f6514e179 100644 --- a/ccan/ccan/tcon/test/compile_fail-container1w.c +++ b/ccan/ccan/tcon/test/compile_fail-container1w.c @@ -21,7 +21,7 @@ int main(void) { TCON_WRAP(struct info_base, TCON_CONTAINER(concan, struct outer, inner)) info; - struct outer ovar; + struct outer ovar = { 0, { 0 } }; #ifdef FAIL #if !HAVE_TYPEOF #error We cannot detect type problems without HAVE_TYPEOF diff --git a/ccan/ccan/tcon/test/compile_fail-container3.c b/ccan/ccan/tcon/test/compile_fail-container3.c index 9185225a9361..dfdfdba9a341 100644 --- a/ccan/ccan/tcon/test/compile_fail-container3.c +++ b/ccan/ccan/tcon/test/compile_fail-container3.c @@ -25,7 +25,7 @@ struct info_tcon { int main(void) { struct info_tcon info; - struct outer ovar; + struct outer ovar = { 0, { 0 } }; #ifdef FAIL #if !HAVE_TYPEOF #error We cannot detect type problems without HAVE_TYPEOF diff --git a/ccan/ccan/tcon/test/compile_fail-container3w.c b/ccan/ccan/tcon/test/compile_fail-container3w.c index 958e5c8b3dca..a56e510f1e2b 100644 --- a/ccan/ccan/tcon/test/compile_fail-container3w.c +++ b/ccan/ccan/tcon/test/compile_fail-container3w.c @@ -21,7 +21,7 @@ int main(void) { TCON_WRAP(struct info_base, TCON_CONTAINER(concan, struct outer, inner)) info; - struct outer ovar; + struct outer ovar = { 0, { 0 } }; #ifdef FAIL #if !HAVE_TYPEOF #error We cannot detect type problems without HAVE_TYPEOF diff --git a/ccan/tools/configurator/configurator.c b/ccan/tools/configurator/configurator.c index f830cbca14eb..722a6f692883 100644 --- a/ccan/tools/configurator/configurator.c +++ b/ccan/tools/configurator/configurator.c @@ -197,7 +197,7 @@ static const struct test base_tests[] = { "return __builtin_clzll(1) == (sizeof(long long)*8 - 1) ? 0 : 1;" }, { "HAVE_BUILTIN_CTZ", "__builtin_ctz support", "INSIDE_MAIN", NULL, NULL, - "return __builtin_ctz(1 << (sizeof(int)*8 - 1)) == (sizeof(int)*8 - 1) ? 0 : 1;" }, + "return __builtin_ctz(1U << (sizeof(int)*8 - 1)) == (sizeof(int)*8 - 1) ? 0 : 1;" }, { "HAVE_BUILTIN_CTZL", "__builtin_ctzl support", "INSIDE_MAIN", NULL, NULL, "return __builtin_ctzl(1UL << (sizeof(long)*8 - 1)) == (sizeof(long)*8 - 1) ? 0 : 1;" }, diff --git a/channeld/channeld.c b/channeld/channeld.c index 0581158704cd..04e33fc2f924 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -98,7 +98,6 @@ struct peer { struct timers timers; struct oneshot *commit_timer; - u64 commit_timer_attempts; u32 commit_msec; /* The feerate we want. */ @@ -140,7 +139,6 @@ struct peer { /* If master told us to send wrong_funding */ struct bitcoin_outpoint *shutdown_wrong_funding; -#if EXPERIMENTAL_FEATURES /* Do we want quiescence? */ bool stfu; /* Which side is considered the initiator? */ @@ -149,7 +147,6 @@ struct peer { bool stfu_sent[NUM_SIDES]; /* Updates master asked, which we've deferred while quiescing */ struct msg_queue *update_queue; -#endif #if DEVELOPER /* If set, don't fire commit counter when this hits 0 */ @@ -197,6 +194,9 @@ struct peer { /* Most recent channel_update message. */ u8 *channel_update; + + /* --experimental-upgrade-protocol */ + bool experimental_upgrade; }; static u8 *create_channel_announcement(const tal_t *ctx, struct peer *peer); @@ -228,7 +228,6 @@ const u8 *hsm_req(const tal_t *ctx, const u8 *req TAKES) return msg; } -#if EXPERIMENTAL_FEATURES static void maybe_send_stfu(struct peer *peer) { if (!peer->stfu) @@ -253,6 +252,12 @@ static void handle_stfu(struct peer *peer, const u8 *stfu) struct channel_id channel_id; u8 remote_initiated; + if (!feature_negotiated(peer->our_features, + peer->their_features, + OPT_QUIESCE)) + peer_failed_warn(peer->pps, &peer->channel_id, + "stfu not supported"); + if (!fromwire_stfu(stfu, &channel_id, &remote_initiated)) peer_failed_warn(peer->pps, &peer->channel_id, "Bad stfu %s", tal_hex(peer, stfu)); @@ -342,16 +347,6 @@ static void set_channel_type(struct channel *channel, const u8 *type) wire_sync_write(MASTER_FD, take(towire_channeld_upgraded(NULL, channel->type))); } -#else /* !EXPERIMENTAL_FEATURES */ -static bool handle_master_request_later(struct peer *peer, const u8 *msg) -{ - return false; -} - -static void maybe_send_stfu(struct peer *peer) -{ -} -#endif /* Tell gossipd to create channel_update (then it goes into * gossip_store, then streams out to peers, or sends it directly if @@ -690,20 +685,20 @@ static void handle_peer_add_htlc(struct peer *peer, const u8 *msg) u8 onion_routing_packet[TOTAL_PACKET_SIZE(ROUTING_INFO_SIZE)]; enum channel_add_err add_err; struct htlc *htlc; - struct tlv_update_add_tlvs *tlvs; + struct tlv_update_add_htlc_tlvs *tlvs; if (!fromwire_update_add_htlc(msg, msg, &channel_id, &id, &amount, &payment_hash, &cltv_expiry, onion_routing_packet, &tlvs) /* This is an *even* field: don't send if we didn't understand */ - || (tlvs->blinding && !feature_offered(peer->our_features->bits[INIT_FEATURE], - OPT_ROUTE_BLINDING))) { + || (tlvs->blinding_point && !feature_offered(peer->our_features->bits[INIT_FEATURE], + OPT_ROUTE_BLINDING))) { peer_failed_warn(peer->pps, &peer->channel_id, "Bad peer_add_htlc %s", tal_hex(msg, msg)); } add_err = channel_add_htlc(peer->channel, REMOTE, id, amount, cltv_expiry, &payment_hash, - onion_routing_packet, tlvs->blinding, &htlc, NULL, + onion_routing_packet, tlvs->blinding_point, &htlc, NULL, /* We don't immediately fail incoming htlcs, * instead we wait and fail them after * they've been committed */ @@ -1145,11 +1140,10 @@ static bool want_fee_update(const struct peer *peer, u32 *target) if (peer->channel->opener != LOCAL) return false; -#if EXPERIMENTAL_FEATURES /* No fee update while quiescing! */ if (peer->stfu) return false; -#endif + current = channel_feerate(peer->channel, REMOTE); /* max is *approximate*: only take it into account if we're @@ -1185,11 +1179,10 @@ static bool want_blockheight_update(const struct peer *peer, u32 *height) if (peer->channel->lease_expiry == 0) return false; -#if EXPERIMENTAL_FEATURES /* No fee update while quiescing! */ if (peer->stfu) return false; -#endif + /* What's the current blockheight */ last = get_blockheight(peer->channel->blockheight_states, peer->channel->opener, LOCAL); @@ -1234,16 +1227,10 @@ static void send_commit(struct peer *peer) if (peer->revocations_received != peer->next_index[REMOTE] - 1) { assert(peer->revocations_received == peer->next_index[REMOTE] - 2); - peer->commit_timer_attempts++; - /* Only report this in extreme cases */ - if (peer->commit_timer_attempts % 100 == 0) - status_debug("Can't send commit:" - " waiting for revoke_and_ack with %" - PRIu64" attempts", - peer->commit_timer_attempts); - /* Mark this as done and try again. */ + status_debug("Can't send commit: waiting for revoke_and_ack"); + /* Mark this as done: handle_peer_revoke_and_ack will + * restart. */ peer->commit_timer = NULL; - start_commit_timer(peer); return; } @@ -1399,7 +1386,6 @@ static void start_commit_timer(struct peer *peer) if (peer->commit_timer) return; - peer->commit_timer_attempts = 0; peer->commit_timer = new_reltimer(&peer->timers, peer, time_from_msec(peer->commit_msec), send_commit, peer); @@ -2136,29 +2122,17 @@ static void handle_unexpected_reestablish(struct peer *peer, const u8 *msg) u64 next_revocation_number; struct secret your_last_per_commitment_secret; struct pubkey my_current_per_commitment_point; -#if EXPERIMENTAL_FEATURES struct tlv_channel_reestablish_tlvs *tlvs; -#endif - - if (!fromwire_channel_reestablish -#if EXPERIMENTAL_FEATURES - (tmpctx, msg, &channel_id, - &next_commitment_number, - &next_revocation_number, - &your_last_per_commitment_secret, - &my_current_per_commitment_point, - &tlvs) -#else - (msg, &channel_id, - &next_commitment_number, - &next_revocation_number, - &your_last_per_commitment_secret, - &my_current_per_commitment_point) -#endif - ) + if (!fromwire_channel_reestablish(tmpctx, msg, &channel_id, + &next_commitment_number, + &next_revocation_number, + &your_last_per_commitment_secret, + &my_current_per_commitment_point, + &tlvs)) { peer_failed_warn(peer->pps, &peer->channel_id, "Bad channel_reestablish %s", tal_hex(peer, msg)); + } /* Is it the same as the peer channel ID? */ if (channel_id_eq(&channel_id, &peer->channel_id)) { @@ -2253,12 +2227,9 @@ static void peer_in(struct peer *peer, const u8 *msg) case WIRE_SHUTDOWN: handle_peer_shutdown(peer, msg); return; - -#if EXPERIMENTAL_FEATURES case WIRE_STFU: handle_stfu(peer, msg); return; -#endif case WIRE_INIT: case WIRE_OPEN_CHANNEL: case WIRE_ACCEPT_CHANNEL: @@ -2270,13 +2241,14 @@ static void peer_in(struct peer *peer, const u8 *msg) case WIRE_TX_ADD_OUTPUT: case WIRE_TX_REMOVE_OUTPUT: case WIRE_TX_COMPLETE: + case WIRE_TX_ABORT: case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: case WIRE_TX_SIGNATURES: handle_unexpected_tx_sigs(peer, msg); return; - case WIRE_INIT_RBF: - case WIRE_ACK_RBF: + case WIRE_TX_INIT_RBF: + case WIRE_TX_ACK_RBF: break; case WIRE_CHANNEL_REESTABLISH: @@ -2297,6 +2269,8 @@ static void peer_in(struct peer *peer, const u8 *msg) case WIRE_WARNING: case WIRE_ERROR: case WIRE_ONION_MESSAGE: + case WIRE_PEER_STORAGE: + case WIRE_YOUR_PEER_STORAGE: abort(); } @@ -2373,7 +2347,8 @@ static void resend_commitment(struct peer *peer, struct changed_htlc *last) * is to sort them all into ascending ID order here (we could do * this when we save them in channel_sending_commit, but older versions * won't have them sorted in the db, so doing it here is better). */ - asort(last, tal_count(last), cmp_changed_htlc_id, NULL); + if (last) + asort(last, tal_count(last), cmp_changed_htlc_id, NULL); /* BOLT #2: * @@ -2420,11 +2395,11 @@ static void resend_commitment(struct peer *peer, struct changed_htlc *last) last[i].id); if (h->state == SENT_ADD_COMMIT) { - struct tlv_update_add_tlvs *tlvs; + struct tlv_update_add_htlc_tlvs *tlvs; if (h->blinding) { - tlvs = tlv_update_add_tlvs_new(tmpctx); - tlvs->blinding = tal_dup(tlvs, struct pubkey, - h->blinding); + tlvs = tlv_update_add_htlc_tlvs_new(tmpctx); + tlvs->blinding_point = tal_dup(tlvs, struct pubkey, + h->blinding); } else tlvs = NULL; msg = towire_update_add_htlc(NULL, &peer->channel_id, @@ -2667,7 +2642,6 @@ static bool capture_premature_msg(const u8 ***shit_lnd_says, const u8 *msg) return true; } -#if EXPERIMENTAL_FEATURES /* Unwrap a channel_type into a raw byte array for the wire: can be NULL */ static u8 *to_bytearr(const tal_t *ctx, const struct channel_type *channel_type TAKES) @@ -2687,23 +2661,6 @@ static u8 *to_bytearr(const tal_t *ctx, return ret; } -/* This is the no-tlvs version, where we can't handle old tlvs */ -static bool fromwire_channel_reestablish_notlvs(const void *p, struct channel_id *channel_id, u64 *next_commitment_number, u64 *next_revocation_number, struct secret *your_last_per_commitment_secret, struct pubkey *my_current_per_commitment_point) -{ - const u8 *cursor = p; - size_t plen = tal_count(p); - - if (fromwire_u16(&cursor, &plen) != WIRE_CHANNEL_REESTABLISH) - return false; - fromwire_channel_id(&cursor, &plen, channel_id); - *next_commitment_number = fromwire_u64(&cursor, &plen); - *next_revocation_number = fromwire_u64(&cursor, &plen); - fromwire_secret(&cursor, &plen, your_last_per_commitment_secret); - fromwire_pubkey(&cursor, &plen, my_current_per_commitment_point); - return cursor != NULL; -} -#endif - static void peer_reconnect(struct peer *peer, const struct secret *last_remote_per_commit_secret, bool reestablish_only) @@ -2720,9 +2677,7 @@ static void peer_reconnect(struct peer *peer, struct secret last_local_per_commitment_secret; bool dataloss_protect, check_extra_fields; const u8 **premature_msgs = tal_arr(peer, const u8 *, 0); -#if EXPERIMENTAL_FEATURES struct tlv_channel_reestablish_tlvs *send_tlvs, *recv_tlvs; -#endif dataloss_protect = feature_negotiated(peer->our_features, peer->their_features, @@ -2737,53 +2692,45 @@ static void peer_reconnect(struct peer *peer, get_per_commitment_point(peer->next_index[LOCAL] - 1, &my_current_per_commitment_point, NULL); -#if EXPERIMENTAL_FEATURES - /* Subtle: we free tmpctx below as we loop, so tal off peer */ - send_tlvs = tlv_channel_reestablish_tlvs_new(peer); - - /* FIXME: v0.10.1 would send a different tlv set, due to older spec. - * That did *not* offer OPT_QUIESCE, so in that case don't send tlvs. */ - if (!feature_negotiated(peer->our_features, - peer->their_features, - OPT_QUIESCE)) - goto skip_tlvs; + if (peer->experimental_upgrade) { + /* Subtle: we free tmpctx below as we loop, so tal off peer */ + send_tlvs = tlv_channel_reestablish_tlvs_new(peer); - /* BOLT-upgrade_protocol #2: - * A node sending `channel_reestablish`, if it supports upgrading channels: - * - MUST set `next_to_send` the commitment number of the next - * `commitment_signed` it expects to send. - */ - send_tlvs->next_to_send = tal_dup(send_tlvs, u64, &peer->next_index[REMOTE]); - - /* BOLT-upgrade_protocol #2: - * - if it initiated the channel: - * - MUST set `desired_type` to the channel_type it wants for the - * channel. - */ - if (peer->channel->opener == LOCAL) - send_tlvs->desired_channel_type = - to_bytearr(send_tlvs, - take(channel_desired_type(NULL, - peer->channel))); - else { /* BOLT-upgrade_protocol #2: - * - otherwise: - * - MUST set `current_type` to the current channel_type of the - * channel. - * - MUST set `upgradable` to the channel types it could change - * to. - * - MAY not set `upgradable` if it would be empty. + * A node sending `channel_reestablish`, if it supports upgrading channels: + * - MUST set `next_to_send` the commitment number of the next + * `commitment_signed` it expects to send. */ - send_tlvs->current_channel_type - = to_bytearr(send_tlvs, peer->channel->type); - send_tlvs->upgradable_channel_type - = to_bytearr(send_tlvs, - take(channel_upgradable_type(NULL, - peer->channel))); - } + send_tlvs->next_to_send = tal_dup(send_tlvs, u64, &peer->next_index[REMOTE]); -skip_tlvs: -#endif + /* BOLT-upgrade_protocol #2: + * - if it initiated the channel: + * - MUST set `desired_type` to the channel_type it wants for the + * channel. + */ + if (peer->channel->opener == LOCAL) { + send_tlvs->desired_channel_type = + to_bytearr(send_tlvs, + take(channel_desired_type(NULL, + peer->channel))); + } else { + /* BOLT-upgrade_protocol #2: + * - otherwise: + * - MUST set `current_type` to the current channel_type of the + * channel. + * - MUST set `upgradable` to the channel types it could change + * to. + * - MAY not set `upgradable` if it would be empty. + */ + send_tlvs->current_channel_type + = to_bytearr(send_tlvs, peer->channel->type); + send_tlvs->upgradable_channel_type + = to_bytearr(send_tlvs, + take(channel_upgradable_type(NULL, + peer->channel))); + } + } else + send_tlvs = NULL; /* BOLT #2: * @@ -2822,22 +2769,15 @@ static void peer_reconnect(struct peer *peer, peer->revocations_received, last_remote_per_commit_secret, /* Can send any (valid) point here */ - &peer->remote_per_commit -#if EXPERIMENTAL_FEATURES - , send_tlvs -#endif - ); + &peer->remote_per_commit, send_tlvs); } else { msg = towire_channel_reestablish (NULL, &peer->channel_id, peer->next_index[LOCAL], peer->revocations_received, last_remote_per_commit_secret, - &my_current_per_commitment_point -#if EXPERIMENTAL_FEATURES - , send_tlvs -#endif - ); + &my_current_per_commitment_point, + send_tlvs); } peer_write(peer->pps, take(msg)); @@ -2861,53 +2801,22 @@ static void peer_reconnect(struct peer *peer, } while (handle_peer_error(peer->pps, &peer->channel_id, msg) || capture_premature_msg(&premature_msgs, msg)); -#if EXPERIMENTAL_FEATURES /* Initialize here in case we don't read it below! */ recv_tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); - /* FIXME: v0.10.1 would send a different tlv set, due to older spec. - * That did *not* offer OPT_QUIESCE, so in that case ignore tlvs. */ - if (!feature_negotiated(peer->our_features, - peer->their_features, - OPT_QUIESCE)) { - if (!fromwire_channel_reestablish_notlvs(msg, - &channel_id, - &next_commitment_number, - &next_revocation_number, - &last_local_per_commitment_secret, - &remote_current_per_commitment_point)) - peer_failed_warn(peer->pps, - &peer->channel_id, - "bad reestablish msg: %s %s", - peer_wire_name(fromwire_peektype(msg)), - tal_hex(msg, msg)); - } else if (!fromwire_channel_reestablish(tmpctx, msg, - &channel_id, - &next_commitment_number, - &next_revocation_number, - &last_local_per_commitment_secret, - &remote_current_per_commitment_point, - &recv_tlvs)) { - peer_failed_warn(peer->pps, - &peer->channel_id, - "bad reestablish msg: %s %s", - peer_wire_name(fromwire_peektype(msg)), - tal_hex(msg, msg)); - } -#else /* !EXPERIMENTAL_FEATURES */ - if (!fromwire_channel_reestablish(msg, - &channel_id, - &next_commitment_number, - &next_revocation_number, - &last_local_per_commitment_secret, - &remote_current_per_commitment_point)) { + if (!fromwire_channel_reestablish(tmpctx, msg, + &channel_id, + &next_commitment_number, + &next_revocation_number, + &last_local_per_commitment_secret, + &remote_current_per_commitment_point, + &recv_tlvs)) { peer_failed_warn(peer->pps, &peer->channel_id, "bad reestablish msg: %s %s", peer_wire_name(fromwire_peektype(msg)), tal_hex(msg, msg)); } -#endif if (!channel_id_eq(&channel_id, &peer->channel_id)) { peer_failed_err(peer->pps, @@ -3085,7 +2994,10 @@ static void peer_reconnect(struct peer *peer, /* (If we had sent `closing_signed`, we'd be in closingd). */ maybe_send_shutdown(peer); -#if EXPERIMENTAL_FEATURES + /* If we didn't send (i.e. don't support!) ignore theirs */ + if (!send_tlvs) + recv_tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); + if (recv_tlvs->desired_channel_type) status_debug("They sent desired_channel_type [%s]", fmt_featurebits(tmpctx, @@ -3165,8 +3077,6 @@ static void peer_reconnect(struct peer *peer, } tal_free(send_tlvs); -#endif /* EXPERIMENTAL_FEATURES */ - /* Now stop, we've been polite long enough. */ if (reestablish_only) { /* If we were successfully closing, we still go to closingd. */ @@ -3298,7 +3208,7 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg) const char *failstr; struct amount_sat htlc_fee; struct pubkey *blinding; - struct tlv_update_add_tlvs *tlvs; + struct tlv_update_add_htlc_tlvs *tlvs; if (!peer->channel_ready[LOCAL] || !peer->channel_ready[REMOTE]) status_failed(STATUS_FAIL_MASTER_IO, @@ -3310,8 +3220,8 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg) master_badmsg(WIRE_CHANNELD_OFFER_HTLC, inmsg); if (blinding) { - tlvs = tlv_update_add_tlvs_new(tmpctx); - tlvs->blinding = tal_dup(tlvs, struct pubkey, blinding); + tlvs = tlv_update_add_htlc_tlvs_new(tmpctx); + tlvs->blinding_point = tal_dup(tlvs, struct pubkey, blinding); } else tlvs = NULL; @@ -3640,7 +3550,6 @@ static void handle_dev_memleak(struct peer *peer, const u8 *msg) found_leak))); } -#if EXPERIMENTAL_FEATURES static void handle_dev_quiesce(struct peer *peer, const u8 *msg) { if (!fromwire_channeld_dev_quiesce(msg)) @@ -3654,7 +3563,6 @@ static void handle_dev_quiesce(struct peer *peer, const u8 *msg) peer->stfu_initiator = LOCAL; maybe_send_stfu(peer); } -#endif /* EXPERIMENTAL_FEATURES */ #endif /* DEVELOPER */ static void req_in(struct peer *peer, const u8 *msg) @@ -3712,10 +3620,8 @@ static void req_in(struct peer *peer, const u8 *msg) handle_dev_memleak(peer, msg); return; case WIRE_CHANNELD_DEV_QUIESCE: -#if EXPERIMENTAL_FEATURES handle_dev_quiesce(peer, msg); return; -#endif /* EXPERIMENTAL_FEATURES */ #else case WIRE_CHANNELD_DEV_REENABLE_COMMIT: case WIRE_CHANNELD_DEV_MEMLEAK: @@ -3840,7 +3746,8 @@ static void init_channel(struct peer *peer) &dev_disable_commit, &pbases, &reestablish_only, - &peer->channel_update)) { + &peer->channel_update, + &peer->experimental_upgrade)) { master_badmsg(WIRE_CHANNELD_INIT, msg); } @@ -3984,11 +3891,9 @@ int main(int argc, char *argv[]) peer->shutdown_wrong_funding = NULL; peer->last_update_timestamp = 0; peer->last_empty_commitment = 0; -#if EXPERIMENTAL_FEATURES peer->stfu = false; peer->stfu_sent[LOCAL] = peer->stfu_sent[REMOTE] = false; peer->update_queue = msg_queue_new(peer, false); -#endif /* We send these to HSM to get real signatures; don't have valgrind * complain. */ diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index f4b60fe8b75f..03af74bf7cc2 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -82,6 +82,7 @@ msgdata,channeld_init,pbases,penalty_base,num_penalty_bases msgdata,channeld_init,reestablish_only,bool, msgdata,channeld_init,channel_update_len,u16, msgdata,channeld_init,channel_update,u8,channel_update_len +msgdata,channeld_init,experimental_upgrade,bool, # master->channeld funding hit new depth(funding locked if >= lock depth) # alias != NULL if zeroconf and short_channel_id == NULL diff --git a/channeld/commit_tx.c b/channeld/commit_tx.c index 6f8c41c8320b..30f946de7cdc 100644 --- a/channeld/commit_tx.c +++ b/channeld/commit_tx.c @@ -156,8 +156,8 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, base_fee = commit_tx_base_fee(feerate_per_kw, untrimmed, option_anchor_outputs); - SUPERVERBOSE("# base commitment transaction fee = %"PRIu64"\n", - base_fee.satoshis /* Raw: spec uses raw numbers */); + SUPERVERBOSE("# base commitment transaction fee = %"PRIu64" for %zu untrimmed\n", + base_fee.satoshis /* Raw: spec uses raw numbers */, untrimmed); /* BOLT #3: * If `option_anchors` applies to the commitment @@ -304,7 +304,7 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, * Otherwise, this output is a simple P2WPKH to `remotepubkey`. */ if (option_anchor_outputs) { - redeem = anchor_to_remote_redeem(tmpctx, + redeem = bitcoin_wscript_to_remote_anchored(tmpctx, &keyset->other_payment_key, (!side) == lessor ? csv_lock : 1); diff --git a/channeld/test/run-commit_tx.c b/channeld/test/run-commit_tx.c index f222e7ae3d59..d1eb5721202a 100644 --- a/channeld/test/run-commit_tx.c +++ b/channeld/test/run-commit_tx.c @@ -380,7 +380,8 @@ static void report(struct bitcoin_tx *tx, const struct pubkey *remote_revocation_key, u32 feerate_per_kw, bool option_anchor_outputs, - const struct htlc **htlc_map) + const struct htlc **htlc_map, + size_t total_htlcs) { char *txhex; struct bitcoin_signature localsig, remotesig; @@ -410,6 +411,13 @@ static void report(struct bitcoin_tx *tx, txhex = tal_hex(tmpctx, linearize_tx(tx, tx)); printf("output commit_tx: %s\n", txhex); + /* Now signatures are attached, this should be correct. But note + * that spec uses worst-case weight, so we will be slightly higher. */ + assert(tx_feerate(tx) >= feerate_per_kw); + /* Of course, trimmed htlcs magnify this! */ + if (tx->wtx->num_outputs == total_htlcs + 2) + assert(tx_feerate(tx) <= feerate_per_kw * 1.01); + report_htlcs(tx, htlc_map, to_self_delay, local_htlcsecretkey, localkey, local_htlckey, local_delayedkey, @@ -837,7 +845,8 @@ int main(int argc, const char *argv[]) &remote_revocation_key, feerate_per_kw, option_anchor_outputs, - htlc_map); + htlc_map, + 0); /* BOLT #3: * @@ -903,7 +912,8 @@ int main(int argc, const char *argv[]) &remote_revocation_key, feerate_per_kw, option_anchor_outputs, - htlc_map); + htlc_map, + tal_count(htlcs)); do { struct bitcoin_tx *newtx; @@ -1000,7 +1010,8 @@ int main(int argc, const char *argv[]) &remote_revocation_key, feerate_per_kw-1, option_anchor_outputs, - htlc_map); + htlc_map, + tal_count(htlcs)); printf("\n" "name: commitment tx with %s untrimmed (minimum feerate)\n" @@ -1049,7 +1060,8 @@ int main(int argc, const char *argv[]) &remote_revocation_key, feerate_per_kw, option_anchor_outputs, - htlc_map); + htlc_map, + tal_count(htlcs)); assert(newtx->wtx->num_outputs != tx->wtx->num_outputs); @@ -1124,7 +1136,8 @@ int main(int argc, const char *argv[]) &remote_revocation_key, feerate_per_kw, option_anchor_outputs, - htlc_map); + htlc_map, + tal_count(htlcs)); break; } @@ -1134,11 +1147,11 @@ int main(int argc, const char *argv[]) /* BOLT #3: * * name: commitment tx with 3 htlc outputs, 2 offered having the same amount and preimage - * to_local_msat: 6988000000 + * to_local_msat: 6987999999 * to_remote_msat: 3000000000 * local_feerate_per_kw: 253 */ - to_local.millisatoshis = 6988000000; + to_local.millisatoshis = 6987999999; to_remote.millisatoshis = 3000000000; feerate_per_kw = 253; printf("\n" @@ -1195,7 +1208,8 @@ int main(int argc, const char *argv[]) &remote_revocation_key, feerate_per_kw, option_anchor_outputs, - htlc_map); + htlc_map, + tal_count(htlcs)); common_shutdown(); /* FIXME: Do BOLT comparison! */ diff --git a/channeld/watchtower.c b/channeld/watchtower.c index 269b4f405ad0..00f34d30fd66 100644 --- a/channeld/watchtower.c +++ b/channeld/watchtower.c @@ -96,7 +96,9 @@ penalty_tx_create(const tal_t *ctx, if (amount_sat_less(to_them_sats, min_out)) { /* FIXME: We should use SIGHASH_NONE so others can take it */ - fee = amount_tx_fee(feerate_floor(), weight); + /* We use the minimum possible fee here; if it doesn't + * propagate, who cares? */ + fee = amount_tx_fee(FEERATE_FLOOR, weight); } /* This can only happen if feerate_floor() is still too high; shouldn't diff --git a/cli/Makefile b/cli/Makefile index 5afdb39cae1e..82dea907ea61 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -8,6 +8,7 @@ ALL_PROGRAMS += cli/lightning-cli LIGHTNING_CLI_COMMON_OBJS := \ bitcoin/chainparams.o \ common/configdir.o \ + common/configvar.o \ common/json_parse_simple.o \ common/status_levels.o \ common/utils.o \ diff --git a/cli/lightning-cli.c b/cli/lightning-cli.c index dfc2ff00f622..392ad88fc7a8 100644 --- a/cli/lightning-cli.c +++ b/cli/lightning-cli.c @@ -594,12 +594,13 @@ static char *opt_set_level(const char *arg, enum log_level *level) return NULL; } -static void opt_show_level(char buf[OPT_SHOW_LEN], const enum log_level *level) +static bool opt_show_level(char *buf, size_t len, const enum log_level *level) { if (*level == LOG_LEVEL_MAX + 1) - strncpy(buf, "none", OPT_SHOW_LEN-1); + strncpy(buf, "none", len); else - strncpy(buf, log_level_name(*level), OPT_SHOW_LEN-1); + strncpy(buf, log_level_name(*level), len); + return true; } /* The standard opt_log_stderr_exit exits with status 1 */ @@ -649,7 +650,7 @@ int main(int argc, char *argv[]) jsmntok_t *toks; const jsmntok_t *result, *error, *id; const tal_t *ctx = tal(NULL, char); - char *config_filename, *lightning_dir, *net_dir, *rpc_filename; + char *net_dir, *rpc_filename; jsmn_parser parser; int parserr; enum format format = DEFAULT_FORMAT; @@ -666,9 +667,8 @@ int main(int argc, char *argv[]) setup_option_allocators(); - initial_config_opts(ctx, argc, argv, - &config_filename, &lightning_dir, &net_dir, - &rpc_filename); + opt_exitcode = ERROR_USAGE; + minimal_config_opts(ctx, argc, argv, &net_dir, &rpc_filename); opt_register_noarg("--help|-h", opt_usage_and_exit, " [...]", "Show this message. Use the command help (without hyphens -- \"lightning-cli help\") to get a list of all RPC commands"); @@ -694,8 +694,6 @@ int main(int argc, char *argv[]) NULL, &commando, "Send this as a commando command to nodeid:rune"); - opt_register_version(); - opt_early_parse(argc, argv, opt_log_stderr_exit_usage); opt_parse(&argc, argv, opt_log_stderr_exit_usage); diff --git a/cli/test/Makefile b/cli/test/Makefile index 331018413d81..d06cfe2474c6 100644 --- a/cli/test/Makefile +++ b/cli/test/Makefile @@ -10,6 +10,7 @@ ALL_TEST_PROGRAMS += $(CLI_TEST_PROGRAMS) CLI_TEST_COMMON_OBJS := \ common/autodata.o \ common/configdir.o \ + common/configvar.o \ common/daemon_conn.o \ common/htlc_state.o \ common/json_parse_simple.o \ @@ -18,6 +19,7 @@ CLI_TEST_COMMON_OBJS := \ common/msg_queue.o \ common/setup.o \ common/utils.o \ + common/version.o \ common/type_to_string.o \ common/permute_tx.o diff --git a/cli/test/run-human-mode.c b/cli/test/run-human-mode.c index 96b1e31c0a0c..9e5f0bed2b95 100644 --- a/cli/test/run-human-mode.c +++ b/cli/test/run-human-mode.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -45,12 +46,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, @@ -100,9 +107,6 @@ void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id U /* Generated stub for towire_node_id */ void towire_node_id(u8 **pptr UNNEEDED, const struct node_id *id UNNEEDED) { fprintf(stderr, "towire_node_id called!\n"); abort(); } -/* Generated stub for version_and_exit */ -char *version_and_exit(const void *unused UNNEEDED) -{ fprintf(stderr, "version_and_exit called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ int test_socket(int domain UNUSED, int type UNUSED, int protocol UNUSED) diff --git a/cli/test/run-large-input.c b/cli/test/run-large-input.c index be4f6eb2183f..0e0dc5494294 100644 --- a/cli/test/run-large-input.c +++ b/cli/test/run-large-input.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -45,12 +46,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, @@ -100,9 +107,6 @@ void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id U /* Generated stub for towire_node_id */ void towire_node_id(u8 **pptr UNNEEDED, const struct node_id *id UNNEEDED) { fprintf(stderr, "towire_node_id called!\n"); abort(); } -/* Generated stub for version_and_exit */ -char *version_and_exit(const void *unused UNNEEDED) -{ fprintf(stderr, "version_and_exit called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ int test_socket(int domain UNUSED, int type UNUSED, int protocol UNUSED) diff --git a/cli/test/run-remove-hint.c b/cli/test/run-remove-hint.c index 7d6dcfc3238c..5811b0fbb2b4 100644 --- a/cli/test/run-remove-hint.c +++ b/cli/test/run-remove-hint.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -48,12 +49,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, @@ -103,9 +110,6 @@ void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id U /* Generated stub for towire_node_id */ void towire_node_id(u8 **pptr UNNEEDED, const struct node_id *id UNNEEDED) { fprintf(stderr, "towire_node_id called!\n"); abort(); } -/* Generated stub for version_and_exit */ -char *version_and_exit(const void *unused UNNEEDED) -{ fprintf(stderr, "version_and_exit called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ int test_socket(int domain UNUSED, int type UNUSED, int protocol UNUSED) diff --git a/cln-grpc/Cargo.toml b/cln-grpc/Cargo.toml index b95246138089..08e49525121d 100644 --- a/cln-grpc/Cargo.toml +++ b/cln-grpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cln-grpc" -version = "0.1.2" +version = "0.1.3" edition = "2021" license = "MIT" description = "The Core Lightning API as grpc primitives. Provides the bindings used to expose the API over the network." @@ -8,10 +8,14 @@ homepage = "https://github.com/ElementsProject/lightning/tree/master/cln-grpc" repository = "https://github.com/ElementsProject/lightning" documentation = "https://docs.rs/cln-grpc" +[features] +default = [] +server = ["cln-rpc"] + [dependencies] anyhow = "1.0" log = "0.4" -cln-rpc = { path="../cln-rpc/", version = "^0.1" } +cln-rpc = { path="../cln-rpc/", version = "^0.1", optional = true } tonic = { version = "0.8", features = ["tls", "transport"] } prost = "0.11" hex = "0.4.3" diff --git a/cln-grpc/proto/node.proto b/cln-grpc/proto/node.proto index 981ae294649f..174558feaa29 100644 --- a/cln-grpc/proto/node.proto +++ b/cln-grpc/proto/node.proto @@ -45,6 +45,10 @@ service Node { rpc TxDiscard(TxdiscardRequest) returns (TxdiscardResponse) {} rpc TxPrepare(TxprepareRequest) returns (TxprepareResponse) {} rpc TxSend(TxsendRequest) returns (TxsendResponse) {} + rpc ListPeerChannels(ListpeerchannelsRequest) returns (ListpeerchannelsResponse) {} + rpc ListClosedChannels(ListclosedchannelsRequest) returns (ListclosedchannelsResponse) {} + rpc DecodePay(DecodepayRequest) returns (DecodepayResponse) {} + rpc Decode(DecodeRequest) returns (DecodeResponse) {} rpc Disconnect(DisconnectRequest) returns (DisconnectResponse) {} rpc Feerates(FeeratesRequest) returns (FeeratesResponse) {} rpc FundChannel(FundchannelRequest) returns (FundchannelResponse) {} @@ -52,9 +56,13 @@ service Node { rpc ListForwards(ListforwardsRequest) returns (ListforwardsResponse) {} rpc ListPays(ListpaysRequest) returns (ListpaysResponse) {} rpc Ping(PingRequest) returns (PingResponse) {} + rpc SendCustomMsg(SendcustommsgRequest) returns (SendcustommsgResponse) {} rpc SetChannel(SetchannelRequest) returns (SetchannelResponse) {} + rpc SignInvoice(SigninvoiceRequest) returns (SigninvoiceResponse) {} rpc SignMessage(SignmessageRequest) returns (SignmessageResponse) {} rpc Stop(StopRequest) returns (StopResponse) {} + rpc PreApproveKeysend(PreapprovekeysendRequest) returns (PreapprovekeysendResponse) {} + rpc PreApproveInvoice(PreapproveinvoiceRequest) returns (PreapproveinvoiceResponse) {} } message GetinfoRequest { @@ -62,7 +70,7 @@ message GetinfoRequest { message GetinfoResponse { bytes id = 1; - string alias = 2; + optional string alias = 2; bytes color = 3; uint32 num_peers = 4; uint32 num_pending_channels = 5; @@ -73,7 +81,6 @@ message GetinfoResponse { optional GetinfoOur_features our_features = 10; uint32 blockheight = 11; string network = 12; - optional uint64 msatoshi_fees_collected = 18; Amount fees_collected_msat = 13; repeated GetinfoAddress address = 14; repeated GetinfoBinding binding = 15; @@ -96,7 +103,6 @@ message GetinfoAddress { IPV6 = 2; TORV2 = 3; TORV3 = 4; - WEBSOCKET = 5; } GetinfoAddressType item_type = 1; uint32 port = 2; @@ -107,6 +113,7 @@ message GetinfoBinding { // Getinfo.binding[].type enum GetinfoBindingType { LOCAL_SOCKET = 0; + WEBSOCKET = 5; IPV4 = 1; IPV6 = 2; TORV2 = 3; @@ -130,6 +137,7 @@ message ListpeersResponse { message ListpeersPeers { bytes id = 1; bool connected = 2; + optional uint32 num_channels = 8; repeated ListpeersPeersLog log = 3; repeated ListpeersPeersChannels channels = 4; repeated string netaddr = 5; @@ -238,8 +246,6 @@ message ListpeersPeersChannelsInflight { } message ListpeersPeersChannelsFunding { - optional Amount local_msat = 1; - optional Amount remote_msat = 2; optional Amount pushed_msat = 3; Amount local_funds_msat = 4; Amount remote_funds_msat = 7; @@ -265,6 +271,7 @@ message ListpeersPeersChannelsHtlcs { bytes payment_hash = 5; optional bool local_trimmed = 6; optional string status = 7; + HtlcState state = 8; } message ListfundsRequest { @@ -303,6 +310,7 @@ message ListfundsChannels { uint32 funding_output = 5; bool connected = 6; ChannelState state = 7; + optional bytes channel_id = 9; optional string short_channel_id = 8; } @@ -587,7 +595,6 @@ message InvoiceRequest { optional uint64 expiry = 7; repeated string fallbacks = 4; optional bytes preimage = 5; - optional bool exposeprivatechannels = 8; optional uint32 cltv = 6; optional bool deschashonly = 9; } @@ -753,47 +760,15 @@ message ListtransactionsTransactions { } message ListtransactionsTransactionsInputs { - // ListTransactions.transactions[].inputs[].type - enum ListtransactionsTransactionsInputsType { - THEIRS = 0; - DEPOSIT = 1; - WITHDRAW = 2; - CHANNEL_FUNDING = 3; - CHANNEL_MUTUAL_CLOSE = 4; - CHANNEL_UNILATERAL_CLOSE = 5; - CHANNEL_SWEEP = 6; - CHANNEL_HTLC_SUCCESS = 7; - CHANNEL_HTLC_TIMEOUT = 8; - CHANNEL_PENALTY = 9; - CHANNEL_UNILATERAL_CHEAT = 10; - } bytes txid = 1; uint32 index = 2; uint32 sequence = 3; - optional ListtransactionsTransactionsInputsType item_type = 4; - optional string channel = 5; } message ListtransactionsTransactionsOutputs { - // ListTransactions.transactions[].outputs[].type - enum ListtransactionsTransactionsOutputsType { - THEIRS = 0; - DEPOSIT = 1; - WITHDRAW = 2; - CHANNEL_FUNDING = 3; - CHANNEL_MUTUAL_CLOSE = 4; - CHANNEL_UNILATERAL_CLOSE = 5; - CHANNEL_SWEEP = 6; - CHANNEL_HTLC_SUCCESS = 7; - CHANNEL_HTLC_TIMEOUT = 8; - CHANNEL_PENALTY = 9; - CHANNEL_UNILATERAL_CHEAT = 10; - } uint32 index = 1; Amount amount_msat = 6; bytes scriptPubKey = 3; - optional ListtransactionsTransactionsOutputsType item_type = 4; - optional string channel = 5; } message PayRequest { @@ -854,7 +829,6 @@ message ListnodesNodesAddresses { IPV6 = 2; TORV2 = 3; TORV3 = 4; - WEBSOCKET = 5; } ListnodesNodesAddressesType item_type = 1; uint32 port = 2; @@ -1102,6 +1076,333 @@ message TxsendResponse { bytes txid = 3; } +message ListpeerchannelsRequest { + optional bytes id = 1; +} + +message ListpeerchannelsResponse { + repeated ListpeerchannelsChannels channels = 1; +} + +message ListpeerchannelsChannels { + // ListPeerChannels.channels[].state + enum ListpeerchannelsChannelsState { + OPENINGD = 0; + CHANNELD_AWAITING_LOCKIN = 1; + CHANNELD_NORMAL = 2; + CHANNELD_SHUTTING_DOWN = 3; + CLOSINGD_SIGEXCHANGE = 4; + CLOSINGD_COMPLETE = 5; + AWAITING_UNILATERAL = 6; + FUNDING_SPEND_SEEN = 7; + ONCHAIN = 8; + DUALOPEND_OPEN_INIT = 9; + DUALOPEND_AWAITING_LOCKIN = 10; + } + optional bytes peer_id = 1; + optional bool peer_connected = 2; + optional ListpeerchannelsChannelsState state = 3; + optional bytes scratch_txid = 4; + optional ListpeerchannelsChannelsFeerate feerate = 6; + optional string owner = 7; + optional string short_channel_id = 8; + optional bytes channel_id = 9; + optional bytes funding_txid = 10; + optional uint32 funding_outnum = 11; + optional string initial_feerate = 12; + optional string last_feerate = 13; + optional string next_feerate = 14; + optional uint32 next_fee_step = 15; + repeated ListpeerchannelsChannelsInflight inflight = 16; + optional bytes close_to = 17; + optional bool private = 18; + optional ChannelSide opener = 19; + optional ChannelSide closer = 20; + optional ListpeerchannelsChannelsFunding funding = 22; + optional Amount to_us_msat = 23; + optional Amount min_to_us_msat = 24; + optional Amount max_to_us_msat = 25; + optional Amount total_msat = 26; + optional Amount fee_base_msat = 27; + optional uint32 fee_proportional_millionths = 28; + optional Amount dust_limit_msat = 29; + optional Amount max_total_htlc_in_msat = 30; + optional Amount their_reserve_msat = 31; + optional Amount our_reserve_msat = 32; + optional Amount spendable_msat = 33; + optional Amount receivable_msat = 34; + optional Amount minimum_htlc_in_msat = 35; + optional Amount minimum_htlc_out_msat = 36; + optional Amount maximum_htlc_out_msat = 37; + optional uint32 their_to_self_delay = 38; + optional uint32 our_to_self_delay = 39; + optional uint32 max_accepted_htlcs = 40; + optional ListpeerchannelsChannelsAlias alias = 41; + repeated string status = 43; + optional uint64 in_payments_offered = 44; + optional Amount in_offered_msat = 45; + optional uint64 in_payments_fulfilled = 46; + optional Amount in_fulfilled_msat = 47; + optional uint64 out_payments_offered = 48; + optional Amount out_offered_msat = 49; + optional uint64 out_payments_fulfilled = 50; + optional Amount out_fulfilled_msat = 51; + repeated ListpeerchannelsChannelsHtlcs htlcs = 52; + optional string close_to_addr = 53; +} + +message ListpeerchannelsChannelsFeerate { + optional uint32 perkw = 1; + optional uint32 perkb = 2; +} + +message ListpeerchannelsChannelsInflight { + optional bytes funding_txid = 1; + optional uint32 funding_outnum = 2; + optional string feerate = 3; + optional Amount total_funding_msat = 4; + optional Amount our_funding_msat = 5; + optional bytes scratch_txid = 6; +} + +message ListpeerchannelsChannelsFunding { + optional Amount pushed_msat = 1; + optional Amount local_funds_msat = 2; + optional Amount remote_funds_msat = 3; + optional Amount fee_paid_msat = 4; + optional Amount fee_rcvd_msat = 5; +} + +message ListpeerchannelsChannelsAlias { + optional string local = 1; + optional string remote = 2; +} + +message ListpeerchannelsChannelsHtlcs { + // ListPeerChannels.channels[].htlcs[].direction + enum ListpeerchannelsChannelsHtlcsDirection { + IN = 0; + OUT = 1; + } + optional ListpeerchannelsChannelsHtlcsDirection direction = 1; + optional uint64 id = 2; + optional Amount amount_msat = 3; + optional uint32 expiry = 4; + optional bytes payment_hash = 5; + optional bool local_trimmed = 6; + optional string status = 7; + optional HtlcState state = 8; +} + +message ListclosedchannelsRequest { + optional bytes id = 1; +} + +message ListclosedchannelsResponse { + repeated ListclosedchannelsClosedchannels closedchannels = 1; +} + +message ListclosedchannelsClosedchannels { + // ListClosedChannels.closedchannels[].close_cause + enum ListclosedchannelsClosedchannelsClose_cause { + UNKNOWN = 0; + LOCAL = 1; + USER = 2; + REMOTE = 3; + PROTOCOL = 4; + ONCHAIN = 5; + } + optional bytes peer_id = 1; + bytes channel_id = 2; + optional string short_channel_id = 3; + optional ListclosedchannelsClosedchannelsAlias alias = 4; + ChannelSide opener = 5; + optional ChannelSide closer = 6; + bool private = 7; + uint64 total_local_commitments = 9; + uint64 total_remote_commitments = 10; + uint64 total_htlcs_sent = 11; + bytes funding_txid = 12; + uint32 funding_outnum = 13; + bool leased = 14; + optional Amount funding_fee_paid_msat = 15; + optional Amount funding_fee_rcvd_msat = 16; + optional Amount funding_pushed_msat = 17; + Amount total_msat = 18; + Amount final_to_us_msat = 19; + Amount min_to_us_msat = 20; + Amount max_to_us_msat = 21; + optional bytes last_commitment_txid = 22; + optional Amount last_commitment_fee_msat = 23; + ListclosedchannelsClosedchannelsClose_cause close_cause = 24; +} + +message ListclosedchannelsClosedchannelsAlias { + optional string local = 1; + optional string remote = 2; +} + +message DecodepayRequest { + string bolt11 = 1; + optional string description = 2; +} + +message DecodepayResponse { + string currency = 1; + uint64 created_at = 2; + uint64 expiry = 3; + bytes payee = 4; + optional Amount amount_msat = 5; + bytes payment_hash = 6; + string signature = 7; + optional string description = 8; + optional bytes description_hash = 9; + uint32 min_final_cltv_expiry = 10; + optional bytes payment_secret = 11; + optional bytes features = 12; + optional bytes payment_metadata = 13; + repeated DecodepayFallbacks fallbacks = 14; + repeated DecodepayExtra extra = 16; +} + +message DecodepayFallbacks { + // DecodePay.fallbacks[].type + enum DecodepayFallbacksType { + P2PKH = 0; + P2SH = 1; + P2WPKH = 2; + P2WSH = 3; + } + DecodepayFallbacksType item_type = 1; + optional string addr = 2; + bytes hex = 3; +} + +message DecodepayExtra { + string tag = 1; + string data = 2; +} + +message DecodeRequest { + string string = 1; +} + +message DecodeResponse { + // Decode.type + enum DecodeType { + BOLT12_OFFER = 0; + BOLT12_INVOICE = 1; + BOLT12_INVOICE_REQUEST = 2; + BOLT11_INVOICE = 3; + RUNE = 4; + } + DecodeType item_type = 1; + bool valid = 2; + optional bytes offer_id = 3; + repeated bytes offer_chains = 4; + optional bytes offer_metadata = 5; + optional string offer_currency = 6; + optional string warning_unknown_offer_currency = 7; + optional uint32 currency_minor_unit = 8; + optional uint64 offer_amount = 9; + optional Amount offer_amount_msat = 10; + optional string offer_description = 11; + optional string offer_issuer = 12; + optional bytes offer_features = 13; + optional uint64 offer_absolute_expiry = 14; + optional uint64 offer_quantity_max = 15; + repeated DecodeOffer_paths offer_paths = 16; + optional bytes offer_node_id = 17; + optional string warning_missing_offer_node_id = 20; + optional string warning_invalid_offer_description = 21; + optional string warning_missing_offer_description = 22; + optional string warning_invalid_offer_currency = 23; + optional string warning_invalid_offer_issuer = 24; + optional bytes invreq_metadata = 25; + optional bytes invreq_payer_id = 26; + optional bytes invreq_chain = 27; + optional Amount invreq_amount_msat = 28; + optional bytes invreq_features = 29; + optional uint64 invreq_quantity = 30; + optional string invreq_payer_note = 31; + optional uint32 invreq_recurrence_counter = 32; + optional uint32 invreq_recurrence_start = 33; + optional string warning_missing_invreq_metadata = 35; + optional string warning_missing_invreq_payer_id = 36; + optional string warning_invalid_invreq_payer_note = 37; + optional string warning_missing_invoice_request_signature = 38; + optional string warning_invalid_invoice_request_signature = 39; + optional uint64 invoice_created_at = 41; + optional uint32 invoice_relative_expiry = 42; + optional bytes invoice_payment_hash = 43; + optional Amount invoice_amount_msat = 44; + repeated DecodeInvoice_fallbacks invoice_fallbacks = 45; + optional bytes invoice_features = 46; + optional bytes invoice_node_id = 47; + optional uint64 invoice_recurrence_basetime = 48; + optional string warning_missing_invoice_paths = 50; + optional string warning_missing_invoice_blindedpay = 51; + optional string warning_missing_invoice_created_at = 52; + optional string warning_missing_invoice_payment_hash = 53; + optional string warning_missing_invoice_amount = 54; + optional string warning_missing_invoice_recurrence_basetime = 55; + optional string warning_missing_invoice_node_id = 56; + optional string warning_missing_invoice_signature = 57; + optional string warning_invalid_invoice_signature = 58; + repeated DecodeFallbacks fallbacks = 59; + optional uint64 created_at = 60; + optional uint64 expiry = 61; + optional bytes payee = 62; + optional bytes payment_hash = 63; + optional bytes description_hash = 64; + optional uint32 min_final_cltv_expiry = 65; + optional bytes payment_secret = 66; + optional bytes payment_metadata = 67; + repeated DecodeExtra extra = 69; + optional string unique_id = 70; + optional string version = 71; + optional string string = 72; + repeated DecodeRestrictions restrictions = 73; + optional string warning_rune_invalid_utf8 = 74; + optional bytes hex = 75; +} + +message DecodeOffer_paths { + bytes first_node_id = 1; + bytes blinding = 2; +} + +message DecodeOffer_recurrencePaywindow { + uint32 seconds_before = 1; + uint32 seconds_after = 2; + optional bool proportional_amount = 3; +} + +message DecodeInvoice_pathsPath { + bytes blinded_node_id = 1; + bytes encrypted_recipient_data = 2; +} + +message DecodeInvoice_fallbacks { + uint32 version = 1; + bytes hex = 2; + optional string address = 3; +} + +message DecodeFallbacks { + optional string warning_invoice_fallbacks_version_invalid = 1; +} + +message DecodeExtra { + string tag = 1; + string data = 2; +} + +message DecodeRestrictions { + repeated string alternatives = 1; + string summary = 2; +} + message DisconnectRequest { bytes id = 1; optional bool force = 2; @@ -1129,6 +1430,8 @@ message FeeratesResponse { message FeeratesPerkb { uint32 min_acceptable = 1; uint32 max_acceptable = 2; + optional uint32 floor = 10; + repeated FeeratesPerkbEstimates estimates = 9; optional uint32 opening = 3; optional uint32 mutual_close = 4; optional uint32 unilateral_close = 5; @@ -1137,9 +1440,17 @@ message FeeratesPerkb { optional uint32 penalty = 8; } +message FeeratesPerkbEstimates { + optional uint32 blockcount = 1; + optional uint32 feerate = 2; + optional uint32 smoothed_feerate = 3; +} + message FeeratesPerkw { uint32 min_acceptable = 1; uint32 max_acceptable = 2; + optional uint32 floor = 10; + repeated FeeratesPerkwEstimates estimates = 9; optional uint32 opening = 3; optional uint32 mutual_close = 4; optional uint32 unilateral_close = 5; @@ -1148,6 +1459,12 @@ message FeeratesPerkw { optional uint32 penalty = 8; } +message FeeratesPerkwEstimates { + optional uint32 blockcount = 1; + optional uint32 feerate = 2; + optional uint32 smoothed_feerate = 3; +} + message FeeratesOnchain_fee_estimates { uint64 opening_channel_satoshis = 1; uint64 mutual_close_satoshis = 2; @@ -1203,7 +1520,6 @@ message GetrouteRoute { bytes id = 1; string channel = 2; uint32 direction = 3; - optional uint64 msatoshi = 7; Amount amount_msat = 4; uint32 delay = 5; GetrouteRouteStyle style = 6; @@ -1298,6 +1614,15 @@ message PingResponse { uint32 totlen = 1; } +message SendcustommsgRequest { + bytes node_id = 1; + bytes msg = 2; +} + +message SendcustommsgResponse { + string status = 1; +} + message SetchannelRequest { string id = 1; optional Amount feebase = 2; @@ -1323,6 +1648,14 @@ message SetchannelChannels { optional string warning_htlcmax_too_high = 9; } +message SigninvoiceRequest { + string invstring = 1; +} + +message SigninvoiceResponse { + string bolt11 = 1; +} + message SignmessageRequest { string message = 1; } @@ -1338,3 +1671,19 @@ message StopRequest { message StopResponse { } + +message PreapprovekeysendRequest { + optional bytes destination = 1; + optional bytes payment_hash = 2; + optional Amount amount_msat = 3; +} + +message PreapprovekeysendResponse { +} + +message PreapproveinvoiceRequest { + optional string bolt11 = 1; +} + +message PreapproveinvoiceResponse { +} diff --git a/cln-grpc/proto/primitives.proto b/cln-grpc/proto/primitives.proto index 0f469295ad9b..31402364baae 100644 --- a/cln-grpc/proto/primitives.proto +++ b/cln-grpc/proto/primitives.proto @@ -20,8 +20,8 @@ message AmountOrAny { } enum ChannelSide { - IN = 0; - OUT = 1; + LOCAL = 0; + REMOTE = 1; } enum ChannelState { @@ -38,6 +38,29 @@ enum ChannelState { DualopendAwaitingLockin = 10; } +enum HtlcState { + SentAddHtlc = 0; + SentAddCommit = 1; + RcvdAddRevocation = 2; + RcvdAddAckCommit = 3; + SentAddAckRevocation = 4; + RcvdAddAckRevocation = 5; + RcvdRemoveHtlc = 6; + RcvdRemoveCommit = 7; + SentRemoveRevocation = 8; + SentRemoveAckCommit = 9; + RcvdRemoveAckRevocation = 10; + RCVD_ADD_HTLC = 11; + RCVD_ADD_COMMIT = 12; + SENT_ADD_REVOCATION = 13; + SENT_ADD_ACK_COMMIT = 14; + SENT_REMOVE_HTLC = 15; + SENT_REMOVE_COMMIT = 16; + RCVD_REMOVE_REVOCATION = 17; + RCVD_REMOVE_ACK_COMMIT = 18; + SENT_REMOVE_ACK_REVOCATION = 19; +} + message ChannelStateChangeCause {} message Outpoint { diff --git a/cln-grpc/src/convert.rs b/cln-grpc/src/convert.rs index f727f78b03ac..aeae52b83476 100644 --- a/cln-grpc/src/convert.rs +++ b/cln-grpc/src/convert.rs @@ -12,7 +12,7 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::Hash; use cln_rpc::primitives::PublicKey; -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::GetinfoOurFeatures { fn from(c: responses::GetinfoOur_features) -> Self { Self { @@ -24,7 +24,7 @@ impl From for pb::GetinfoOurFeatures { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::GetinfoAddress { fn from(c: responses::GetinfoAddress) -> Self { Self { @@ -35,7 +35,7 @@ impl From for pb::GetinfoAddress { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::GetinfoBinding { fn from(c: responses::GetinfoBinding) -> Self { Self { @@ -47,12 +47,12 @@ impl From for pb::GetinfoBinding { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::GetinfoResponse { fn from(c: responses::GetinfoResponse) -> Self { Self { id: c.id.serialize().to_vec(), // Rule #2 for type pubkey - alias: c.alias, // Rule #2 for type string + alias: c.alias, // Rule #2 for type string? color: hex::decode(&c.color).unwrap(), // Rule #2 for type hex num_peers: c.num_peers, // Rule #2 for type u32 num_pending_channels: c.num_pending_channels, // Rule #2 for type u32 @@ -63,17 +63,18 @@ impl From for pb::GetinfoResponse { our_features: c.our_features.map(|v| v.into()), blockheight: c.blockheight, // Rule #2 for type u32 network: c.network, // Rule #2 for type string - msatoshi_fees_collected: c.msatoshi_fees_collected, // Rule #2 for type u64? fees_collected_msat: Some(c.fees_collected_msat.into()), // Rule #2 for type msat - address: c.address.into_iter().map(|i| i.into()).collect(), // Rule #3 for type GetinfoAddress - binding: c.binding.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + // Field: Getinfo.address[] + address: c.address.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + // Field: Getinfo.binding[] + binding: c.binding.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 warning_bitcoind_sync: c.warning_bitcoind_sync, // Rule #2 for type string? warning_lightningd_sync: c.warning_lightningd_sync, // Rule #2 for type string? } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListpeersPeersLog { fn from(c: responses::ListpeersPeersLog) -> Self { Self { @@ -88,7 +89,7 @@ impl From for pb::ListpeersPeersLog { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListpeersPeersChannelsFeerate { fn from(c: responses::ListpeersPeersChannelsFeerate) -> Self { Self { @@ -98,7 +99,7 @@ impl From for pb::ListpeersPeersChanne } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListpeersPeersChannelsInflight { fn from(c: responses::ListpeersPeersChannelsInflight) -> Self { Self { @@ -112,12 +113,10 @@ impl From for pb::ListpeersPeersChann } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListpeersPeersChannelsFunding { fn from(c: responses::ListpeersPeersChannelsFunding) -> Self { Self { - local_msat: c.local_msat.map(|f| f.into()), // Rule #2 for type msat? - remote_msat: c.remote_msat.map(|f| f.into()), // Rule #2 for type msat? pushed_msat: c.pushed_msat.map(|f| f.into()), // Rule #2 for type msat? local_funds_msat: Some(c.local_funds_msat.into()), // Rule #2 for type msat remote_funds_msat: Some(c.remote_funds_msat.into()), // Rule #2 for type msat @@ -127,7 +126,7 @@ impl From for pb::ListpeersPeersChanne } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListpeersPeersChannelsAlias { fn from(c: responses::ListpeersPeersChannelsAlias) -> Self { Self { @@ -137,7 +136,7 @@ impl From for pb::ListpeersPeersChannels } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListpeersPeersChannelsHtlcs { fn from(c: responses::ListpeersPeersChannelsHtlcs) -> Self { Self { @@ -148,11 +147,12 @@ impl From for pb::ListpeersPeersChannels payment_hash: c.payment_hash.to_vec(), // Rule #2 for type hash local_trimmed: c.local_trimmed, // Rule #2 for type boolean? status: c.status, // Rule #2 for type string? + state: c.state as i32, } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListpeersPeersChannels { fn from(c: responses::ListpeersPeersChannels) -> Self { Self { @@ -168,12 +168,14 @@ impl From for pb::ListpeersPeersChannels { last_feerate: c.last_feerate, // Rule #2 for type string? next_feerate: c.next_feerate, // Rule #2 for type string? next_fee_step: c.next_fee_step, // Rule #2 for type u32? - inflight: c.inflight.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + // Field: ListPeers.peers[].channels[].inflight[] + inflight: c.inflight.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 close_to: c.close_to.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? private: c.private, // Rule #2 for type boolean? opener: c.opener as i32, closer: c.closer.map(|v| v as i32), - features: c.features.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListpeersPeersChannelsFeatures + // Field: ListPeers.peers[].channels[].features[] + features: c.features.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListpeersPeersChannelsFeatures funding: c.funding.map(|v| v.into()), to_us_msat: c.to_us_msat.map(|f| f.into()), // Rule #2 for type msat? min_to_us_msat: c.min_to_us_msat.map(|f| f.into()), // Rule #2 for type msat? @@ -194,7 +196,8 @@ impl From for pb::ListpeersPeersChannels { our_to_self_delay: c.our_to_self_delay, // Rule #2 for type u32? max_accepted_htlcs: c.max_accepted_htlcs, // Rule #2 for type u32? alias: c.alias.map(|v| v.into()), - status: c.status.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + // Field: ListPeers.peers[].channels[].status[] + status: c.status.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 in_payments_offered: c.in_payments_offered, // Rule #2 for type u64? in_offered_msat: c.in_offered_msat.map(|f| f.into()), // Rule #2 for type msat? in_payments_fulfilled: c.in_payments_fulfilled, // Rule #2 for type u64? @@ -203,37 +206,43 @@ impl From for pb::ListpeersPeersChannels { out_offered_msat: c.out_offered_msat.map(|f| f.into()), // Rule #2 for type msat? out_payments_fulfilled: c.out_payments_fulfilled, // Rule #2 for type u64? out_fulfilled_msat: c.out_fulfilled_msat.map(|f| f.into()), // Rule #2 for type msat? - htlcs: c.htlcs.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + // Field: ListPeers.peers[].channels[].htlcs[] + htlcs: c.htlcs.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 close_to_addr: c.close_to_addr, // Rule #2 for type string? } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListpeersPeers { fn from(c: responses::ListpeersPeers) -> Self { Self { id: c.id.serialize().to_vec(), // Rule #2 for type pubkey connected: c.connected, // Rule #2 for type boolean - log: c.log.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 - channels: c.channels.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 - netaddr: c.netaddr.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + num_channels: c.num_channels, // Rule #2 for type u32? + // Field: ListPeers.peers[].log[] + log: c.log.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + // Field: ListPeers.peers[].channels[] + channels: c.channels.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + // Field: ListPeers.peers[].netaddr[] + netaddr: c.netaddr.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 remote_addr: c.remote_addr, // Rule #2 for type string? features: c.features.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListpeersResponse { fn from(c: responses::ListpeersResponse) -> Self { Self { - peers: c.peers.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListpeersPeers + // Field: ListPeers.peers[] + peers: c.peers.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListpeersPeers } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListfundsOutputs { fn from(c: responses::ListfundsOutputs) -> Self { Self { @@ -250,7 +259,7 @@ impl From for pb::ListfundsOutputs { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListfundsChannels { fn from(c: responses::ListfundsChannels) -> Self { Self { @@ -261,22 +270,25 @@ impl From for pb::ListfundsChannels { funding_output: c.funding_output, // Rule #2 for type u32 connected: c.connected, // Rule #2 for type boolean state: c.state as i32, + channel_id: c.channel_id.map(|v| v.to_vec()), // Rule #2 for type hash? short_channel_id: c.short_channel_id.map(|v| v.to_string()), // Rule #2 for type short_channel_id? } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListfundsResponse { fn from(c: responses::ListfundsResponse) -> Self { Self { - outputs: c.outputs.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListfundsOutputs - channels: c.channels.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListfundsChannels + // Field: ListFunds.outputs[] + outputs: c.outputs.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListfundsOutputs + // Field: ListFunds.channels[] + channels: c.channels.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListfundsChannels } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::SendpayResponse { fn from(c: responses::SendpayResponse) -> Self { Self { @@ -299,7 +311,7 @@ impl From for pb::SendpayResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListchannelsChannels { fn from(c: responses::ListchannelsChannels) -> Self { Self { @@ -323,16 +335,17 @@ impl From for pb::ListchannelsChannels { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListchannelsResponse { fn from(c: responses::ListchannelsResponse) -> Self { Self { - channels: c.channels.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListchannelsChannels + // Field: ListChannels.channels[] + channels: c.channels.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListchannelsChannels } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::AddgossipResponse { fn from(c: responses::AddgossipResponse) -> Self { Self { @@ -340,7 +353,7 @@ impl From for pb::AddgossipResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::AutocleaninvoiceResponse { fn from(c: responses::AutocleaninvoiceResponse) -> Self { Self { @@ -351,7 +364,7 @@ impl From for pb::AutocleaninvoiceResponse } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::CheckmessageResponse { fn from(c: responses::CheckmessageResponse) -> Self { Self { @@ -361,7 +374,7 @@ impl From for pb::CheckmessageResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::CloseResponse { fn from(c: responses::CloseResponse) -> Self { Self { @@ -372,7 +385,7 @@ impl From for pb::CloseResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ConnectAddress { fn from(c: responses::ConnectAddress) -> Self { Self { @@ -384,7 +397,7 @@ impl From for pb::ConnectAddress { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ConnectResponse { fn from(c: responses::ConnectResponse) -> Self { Self { @@ -396,7 +409,7 @@ impl From for pb::ConnectResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::CreateinvoiceResponse { fn from(c: responses::CreateinvoiceResponse) -> Self { Self { @@ -418,11 +431,12 @@ impl From for pb::CreateinvoiceResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::DatastoreResponse { fn from(c: responses::DatastoreResponse) -> Self { Self { - key: c.key.into_iter().map(|i| i.into()).collect(), // Rule #3 for type string + // Field: Datastore.key + key: c.key.into_iter().map(|i| i.into()).collect(), // Rule #3 for type string generation: c.generation, // Rule #2 for type u64? hex: c.hex.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? string: c.string, // Rule #2 for type string? @@ -430,21 +444,23 @@ impl From for pb::DatastoreResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::CreateonionResponse { fn from(c: responses::CreateonionResponse) -> Self { Self { onion: hex::decode(&c.onion).unwrap(), // Rule #2 for type hex - shared_secrets: c.shared_secrets.into_iter().map(|i| i.to_vec()).collect(), // Rule #3 for type secret + // Field: CreateOnion.shared_secrets[] + shared_secrets: c.shared_secrets.into_iter().map(|i| i.to_vec()).collect(), // Rule #3 for type secret } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::DeldatastoreResponse { fn from(c: responses::DeldatastoreResponse) -> Self { Self { - key: c.key.into_iter().map(|i| i.into()).collect(), // Rule #3 for type string + // Field: DelDatastore.key + key: c.key.into_iter().map(|i| i.into()).collect(), // Rule #3 for type string generation: c.generation, // Rule #2 for type u64? hex: c.hex.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? string: c.string, // Rule #2 for type string? @@ -452,7 +468,7 @@ impl From for pb::DeldatastoreResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::DelexpiredinvoiceResponse { fn from(c: responses::DelexpiredinvoiceResponse) -> Self { Self { @@ -460,7 +476,7 @@ impl From for pb::DelexpiredinvoiceRespons } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::DelinvoiceResponse { fn from(c: responses::DelinvoiceResponse) -> Self { Self { @@ -478,7 +494,7 @@ impl From for pb::DelinvoiceResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::InvoiceResponse { fn from(c: responses::InvoiceResponse) -> Self { Self { @@ -495,11 +511,12 @@ impl From for pb::InvoiceResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListdatastoreDatastore { fn from(c: responses::ListdatastoreDatastore) -> Self { Self { - key: c.key.into_iter().map(|i| i.into()).collect(), // Rule #3 for type string + // Field: ListDatastore.datastore[].key[] + key: c.key.into_iter().map(|i| i.into()).collect(), // Rule #3 for type string generation: c.generation, // Rule #2 for type u64? hex: c.hex.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? string: c.string, // Rule #2 for type string? @@ -507,16 +524,17 @@ impl From for pb::ListdatastoreDatastore { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListdatastoreResponse { fn from(c: responses::ListdatastoreResponse) -> Self { Self { - datastore: c.datastore.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListdatastoreDatastore + // Field: ListDatastore.datastore[] + datastore: c.datastore.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListdatastoreDatastore } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListinvoicesInvoices { fn from(c: responses::ListinvoicesInvoices) -> Self { Self { @@ -538,16 +556,17 @@ impl From for pb::ListinvoicesInvoices { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListinvoicesResponse { fn from(c: responses::ListinvoicesResponse) -> Self { Self { - invoices: c.invoices.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListinvoicesInvoices + // Field: ListInvoices.invoices[] + invoices: c.invoices.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListinvoicesInvoices } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::SendonionResponse { fn from(c: responses::SendonionResponse) -> Self { Self { @@ -568,7 +587,7 @@ impl From for pb::SendonionResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListsendpaysPayments { fn from(c: responses::ListsendpaysPayments) -> Self { Self { @@ -591,42 +610,39 @@ impl From for pb::ListsendpaysPayments { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListsendpaysResponse { fn from(c: responses::ListsendpaysResponse) -> Self { Self { - payments: c.payments.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListsendpaysPayments + // Field: ListSendPays.payments[] + payments: c.payments.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListsendpaysPayments } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListtransactionsTransactionsInputs { fn from(c: responses::ListtransactionsTransactionsInputs) -> Self { Self { txid: hex::decode(&c.txid).unwrap(), // Rule #2 for type txid index: c.index, // Rule #2 for type u32 sequence: c.sequence, // Rule #2 for type u32 - item_type: c.item_type.map(|v| v as i32), - channel: c.channel.map(|v| v.to_string()), // Rule #2 for type short_channel_id? } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListtransactionsTransactionsOutputs { fn from(c: responses::ListtransactionsTransactionsOutputs) -> Self { Self { index: c.index, // Rule #2 for type u32 amount_msat: Some(c.amount_msat.into()), // Rule #2 for type msat script_pub_key: hex::decode(&c.script_pub_key).unwrap(), // Rule #2 for type hex - item_type: c.item_type.map(|v| v as i32), - channel: c.channel.map(|v| v.to_string()), // Rule #2 for type short_channel_id? } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListtransactionsTransactions { fn from(c: responses::ListtransactionsTransactions) -> Self { Self { @@ -636,22 +652,25 @@ impl From for pb::ListtransactionsTrans txindex: c.txindex, // Rule #2 for type u32 locktime: c.locktime, // Rule #2 for type u32 version: c.version, // Rule #2 for type u32 - inputs: c.inputs.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListtransactionsTransactionsInputs - outputs: c.outputs.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListtransactionsTransactionsOutputs + // Field: ListTransactions.transactions[].inputs[] + inputs: c.inputs.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListtransactionsTransactionsInputs + // Field: ListTransactions.transactions[].outputs[] + outputs: c.outputs.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListtransactionsTransactionsOutputs } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListtransactionsResponse { fn from(c: responses::ListtransactionsResponse) -> Self { Self { - transactions: c.transactions.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListtransactionsTransactions + // Field: ListTransactions.transactions[] + transactions: c.transactions.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListtransactionsTransactions } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::PayResponse { fn from(c: responses::PayResponse) -> Self { Self { @@ -668,7 +687,7 @@ impl From for pb::PayResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListnodesNodesAddresses { fn from(c: responses::ListnodesNodesAddresses) -> Self { Self { @@ -679,7 +698,7 @@ impl From for pb::ListnodesNodesAddresses { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListnodesNodes { fn from(c: responses::ListnodesNodes) -> Self { Self { @@ -688,21 +707,23 @@ impl From for pb::ListnodesNodes { alias: c.alias, // Rule #2 for type string? color: c.color.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? features: c.features.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? - addresses: c.addresses.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + // Field: ListNodes.nodes[].addresses[] + addresses: c.addresses.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListnodesResponse { fn from(c: responses::ListnodesResponse) -> Self { Self { - nodes: c.nodes.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListnodesNodes + // Field: ListNodes.nodes[] + nodes: c.nodes.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListnodesNodes } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::WaitanyinvoiceResponse { fn from(c: responses::WaitanyinvoiceResponse) -> Self { Self { @@ -722,7 +743,7 @@ impl From for pb::WaitanyinvoiceResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::WaitinvoiceResponse { fn from(c: responses::WaitinvoiceResponse) -> Self { Self { @@ -742,7 +763,7 @@ impl From for pb::WaitinvoiceResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::WaitsendpayResponse { fn from(c: responses::WaitsendpayResponse) -> Self { Self { @@ -764,17 +785,18 @@ impl From for pb::WaitsendpayResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::NewaddrResponse { fn from(c: responses::NewaddrResponse) -> Self { Self { bech32: c.bech32, // Rule #2 for type string? + #[allow(deprecated)] p2sh_segwit: c.p2sh_segwit, // Rule #2 for type string? } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::WithdrawResponse { fn from(c: responses::WithdrawResponse) -> Self { Self { @@ -785,7 +807,7 @@ impl From for pb::WithdrawResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::KeysendResponse { fn from(c: responses::KeysendResponse) -> Self { Self { @@ -802,7 +824,7 @@ impl From for pb::KeysendResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::FundpsbtReservations { fn from(c: responses::FundpsbtReservations) -> Self { Self { @@ -815,7 +837,7 @@ impl From for pb::FundpsbtReservations { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::FundpsbtResponse { fn from(c: responses::FundpsbtResponse) -> Self { Self { @@ -824,12 +846,13 @@ impl From for pb::FundpsbtResponse { estimated_final_weight: c.estimated_final_weight, // Rule #2 for type u32 excess_msat: Some(c.excess_msat.into()), // Rule #2 for type msat change_outnum: c.change_outnum, // Rule #2 for type u32? - reservations: c.reservations.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + // Field: FundPsbt.reservations[] + reservations: c.reservations.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::SendpsbtResponse { fn from(c: responses::SendpsbtResponse) -> Self { Self { @@ -839,7 +862,7 @@ impl From for pb::SendpsbtResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::SignpsbtResponse { fn from(c: responses::SignpsbtResponse) -> Self { Self { @@ -848,7 +871,7 @@ impl From for pb::SignpsbtResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::UtxopsbtReservations { fn from(c: responses::UtxopsbtReservations) -> Self { Self { @@ -861,7 +884,7 @@ impl From for pb::UtxopsbtReservations { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::UtxopsbtResponse { fn from(c: responses::UtxopsbtResponse) -> Self { Self { @@ -870,12 +893,13 @@ impl From for pb::UtxopsbtResponse { estimated_final_weight: c.estimated_final_weight, // Rule #2 for type u32 excess_msat: Some(c.excess_msat.into()), // Rule #2 for type msat change_outnum: c.change_outnum, // Rule #2 for type u32? - reservations: c.reservations.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + // Field: UtxoPsbt.reservations[] + reservations: c.reservations.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::TxdiscardResponse { fn from(c: responses::TxdiscardResponse) -> Self { Self { @@ -885,7 +909,7 @@ impl From for pb::TxdiscardResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::TxprepareResponse { fn from(c: responses::TxprepareResponse) -> Self { Self { @@ -896,7 +920,7 @@ impl From for pb::TxprepareResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::TxsendResponse { fn from(c: responses::TxsendResponse) -> Self { Self { @@ -907,7 +931,372 @@ impl From for pb::TxsendResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] +impl From for pb::ListpeerchannelsChannelsFeerate { + fn from(c: responses::ListpeerchannelsChannelsFeerate) -> Self { + Self { + perkw: c.perkw, // Rule #2 for type u32? + perkb: c.perkb, // Rule #2 for type u32? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListpeerchannelsChannelsInflight { + fn from(c: responses::ListpeerchannelsChannelsInflight) -> Self { + Self { + funding_txid: c.funding_txid.map(|v| hex::decode(v).unwrap()), // Rule #2 for type txid? + funding_outnum: c.funding_outnum, // Rule #2 for type u32? + feerate: c.feerate, // Rule #2 for type string? + total_funding_msat: c.total_funding_msat.map(|f| f.into()), // Rule #2 for type msat? + our_funding_msat: c.our_funding_msat.map(|f| f.into()), // Rule #2 for type msat? + scratch_txid: c.scratch_txid.map(|v| hex::decode(v).unwrap()), // Rule #2 for type txid? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListpeerchannelsChannelsFunding { + fn from(c: responses::ListpeerchannelsChannelsFunding) -> Self { + Self { + pushed_msat: c.pushed_msat.map(|f| f.into()), // Rule #2 for type msat? + local_funds_msat: c.local_funds_msat.map(|f| f.into()), // Rule #2 for type msat? + remote_funds_msat: c.remote_funds_msat.map(|f| f.into()), // Rule #2 for type msat? + fee_paid_msat: c.fee_paid_msat.map(|f| f.into()), // Rule #2 for type msat? + fee_rcvd_msat: c.fee_rcvd_msat.map(|f| f.into()), // Rule #2 for type msat? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListpeerchannelsChannelsAlias { + fn from(c: responses::ListpeerchannelsChannelsAlias) -> Self { + Self { + local: c.local.map(|v| v.to_string()), // Rule #2 for type short_channel_id? + remote: c.remote.map(|v| v.to_string()), // Rule #2 for type short_channel_id? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListpeerchannelsChannelsHtlcs { + fn from(c: responses::ListpeerchannelsChannelsHtlcs) -> Self { + Self { + direction: c.direction.map(|v| v as i32), + id: c.id, // Rule #2 for type u64? + amount_msat: c.amount_msat.map(|f| f.into()), // Rule #2 for type msat? + expiry: c.expiry, // Rule #2 for type u32? + payment_hash: c.payment_hash.map(|v| v.to_vec()), // Rule #2 for type hash? + local_trimmed: c.local_trimmed, // Rule #2 for type boolean? + status: c.status, // Rule #2 for type string? + state: c.state.map(|v| v as i32), + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListpeerchannelsChannels { + fn from(c: responses::ListpeerchannelsChannels) -> Self { + Self { + peer_id: c.peer_id.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? + peer_connected: c.peer_connected, // Rule #2 for type boolean? + state: c.state.map(|v| v as i32), + scratch_txid: c.scratch_txid.map(|v| hex::decode(v).unwrap()), // Rule #2 for type txid? + feerate: c.feerate.map(|v| v.into()), + owner: c.owner, // Rule #2 for type string? + short_channel_id: c.short_channel_id.map(|v| v.to_string()), // Rule #2 for type short_channel_id? + channel_id: c.channel_id.map(|v| v.to_vec()), // Rule #2 for type hash? + funding_txid: c.funding_txid.map(|v| hex::decode(v).unwrap()), // Rule #2 for type txid? + funding_outnum: c.funding_outnum, // Rule #2 for type u32? + initial_feerate: c.initial_feerate, // Rule #2 for type string? + last_feerate: c.last_feerate, // Rule #2 for type string? + next_feerate: c.next_feerate, // Rule #2 for type string? + next_fee_step: c.next_fee_step, // Rule #2 for type u32? + // Field: ListPeerChannels.channels[].inflight[] + inflight: c.inflight.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + close_to: c.close_to.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + private: c.private, // Rule #2 for type boolean? + opener: c.opener.map(|v| v as i32), + closer: c.closer.map(|v| v as i32), + funding: c.funding.map(|v| v.into()), + to_us_msat: c.to_us_msat.map(|f| f.into()), // Rule #2 for type msat? + min_to_us_msat: c.min_to_us_msat.map(|f| f.into()), // Rule #2 for type msat? + max_to_us_msat: c.max_to_us_msat.map(|f| f.into()), // Rule #2 for type msat? + total_msat: c.total_msat.map(|f| f.into()), // Rule #2 for type msat? + fee_base_msat: c.fee_base_msat.map(|f| f.into()), // Rule #2 for type msat? + fee_proportional_millionths: c.fee_proportional_millionths, // Rule #2 for type u32? + dust_limit_msat: c.dust_limit_msat.map(|f| f.into()), // Rule #2 for type msat? + max_total_htlc_in_msat: c.max_total_htlc_in_msat.map(|f| f.into()), // Rule #2 for type msat? + their_reserve_msat: c.their_reserve_msat.map(|f| f.into()), // Rule #2 for type msat? + our_reserve_msat: c.our_reserve_msat.map(|f| f.into()), // Rule #2 for type msat? + spendable_msat: c.spendable_msat.map(|f| f.into()), // Rule #2 for type msat? + receivable_msat: c.receivable_msat.map(|f| f.into()), // Rule #2 for type msat? + minimum_htlc_in_msat: c.minimum_htlc_in_msat.map(|f| f.into()), // Rule #2 for type msat? + minimum_htlc_out_msat: c.minimum_htlc_out_msat.map(|f| f.into()), // Rule #2 for type msat? + maximum_htlc_out_msat: c.maximum_htlc_out_msat.map(|f| f.into()), // Rule #2 for type msat? + their_to_self_delay: c.their_to_self_delay, // Rule #2 for type u32? + our_to_self_delay: c.our_to_self_delay, // Rule #2 for type u32? + max_accepted_htlcs: c.max_accepted_htlcs, // Rule #2 for type u32? + alias: c.alias.map(|v| v.into()), + // Field: ListPeerChannels.channels[].status[] + status: c.status.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + in_payments_offered: c.in_payments_offered, // Rule #2 for type u64? + in_offered_msat: c.in_offered_msat.map(|f| f.into()), // Rule #2 for type msat? + in_payments_fulfilled: c.in_payments_fulfilled, // Rule #2 for type u64? + in_fulfilled_msat: c.in_fulfilled_msat.map(|f| f.into()), // Rule #2 for type msat? + out_payments_offered: c.out_payments_offered, // Rule #2 for type u64? + out_offered_msat: c.out_offered_msat.map(|f| f.into()), // Rule #2 for type msat? + out_payments_fulfilled: c.out_payments_fulfilled, // Rule #2 for type u64? + out_fulfilled_msat: c.out_fulfilled_msat.map(|f| f.into()), // Rule #2 for type msat? + // Field: ListPeerChannels.channels[].htlcs[] + htlcs: c.htlcs.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + close_to_addr: c.close_to_addr, // Rule #2 for type string? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListpeerchannelsResponse { + fn from(c: responses::ListpeerchannelsResponse) -> Self { + Self { + // Field: ListPeerChannels.channels[] + channels: c.channels.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListclosedchannelsClosedchannelsAlias { + fn from(c: responses::ListclosedchannelsClosedchannelsAlias) -> Self { + Self { + local: c.local.map(|v| v.to_string()), // Rule #2 for type short_channel_id? + remote: c.remote.map(|v| v.to_string()), // Rule #2 for type short_channel_id? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListclosedchannelsClosedchannels { + fn from(c: responses::ListclosedchannelsClosedchannels) -> Self { + Self { + peer_id: c.peer_id.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? + channel_id: c.channel_id.to_vec(), // Rule #2 for type hash + short_channel_id: c.short_channel_id.map(|v| v.to_string()), // Rule #2 for type short_channel_id? + alias: c.alias.map(|v| v.into()), + opener: c.opener as i32, + closer: c.closer.map(|v| v as i32), + private: c.private, // Rule #2 for type boolean + total_local_commitments: c.total_local_commitments, // Rule #2 for type u64 + total_remote_commitments: c.total_remote_commitments, // Rule #2 for type u64 + total_htlcs_sent: c.total_htlcs_sent, // Rule #2 for type u64 + funding_txid: hex::decode(&c.funding_txid).unwrap(), // Rule #2 for type txid + funding_outnum: c.funding_outnum, // Rule #2 for type u32 + leased: c.leased, // Rule #2 for type boolean + funding_fee_paid_msat: c.funding_fee_paid_msat.map(|f| f.into()), // Rule #2 for type msat? + funding_fee_rcvd_msat: c.funding_fee_rcvd_msat.map(|f| f.into()), // Rule #2 for type msat? + funding_pushed_msat: c.funding_pushed_msat.map(|f| f.into()), // Rule #2 for type msat? + total_msat: Some(c.total_msat.into()), // Rule #2 for type msat + final_to_us_msat: Some(c.final_to_us_msat.into()), // Rule #2 for type msat + min_to_us_msat: Some(c.min_to_us_msat.into()), // Rule #2 for type msat + max_to_us_msat: Some(c.max_to_us_msat.into()), // Rule #2 for type msat + last_commitment_txid: c.last_commitment_txid.map(|v| v.to_vec()), // Rule #2 for type hash? + last_commitment_fee_msat: c.last_commitment_fee_msat.map(|f| f.into()), // Rule #2 for type msat? + close_cause: c.close_cause as i32, + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListclosedchannelsResponse { + fn from(c: responses::ListclosedchannelsResponse) -> Self { + Self { + // Field: ListClosedChannels.closedchannels[] + closedchannels: c.closedchannels.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListclosedchannelsClosedchannels + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DecodepayFallbacks { + fn from(c: responses::DecodepayFallbacks) -> Self { + Self { + item_type: c.item_type as i32, + addr: c.addr, // Rule #2 for type string? + hex: hex::decode(&c.hex).unwrap(), // Rule #2 for type hex + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DecodepayExtra { + fn from(c: responses::DecodepayExtra) -> Self { + Self { + tag: c.tag, // Rule #2 for type string + data: c.data, // Rule #2 for type string + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DecodepayResponse { + fn from(c: responses::DecodepayResponse) -> Self { + Self { + currency: c.currency, // Rule #2 for type string + created_at: c.created_at, // Rule #2 for type u64 + expiry: c.expiry, // Rule #2 for type u64 + payee: c.payee.serialize().to_vec(), // Rule #2 for type pubkey + amount_msat: c.amount_msat.map(|f| f.into()), // Rule #2 for type msat? + payment_hash: c.payment_hash.to_vec(), // Rule #2 for type hash + signature: c.signature, // Rule #2 for type signature + description: c.description, // Rule #2 for type string? + description_hash: c.description_hash.map(|v| v.to_vec()), // Rule #2 for type hash? + min_final_cltv_expiry: c.min_final_cltv_expiry, // Rule #2 for type u32 + payment_secret: c.payment_secret.map(|v| v.to_vec()), // Rule #2 for type hash? + features: c.features.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + payment_metadata: c.payment_metadata.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + // Field: DecodePay.fallbacks[] + fallbacks: c.fallbacks.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + // Field: DecodePay.extra[] + extra: c.extra.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DecodeOfferPaths { + fn from(c: responses::DecodeOffer_paths) -> Self { + Self { + first_node_id: c.first_node_id.serialize().to_vec(), // Rule #2 for type pubkey + blinding: c.blinding.serialize().to_vec(), // Rule #2 for type pubkey + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DecodeInvoiceFallbacks { + fn from(c: responses::DecodeInvoice_fallbacks) -> Self { + Self { + version: c.version.into(), // Rule #2 for type u8 + hex: hex::decode(&c.hex).unwrap(), // Rule #2 for type hex + address: c.address, // Rule #2 for type string? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DecodeFallbacks { + fn from(c: responses::DecodeFallbacks) -> Self { + Self { + warning_invoice_fallbacks_version_invalid: c.warning_invoice_fallbacks_version_invalid, // Rule #2 for type string? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DecodeExtra { + fn from(c: responses::DecodeExtra) -> Self { + Self { + tag: c.tag, // Rule #2 for type string + data: c.data, // Rule #2 for type string + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DecodeRestrictions { + fn from(c: responses::DecodeRestrictions) -> Self { + Self { + // Field: Decode.restrictions[].alternatives[] + alternatives: c.alternatives.into_iter().map(|i| i.into()).collect(), // Rule #3 for type string + summary: c.summary, // Rule #2 for type string + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DecodeResponse { + fn from(c: responses::DecodeResponse) -> Self { + Self { + item_type: c.item_type as i32, + valid: c.valid, // Rule #2 for type boolean + offer_id: c.offer_id.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + // Field: Decode.offer_chains[] + offer_chains: c.offer_chains.map(|arr| arr.into_iter().map(|i| i.to_vec()).collect()).unwrap_or(vec![]), // Rule #3 + offer_metadata: c.offer_metadata.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + offer_currency: c.offer_currency, // Rule #2 for type string? + warning_unknown_offer_currency: c.warning_unknown_offer_currency, // Rule #2 for type string? + currency_minor_unit: c.currency_minor_unit, // Rule #2 for type u32? + offer_amount: c.offer_amount, // Rule #2 for type u64? + offer_amount_msat: c.offer_amount_msat.map(|f| f.into()), // Rule #2 for type msat? + offer_description: c.offer_description, // Rule #2 for type string? + offer_issuer: c.offer_issuer, // Rule #2 for type string? + offer_features: c.offer_features.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + offer_absolute_expiry: c.offer_absolute_expiry, // Rule #2 for type u64? + offer_quantity_max: c.offer_quantity_max, // Rule #2 for type u64? + // Field: Decode.offer_paths[] + offer_paths: c.offer_paths.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + offer_node_id: c.offer_node_id.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? + warning_missing_offer_node_id: c.warning_missing_offer_node_id, // Rule #2 for type string? + warning_invalid_offer_description: c.warning_invalid_offer_description, // Rule #2 for type string? + warning_missing_offer_description: c.warning_missing_offer_description, // Rule #2 for type string? + warning_invalid_offer_currency: c.warning_invalid_offer_currency, // Rule #2 for type string? + warning_invalid_offer_issuer: c.warning_invalid_offer_issuer, // Rule #2 for type string? + invreq_metadata: c.invreq_metadata.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + invreq_payer_id: c.invreq_payer_id.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + invreq_chain: c.invreq_chain.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + invreq_amount_msat: c.invreq_amount_msat.map(|f| f.into()), // Rule #2 for type msat? + invreq_features: c.invreq_features.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + invreq_quantity: c.invreq_quantity, // Rule #2 for type u64? + invreq_payer_note: c.invreq_payer_note, // Rule #2 for type string? + invreq_recurrence_counter: c.invreq_recurrence_counter, // Rule #2 for type u32? + invreq_recurrence_start: c.invreq_recurrence_start, // Rule #2 for type u32? + warning_missing_invreq_metadata: c.warning_missing_invreq_metadata, // Rule #2 for type string? + warning_missing_invreq_payer_id: c.warning_missing_invreq_payer_id, // Rule #2 for type string? + warning_invalid_invreq_payer_note: c.warning_invalid_invreq_payer_note, // Rule #2 for type string? + warning_missing_invoice_request_signature: c.warning_missing_invoice_request_signature, // Rule #2 for type string? + warning_invalid_invoice_request_signature: c.warning_invalid_invoice_request_signature, // Rule #2 for type string? + invoice_created_at: c.invoice_created_at, // Rule #2 for type u64? + invoice_relative_expiry: c.invoice_relative_expiry, // Rule #2 for type u32? + invoice_payment_hash: c.invoice_payment_hash.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + invoice_amount_msat: c.invoice_amount_msat.map(|f| f.into()), // Rule #2 for type msat? + // Field: Decode.invoice_fallbacks[] + invoice_fallbacks: c.invoice_fallbacks.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + invoice_features: c.invoice_features.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + invoice_node_id: c.invoice_node_id.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? + invoice_recurrence_basetime: c.invoice_recurrence_basetime, // Rule #2 for type u64? + warning_missing_invoice_paths: c.warning_missing_invoice_paths, // Rule #2 for type string? + warning_missing_invoice_blindedpay: c.warning_missing_invoice_blindedpay, // Rule #2 for type string? + warning_missing_invoice_created_at: c.warning_missing_invoice_created_at, // Rule #2 for type string? + warning_missing_invoice_payment_hash: c.warning_missing_invoice_payment_hash, // Rule #2 for type string? + warning_missing_invoice_amount: c.warning_missing_invoice_amount, // Rule #2 for type string? + warning_missing_invoice_recurrence_basetime: c.warning_missing_invoice_recurrence_basetime, // Rule #2 for type string? + warning_missing_invoice_node_id: c.warning_missing_invoice_node_id, // Rule #2 for type string? + warning_missing_invoice_signature: c.warning_missing_invoice_signature, // Rule #2 for type string? + warning_invalid_invoice_signature: c.warning_invalid_invoice_signature, // Rule #2 for type string? + // Field: Decode.fallbacks[] + fallbacks: c.fallbacks.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + created_at: c.created_at, // Rule #2 for type u64? + expiry: c.expiry, // Rule #2 for type u64? + payee: c.payee.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? + payment_hash: c.payment_hash.map(|v| v.to_vec()), // Rule #2 for type hash? + description_hash: c.description_hash.map(|v| v.to_vec()), // Rule #2 for type hash? + min_final_cltv_expiry: c.min_final_cltv_expiry, // Rule #2 for type u32? + payment_secret: c.payment_secret.map(|v| v.to_vec()), // Rule #2 for type secret? + payment_metadata: c.payment_metadata.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + // Field: Decode.extra[] + extra: c.extra.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + unique_id: c.unique_id, // Rule #2 for type string? + version: c.version, // Rule #2 for type string? + string: c.string, // Rule #2 for type string? + // Field: Decode.restrictions[] + restrictions: c.restrictions.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + warning_rune_invalid_utf8: c.warning_rune_invalid_utf8, // Rule #2 for type string? + hex: c.hex.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + } + } +} + +#[allow(unused_variables,deprecated)] impl From for pb::DisconnectResponse { fn from(c: responses::DisconnectResponse) -> Self { Self { @@ -915,39 +1304,71 @@ impl From for pb::DisconnectResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] +impl From for pb::FeeratesPerkbEstimates { + fn from(c: responses::FeeratesPerkbEstimates) -> Self { + Self { + blockcount: c.blockcount, // Rule #2 for type u32? + feerate: c.feerate, // Rule #2 for type u32? + smoothed_feerate: c.smoothed_feerate, // Rule #2 for type u32? + } + } +} + +#[allow(unused_variables,deprecated)] impl From for pb::FeeratesPerkb { fn from(c: responses::FeeratesPerkb) -> Self { Self { min_acceptable: c.min_acceptable, // Rule #2 for type u32 max_acceptable: c.max_acceptable, // Rule #2 for type u32 + floor: c.floor, // Rule #2 for type u32? + // Field: Feerates.perkb.estimates[] + estimates: c.estimates.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 opening: c.opening, // Rule #2 for type u32? mutual_close: c.mutual_close, // Rule #2 for type u32? unilateral_close: c.unilateral_close, // Rule #2 for type u32? + #[allow(deprecated)] delayed_to_us: c.delayed_to_us, // Rule #2 for type u32? + #[allow(deprecated)] htlc_resolution: c.htlc_resolution, // Rule #2 for type u32? penalty: c.penalty, // Rule #2 for type u32? } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] +impl From for pb::FeeratesPerkwEstimates { + fn from(c: responses::FeeratesPerkwEstimates) -> Self { + Self { + blockcount: c.blockcount, // Rule #2 for type u32? + feerate: c.feerate, // Rule #2 for type u32? + smoothed_feerate: c.smoothed_feerate, // Rule #2 for type u32? + } + } +} + +#[allow(unused_variables,deprecated)] impl From for pb::FeeratesPerkw { fn from(c: responses::FeeratesPerkw) -> Self { Self { min_acceptable: c.min_acceptable, // Rule #2 for type u32 max_acceptable: c.max_acceptable, // Rule #2 for type u32 + floor: c.floor, // Rule #2 for type u32? + // Field: Feerates.perkw.estimates[] + estimates: c.estimates.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 opening: c.opening, // Rule #2 for type u32? mutual_close: c.mutual_close, // Rule #2 for type u32? unilateral_close: c.unilateral_close, // Rule #2 for type u32? + #[allow(deprecated)] delayed_to_us: c.delayed_to_us, // Rule #2 for type u32? + #[allow(deprecated)] htlc_resolution: c.htlc_resolution, // Rule #2 for type u32? penalty: c.penalty, // Rule #2 for type u32? } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::FeeratesOnchainFeeEstimates { fn from(c: responses::FeeratesOnchain_fee_estimates) -> Self { Self { @@ -960,7 +1381,7 @@ impl From for pb::FeeratesOnchainFeeEs } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::FeeratesResponse { fn from(c: responses::FeeratesResponse) -> Self { Self { @@ -972,7 +1393,7 @@ impl From for pb::FeeratesResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::FundchannelResponse { fn from(c: responses::FundchannelResponse) -> Self { Self { @@ -986,14 +1407,13 @@ impl From for pb::FundchannelResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::GetrouteRoute { fn from(c: responses::GetrouteRoute) -> Self { Self { id: c.id.serialize().to_vec(), // Rule #2 for type pubkey channel: c.channel.to_string(), // Rule #2 for type short_channel_id direction: c.direction, // Rule #2 for type u32 - msatoshi: c.msatoshi, // Rule #2 for type u64? amount_msat: Some(c.amount_msat.into()), // Rule #2 for type msat delay: c.delay, // Rule #2 for type u32 style: c.style as i32, @@ -1001,16 +1421,17 @@ impl From for pb::GetrouteRoute { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::GetrouteResponse { fn from(c: responses::GetrouteResponse) -> Self { Self { - route: c.route.into_iter().map(|i| i.into()).collect(), // Rule #3 for type GetrouteRoute + // Field: GetRoute.route[] + route: c.route.into_iter().map(|i| i.into()).collect(), // Rule #3 for type GetrouteRoute } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListforwardsForwards { fn from(c: responses::ListforwardsForwards) -> Self { Self { @@ -1028,16 +1449,17 @@ impl From for pb::ListforwardsForwards { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListforwardsResponse { fn from(c: responses::ListforwardsResponse) -> Self { Self { - forwards: c.forwards.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListforwardsForwards + // Field: ListForwards.forwards[] + forwards: c.forwards.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListforwardsForwards } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListpaysPays { fn from(c: responses::ListpaysPays) -> Self { Self { @@ -1057,16 +1479,17 @@ impl From for pb::ListpaysPays { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::ListpaysResponse { fn from(c: responses::ListpaysResponse) -> Self { Self { - pays: c.pays.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListpaysPays + // Field: ListPays.pays[] + pays: c.pays.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListpaysPays } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::PingResponse { fn from(c: responses::PingResponse) -> Self { Self { @@ -1075,7 +1498,16 @@ impl From for pb::PingResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] +impl From for pb::SendcustommsgResponse { + fn from(c: responses::SendcustommsgResponse) -> Self { + Self { + status: c.status, // Rule #2 for type string + } + } +} + +#[allow(unused_variables,deprecated)] impl From for pb::SetchannelChannels { fn from(c: responses::SetchannelChannels) -> Self { Self { @@ -1092,16 +1524,26 @@ impl From for pb::SetchannelChannels { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::SetchannelResponse { fn from(c: responses::SetchannelResponse) -> Self { Self { - channels: c.channels.into_iter().map(|i| i.into()).collect(), // Rule #3 for type SetchannelChannels + // Field: SetChannel.channels[] + channels: c.channels.into_iter().map(|i| i.into()).collect(), // Rule #3 for type SetchannelChannels + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::SigninvoiceResponse { + fn from(c: responses::SigninvoiceResponse) -> Self { + Self { + bolt11: c.bolt11, // Rule #2 for type string } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::SignmessageResponse { fn from(c: responses::SignmessageResponse) -> Self { Self { @@ -1112,7 +1554,7 @@ impl From for pb::SignmessageResponse { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for pb::StopResponse { fn from(c: responses::StopResponse) -> Self { Self { @@ -1120,119 +1562,814 @@ impl From for pb::StopResponse { } } -#[allow(unused_variables)] -impl From for requests::GetinfoRequest { - fn from(c: pb::GetinfoRequest) -> Self { +#[allow(unused_variables,deprecated)] +impl From for pb::PreapprovekeysendResponse { + fn from(c: responses::PreapprovekeysendResponse) -> Self { Self { } } } -#[allow(unused_variables)] -impl From for requests::ListpeersRequest { - fn from(c: pb::ListpeersRequest) -> Self { +#[allow(unused_variables,deprecated)] +impl From for pb::PreapproveinvoiceResponse { + fn from(c: responses::PreapproveinvoiceResponse) -> Self { Self { - id: c.id.map(|v| PublicKey::from_slice(&v).unwrap()), // Rule #1 for type pubkey? - level: c.level, // Rule #1 for type string? } } } -#[allow(unused_variables)] -impl From for requests::ListfundsRequest { - fn from(c: pb::ListfundsRequest) -> Self { +#[allow(unused_variables,deprecated)] +impl From for pb::GetinfoRequest { + fn from(c: requests::GetinfoRequest) -> Self { Self { - spent: c.spent, // Rule #1 for type boolean? } } } -#[allow(unused_variables)] -impl From for requests::SendpayRoute { - fn from(c: pb::SendpayRoute) -> Self { +#[allow(unused_variables,deprecated)] +impl From for pb::ListpeersRequest { + fn from(c: requests::ListpeersRequest) -> Self { Self { - amount_msat: c.amount_msat.unwrap().into(), // Rule #1 for type msat - id: PublicKey::from_slice(&c.id).unwrap(), // Rule #1 for type pubkey - delay: c.delay as u16, // Rule #1 for type u16 - channel: cln_rpc::primitives::ShortChannelId::from_str(&c.channel).unwrap(), // Rule #1 for type short_channel_id + id: c.id.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? + level: c.level, // Rule #2 for type string? } } } -#[allow(unused_variables)] -impl From for requests::SendpayRequest { - fn from(c: pb::SendpayRequest) -> Self { +#[allow(unused_variables,deprecated)] +impl From for pb::ListfundsRequest { + fn from(c: requests::ListfundsRequest) -> Self { Self { - route: c.route.into_iter().map(|s| s.into()).collect(), // Rule #4 - payment_hash: Sha256::from_slice(&c.payment_hash).unwrap(), // Rule #1 for type hash - label: c.label, // Rule #1 for type string? - amount_msat: c.amount_msat.map(|a| a.into()), // Rule #1 for type msat? - bolt11: c.bolt11, // Rule #1 for type string? - payment_secret: c.payment_secret.map(|v| v.try_into().unwrap()), // Rule #1 for type secret? - partid: c.partid.map(|v| v as u16), // Rule #1 for type u16? - localinvreqid: c.localinvreqid.map(|v| hex::encode(v)), // Rule #1 for type hex? - groupid: c.groupid, // Rule #1 for type u64? + spent: c.spent, // Rule #2 for type boolean? } } } -#[allow(unused_variables)] -impl From for requests::ListchannelsRequest { - fn from(c: pb::ListchannelsRequest) -> Self { +#[allow(unused_variables,deprecated)] +impl From for pb::SendpayRoute { + fn from(c: requests::SendpayRoute) -> Self { Self { - short_channel_id: c.short_channel_id.map(|v| cln_rpc::primitives::ShortChannelId::from_str(&v).unwrap()), // Rule #1 for type short_channel_id? - source: c.source.map(|v| PublicKey::from_slice(&v).unwrap()), // Rule #1 for type pubkey? - destination: c.destination.map(|v| PublicKey::from_slice(&v).unwrap()), // Rule #1 for type pubkey? + amount_msat: Some(c.amount_msat.into()), // Rule #2 for type msat + id: c.id.serialize().to_vec(), // Rule #2 for type pubkey + delay: c.delay.into(), // Rule #2 for type u16 + channel: c.channel.to_string(), // Rule #2 for type short_channel_id } } } -#[allow(unused_variables)] -impl From for requests::AddgossipRequest { - fn from(c: pb::AddgossipRequest) -> Self { +#[allow(unused_variables,deprecated)] +impl From for pb::SendpayRequest { + fn from(c: requests::SendpayRequest) -> Self { Self { - message: hex::encode(&c.message), // Rule #1 for type hex + // Field: SendPay.route[] + route: c.route.into_iter().map(|i| i.into()).collect(), // Rule #3 for type SendpayRoute + payment_hash: c.payment_hash.to_vec(), // Rule #2 for type hash + label: c.label, // Rule #2 for type string? + amount_msat: c.amount_msat.map(|f| f.into()), // Rule #2 for type msat? + bolt11: c.bolt11, // Rule #2 for type string? + payment_secret: c.payment_secret.map(|v| v.to_vec()), // Rule #2 for type secret? + partid: c.partid.map(|v| v.into()), // Rule #2 for type u16? + localinvreqid: c.localinvreqid.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + groupid: c.groupid, // Rule #2 for type u64? } } } -#[allow(unused_variables)] -impl From for requests::AutocleaninvoiceRequest { - fn from(c: pb::AutocleaninvoiceRequest) -> Self { +#[allow(unused_variables,deprecated)] +impl From for pb::ListchannelsRequest { + fn from(c: requests::ListchannelsRequest) -> Self { Self { - expired_by: c.expired_by, // Rule #1 for type u64? - cycle_seconds: c.cycle_seconds, // Rule #1 for type u64? + short_channel_id: c.short_channel_id.map(|v| v.to_string()), // Rule #2 for type short_channel_id? + source: c.source.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? + destination: c.destination.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? } } } -#[allow(unused_variables)] -impl From for requests::CheckmessageRequest { - fn from(c: pb::CheckmessageRequest) -> Self { +#[allow(unused_variables,deprecated)] +impl From for pb::AddgossipRequest { + fn from(c: requests::AddgossipRequest) -> Self { Self { - message: c.message, // Rule #1 for type string - zbase: c.zbase, // Rule #1 for type string - pubkey: c.pubkey.map(|v| PublicKey::from_slice(&v).unwrap()), // Rule #1 for type pubkey? + message: hex::decode(&c.message).unwrap(), // Rule #2 for type hex } } } -#[allow(unused_variables)] -impl From for requests::CloseRequest { - fn from(c: pb::CloseRequest) -> Self { +#[allow(unused_variables,deprecated)] +impl From for pb::AutocleaninvoiceRequest { + fn from(c: requests::AutocleaninvoiceRequest) -> Self { Self { - id: c.id, // Rule #1 for type string - unilateraltimeout: c.unilateraltimeout, // Rule #1 for type u32? - destination: c.destination, // Rule #1 for type string? - fee_negotiation_step: c.fee_negotiation_step, // Rule #1 for type string? - wrong_funding: c.wrong_funding.map(|a| a.into()), // Rule #1 for type outpoint? - force_lease_closed: c.force_lease_closed, // Rule #1 for type boolean? - feerange: Some(c.feerange.into_iter().map(|s| s.into()).collect()), // Rule #4 + expired_by: c.expired_by, // Rule #2 for type u64? + cycle_seconds: c.cycle_seconds, // Rule #2 for type u64? } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] +impl From for pb::CheckmessageRequest { + fn from(c: requests::CheckmessageRequest) -> Self { + Self { + message: c.message, // Rule #2 for type string + zbase: c.zbase, // Rule #2 for type string + pubkey: c.pubkey.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::CloseRequest { + fn from(c: requests::CloseRequest) -> Self { + Self { + id: c.id, // Rule #2 for type string + unilateraltimeout: c.unilateraltimeout, // Rule #2 for type u32? + destination: c.destination, // Rule #2 for type string? + fee_negotiation_step: c.fee_negotiation_step, // Rule #2 for type string? + wrong_funding: c.wrong_funding.map(|o|o.into()), // Rule #2 for type outpoint? + force_lease_closed: c.force_lease_closed, // Rule #2 for type boolean? + // Field: Close.feerange[] + feerange: c.feerange.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ConnectRequest { + fn from(c: requests::ConnectRequest) -> Self { + Self { + id: c.id, // Rule #2 for type string + host: c.host, // Rule #2 for type string? + port: c.port.map(|v| v.into()), // Rule #2 for type u16? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::CreateinvoiceRequest { + fn from(c: requests::CreateinvoiceRequest) -> Self { + Self { + invstring: c.invstring, // Rule #2 for type string + label: c.label, // Rule #2 for type string + preimage: hex::decode(&c.preimage).unwrap(), // Rule #2 for type hex + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DatastoreRequest { + fn from(c: requests::DatastoreRequest) -> Self { + Self { + // Field: Datastore.key + key: c.key.into_iter().map(|i| i.into()).collect(), // Rule #3 for type string + string: c.string, // Rule #2 for type string? + hex: c.hex.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + mode: c.mode.map(|v| v as i32), + generation: c.generation, // Rule #2 for type u64? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::CreateonionHops { + fn from(c: requests::CreateonionHops) -> Self { + Self { + pubkey: c.pubkey.serialize().to_vec(), // Rule #2 for type pubkey + payload: hex::decode(&c.payload).unwrap(), // Rule #2 for type hex + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::CreateonionRequest { + fn from(c: requests::CreateonionRequest) -> Self { + Self { + // Field: CreateOnion.hops[] + hops: c.hops.into_iter().map(|i| i.into()).collect(), // Rule #3 for type CreateonionHops + assocdata: hex::decode(&c.assocdata).unwrap(), // Rule #2 for type hex + session_key: c.session_key.map(|v| v.to_vec()), // Rule #2 for type secret? + onion_size: c.onion_size.map(|v| v.into()), // Rule #2 for type u16? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DeldatastoreRequest { + fn from(c: requests::DeldatastoreRequest) -> Self { + Self { + // Field: DelDatastore.key + key: c.key.into_iter().map(|i| i.into()).collect(), // Rule #3 for type string + generation: c.generation, // Rule #2 for type u64? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DelexpiredinvoiceRequest { + fn from(c: requests::DelexpiredinvoiceRequest) -> Self { + Self { + maxexpirytime: c.maxexpirytime, // Rule #2 for type u64? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DelinvoiceRequest { + fn from(c: requests::DelinvoiceRequest) -> Self { + Self { + label: c.label, // Rule #2 for type string + status: c.status as i32, + desconly: c.desconly, // Rule #2 for type boolean? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::InvoiceRequest { + fn from(c: requests::InvoiceRequest) -> Self { + Self { + amount_msat: Some(c.amount_msat.into()), // Rule #2 for type msat_or_any + description: c.description, // Rule #2 for type string + label: c.label, // Rule #2 for type string + expiry: c.expiry, // Rule #2 for type u64? + // Field: Invoice.fallbacks[] + fallbacks: c.fallbacks.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + preimage: c.preimage.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + cltv: c.cltv, // Rule #2 for type u32? + deschashonly: c.deschashonly, // Rule #2 for type boolean? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListdatastoreRequest { + fn from(c: requests::ListdatastoreRequest) -> Self { + Self { + // Field: ListDatastore.key + key: c.key.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListinvoicesRequest { + fn from(c: requests::ListinvoicesRequest) -> Self { + Self { + label: c.label, // Rule #2 for type string? + invstring: c.invstring, // Rule #2 for type string? + payment_hash: c.payment_hash.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + offer_id: c.offer_id, // Rule #2 for type string? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::SendonionFirstHop { + fn from(c: requests::SendonionFirst_hop) -> Self { + Self { + id: c.id.serialize().to_vec(), // Rule #2 for type pubkey + amount_msat: Some(c.amount_msat.into()), // Rule #2 for type msat + delay: c.delay.into(), // Rule #2 for type u16 + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::SendonionRequest { + fn from(c: requests::SendonionRequest) -> Self { + Self { + onion: hex::decode(&c.onion).unwrap(), // Rule #2 for type hex + first_hop: Some(c.first_hop.into()), + payment_hash: c.payment_hash.to_vec(), // Rule #2 for type hash + label: c.label, // Rule #2 for type string? + // Field: SendOnion.shared_secrets[] + shared_secrets: c.shared_secrets.map(|arr| arr.into_iter().map(|i| i.to_vec()).collect()).unwrap_or(vec![]), // Rule #3 + partid: c.partid.map(|v| v.into()), // Rule #2 for type u16? + bolt11: c.bolt11, // Rule #2 for type string? + amount_msat: c.amount_msat.map(|f| f.into()), // Rule #2 for type msat? + destination: c.destination.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? + localinvreqid: c.localinvreqid.map(|v| v.to_vec()), // Rule #2 for type hash? + groupid: c.groupid, // Rule #2 for type u64? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListsendpaysRequest { + fn from(c: requests::ListsendpaysRequest) -> Self { + Self { + bolt11: c.bolt11, // Rule #2 for type string? + payment_hash: c.payment_hash.map(|v| v.to_vec()), // Rule #2 for type hash? + status: c.status.map(|v| v as i32), + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListtransactionsRequest { + fn from(c: requests::ListtransactionsRequest) -> Self { + Self { + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::PayRequest { + fn from(c: requests::PayRequest) -> Self { + Self { + bolt11: c.bolt11, // Rule #2 for type string + amount_msat: c.amount_msat.map(|f| f.into()), // Rule #2 for type msat? + label: c.label, // Rule #2 for type string? + riskfactor: c.riskfactor, // Rule #2 for type number? + maxfeepercent: c.maxfeepercent, // Rule #2 for type number? + retry_for: c.retry_for.map(|v| v.into()), // Rule #2 for type u16? + maxdelay: c.maxdelay.map(|v| v.into()), // Rule #2 for type u16? + exemptfee: c.exemptfee.map(|f| f.into()), // Rule #2 for type msat? + localinvreqid: c.localinvreqid.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + // Field: Pay.exclude + exclude: c.exclude.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + maxfee: c.maxfee.map(|f| f.into()), // Rule #2 for type msat? + description: c.description, // Rule #2 for type string? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListnodesRequest { + fn from(c: requests::ListnodesRequest) -> Self { + Self { + id: c.id.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::WaitanyinvoiceRequest { + fn from(c: requests::WaitanyinvoiceRequest) -> Self { + Self { + lastpay_index: c.lastpay_index, // Rule #2 for type u64? + timeout: c.timeout, // Rule #2 for type u64? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::WaitinvoiceRequest { + fn from(c: requests::WaitinvoiceRequest) -> Self { + Self { + label: c.label, // Rule #2 for type string + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::WaitsendpayRequest { + fn from(c: requests::WaitsendpayRequest) -> Self { + Self { + payment_hash: c.payment_hash.to_vec(), // Rule #2 for type hash + timeout: c.timeout, // Rule #2 for type u32? + partid: c.partid, // Rule #2 for type u64? + groupid: c.groupid, // Rule #2 for type u64? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::NewaddrRequest { + fn from(c: requests::NewaddrRequest) -> Self { + Self { + addresstype: c.addresstype.map(|v| v as i32), + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::WithdrawRequest { + fn from(c: requests::WithdrawRequest) -> Self { + Self { + destination: c.destination, // Rule #2 for type string + satoshi: c.satoshi.map(|o|o.into()), // Rule #2 for type msat_or_all? + feerate: c.feerate.map(|o|o.into()), // Rule #2 for type feerate? + minconf: c.minconf.map(|v| v.into()), // Rule #2 for type u16? + // Field: Withdraw.utxos[] + utxos: c.utxos.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::KeysendRequest { + fn from(c: requests::KeysendRequest) -> Self { + Self { + destination: c.destination.serialize().to_vec(), // Rule #2 for type pubkey + amount_msat: Some(c.amount_msat.into()), // Rule #2 for type msat + label: c.label, // Rule #2 for type string? + maxfeepercent: c.maxfeepercent, // Rule #2 for type number? + retry_for: c.retry_for, // Rule #2 for type u32? + maxdelay: c.maxdelay, // Rule #2 for type u32? + exemptfee: c.exemptfee.map(|f| f.into()), // Rule #2 for type msat? + routehints: c.routehints.map(|rl| rl.into()), // Rule #2 for type RoutehintList? + extratlvs: c.extratlvs.map(|s| s.into()), // Rule #2 for type TlvStream? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::FundpsbtRequest { + fn from(c: requests::FundpsbtRequest) -> Self { + Self { + satoshi: Some(c.satoshi.into()), // Rule #2 for type msat_or_all + feerate: Some(c.feerate.into()), // Rule #2 for type feerate + startweight: c.startweight, // Rule #2 for type u32 + minconf: c.minconf, // Rule #2 for type u32? + reserve: c.reserve, // Rule #2 for type u32? + locktime: c.locktime, // Rule #2 for type u32? + min_witness_weight: c.min_witness_weight, // Rule #2 for type u32? + excess_as_change: c.excess_as_change, // Rule #2 for type boolean? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::SendpsbtRequest { + fn from(c: requests::SendpsbtRequest) -> Self { + Self { + psbt: c.psbt, // Rule #2 for type string + reserve: c.reserve, // Rule #2 for type boolean? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::SignpsbtRequest { + fn from(c: requests::SignpsbtRequest) -> Self { + Self { + psbt: c.psbt, // Rule #2 for type string + // Field: SignPsbt.signonly[] + signonly: c.signonly.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::UtxopsbtRequest { + fn from(c: requests::UtxopsbtRequest) -> Self { + Self { + satoshi: Some(c.satoshi.into()), // Rule #2 for type msat + feerate: Some(c.feerate.into()), // Rule #2 for type feerate + startweight: c.startweight, // Rule #2 for type u32 + // Field: UtxoPsbt.utxos[] + utxos: c.utxos.into_iter().map(|i| i.into()).collect(), // Rule #3 for type outpoint + reserve: c.reserve, // Rule #2 for type u32? + reservedok: c.reservedok, // Rule #2 for type boolean? + locktime: c.locktime, // Rule #2 for type u32? + min_witness_weight: c.min_witness_weight, // Rule #2 for type u32? + excess_as_change: c.excess_as_change, // Rule #2 for type boolean? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::TxdiscardRequest { + fn from(c: requests::TxdiscardRequest) -> Self { + Self { + txid: hex::decode(&c.txid).unwrap(), // Rule #2 for type txid + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::TxprepareRequest { + fn from(c: requests::TxprepareRequest) -> Self { + Self { + // Field: TxPrepare.outputs[] + outputs: c.outputs.into_iter().map(|i| i.into()).collect(), // Rule #3 for type outputdesc + feerate: c.feerate.map(|o|o.into()), // Rule #2 for type feerate? + minconf: c.minconf, // Rule #2 for type u32? + // Field: TxPrepare.utxos[] + utxos: c.utxos.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::TxsendRequest { + fn from(c: requests::TxsendRequest) -> Self { + Self { + txid: hex::decode(&c.txid).unwrap(), // Rule #2 for type txid + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListpeerchannelsRequest { + fn from(c: requests::ListpeerchannelsRequest) -> Self { + Self { + id: c.id.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListclosedchannelsRequest { + fn from(c: requests::ListclosedchannelsRequest) -> Self { + Self { + id: c.id.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DecodepayRequest { + fn from(c: requests::DecodepayRequest) -> Self { + Self { + bolt11: c.bolt11, // Rule #2 for type string + description: c.description, // Rule #2 for type string? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DecodeRequest { + fn from(c: requests::DecodeRequest) -> Self { + Self { + string: c.string, // Rule #2 for type string + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::DisconnectRequest { + fn from(c: requests::DisconnectRequest) -> Self { + Self { + id: c.id.serialize().to_vec(), // Rule #2 for type pubkey + force: c.force, // Rule #2 for type boolean? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::FeeratesRequest { + fn from(c: requests::FeeratesRequest) -> Self { + Self { + style: c.style as i32, + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::FundchannelRequest { + fn from(c: requests::FundchannelRequest) -> Self { + Self { + id: c.id.serialize().to_vec(), // Rule #2 for type pubkey + amount: Some(c.amount.into()), // Rule #2 for type msat_or_all + feerate: c.feerate.map(|o|o.into()), // Rule #2 for type feerate? + announce: c.announce, // Rule #2 for type boolean? + minconf: c.minconf, // Rule #2 for type u32? + push_msat: c.push_msat.map(|f| f.into()), // Rule #2 for type msat? + close_to: c.close_to, // Rule #2 for type string? + request_amt: c.request_amt.map(|f| f.into()), // Rule #2 for type msat? + compact_lease: c.compact_lease, // Rule #2 for type string? + // Field: FundChannel.utxos[] + utxos: c.utxos.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + mindepth: c.mindepth, // Rule #2 for type u32? + reserve: c.reserve.map(|f| f.into()), // Rule #2 for type msat? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::GetrouteRequest { + fn from(c: requests::GetrouteRequest) -> Self { + Self { + id: c.id.serialize().to_vec(), // Rule #2 for type pubkey + amount_msat: Some(c.amount_msat.into()), // Rule #2 for type msat + riskfactor: c.riskfactor, // Rule #2 for type u64 + cltv: c.cltv, // Rule #2 for type number? + fromid: c.fromid.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? + fuzzpercent: c.fuzzpercent, // Rule #2 for type u32? + // Field: GetRoute.exclude[] + exclude: c.exclude.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 + maxhops: c.maxhops, // Rule #2 for type u32? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListforwardsRequest { + fn from(c: requests::ListforwardsRequest) -> Self { + Self { + status: c.status.map(|v| v as i32), + in_channel: c.in_channel.map(|v| v.to_string()), // Rule #2 for type short_channel_id? + out_channel: c.out_channel.map(|v| v.to_string()), // Rule #2 for type short_channel_id? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::ListpaysRequest { + fn from(c: requests::ListpaysRequest) -> Self { + Self { + bolt11: c.bolt11, // Rule #2 for type string? + payment_hash: c.payment_hash.map(|v| v.to_vec()), // Rule #2 for type hash? + status: c.status.map(|v| v as i32), + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::PingRequest { + fn from(c: requests::PingRequest) -> Self { + Self { + id: c.id.serialize().to_vec(), // Rule #2 for type pubkey + len: c.len.map(|v| v.into()), // Rule #2 for type u16? + pongbytes: c.pongbytes.map(|v| v.into()), // Rule #2 for type u16? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::SendcustommsgRequest { + fn from(c: requests::SendcustommsgRequest) -> Self { + Self { + node_id: c.node_id.serialize().to_vec(), // Rule #2 for type pubkey + msg: hex::decode(&c.msg).unwrap(), // Rule #2 for type hex + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::SetchannelRequest { + fn from(c: requests::SetchannelRequest) -> Self { + Self { + id: c.id, // Rule #2 for type string + feebase: c.feebase.map(|f| f.into()), // Rule #2 for type msat? + feeppm: c.feeppm, // Rule #2 for type u32? + htlcmin: c.htlcmin.map(|f| f.into()), // Rule #2 for type msat? + htlcmax: c.htlcmax.map(|f| f.into()), // Rule #2 for type msat? + enforcedelay: c.enforcedelay, // Rule #2 for type u32? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::SigninvoiceRequest { + fn from(c: requests::SigninvoiceRequest) -> Self { + Self { + invstring: c.invstring, // Rule #2 for type string + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::SignmessageRequest { + fn from(c: requests::SignmessageRequest) -> Self { + Self { + message: c.message, // Rule #2 for type string + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::StopRequest { + fn from(c: requests::StopRequest) -> Self { + Self { + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::PreapprovekeysendRequest { + fn from(c: requests::PreapprovekeysendRequest) -> Self { + Self { + destination: c.destination.map(|v| v.serialize().to_vec()), // Rule #2 for type pubkey? + payment_hash: c.payment_hash.map(|v| hex::decode(v).unwrap()), // Rule #2 for type hex? + amount_msat: c.amount_msat.map(|f| f.into()), // Rule #2 for type msat? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for pb::PreapproveinvoiceRequest { + fn from(c: requests::PreapproveinvoiceRequest) -> Self { + Self { + bolt11: c.bolt11, // Rule #2 for type string? + } + } +} + + +#[allow(unused_variables,deprecated)] +impl From for requests::GetinfoRequest { + fn from(c: pb::GetinfoRequest) -> Self { + Self { + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for requests::ListpeersRequest { + fn from(c: pb::ListpeersRequest) -> Self { + Self { + id: c.id.map(|v| PublicKey::from_slice(&v).unwrap()), // Rule #1 for type pubkey? + level: c.level, // Rule #1 for type string? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for requests::ListfundsRequest { + fn from(c: pb::ListfundsRequest) -> Self { + Self { + spent: c.spent, // Rule #1 for type boolean? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for requests::SendpayRoute { + fn from(c: pb::SendpayRoute) -> Self { + Self { + amount_msat: c.amount_msat.unwrap().into(), // Rule #1 for type msat + id: PublicKey::from_slice(&c.id).unwrap(), // Rule #1 for type pubkey + delay: c.delay as u16, // Rule #1 for type u16 + channel: cln_rpc::primitives::ShortChannelId::from_str(&c.channel).unwrap(), // Rule #1 for type short_channel_id + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for requests::SendpayRequest { + fn from(c: pb::SendpayRequest) -> Self { + Self { + route: c.route.into_iter().map(|s| s.into()).collect(), // Rule #4 + payment_hash: Sha256::from_slice(&c.payment_hash).unwrap(), // Rule #1 for type hash + label: c.label, // Rule #1 for type string? + amount_msat: c.amount_msat.map(|a| a.into()), // Rule #1 for type msat? + bolt11: c.bolt11, // Rule #1 for type string? + payment_secret: c.payment_secret.map(|v| v.try_into().unwrap()), // Rule #1 for type secret? + partid: c.partid.map(|v| v as u16), // Rule #1 for type u16? + localinvreqid: c.localinvreqid.map(|v| hex::encode(v)), // Rule #1 for type hex? + groupid: c.groupid, // Rule #1 for type u64? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for requests::ListchannelsRequest { + fn from(c: pb::ListchannelsRequest) -> Self { + Self { + short_channel_id: c.short_channel_id.map(|v| cln_rpc::primitives::ShortChannelId::from_str(&v).unwrap()), // Rule #1 for type short_channel_id? + source: c.source.map(|v| PublicKey::from_slice(&v).unwrap()), // Rule #1 for type pubkey? + destination: c.destination.map(|v| PublicKey::from_slice(&v).unwrap()), // Rule #1 for type pubkey? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for requests::AddgossipRequest { + fn from(c: pb::AddgossipRequest) -> Self { + Self { + message: hex::encode(&c.message), // Rule #1 for type hex + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for requests::AutocleaninvoiceRequest { + fn from(c: pb::AutocleaninvoiceRequest) -> Self { + Self { + expired_by: c.expired_by, // Rule #1 for type u64? + cycle_seconds: c.cycle_seconds, // Rule #1 for type u64? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for requests::CheckmessageRequest { + fn from(c: pb::CheckmessageRequest) -> Self { + Self { + message: c.message, // Rule #1 for type string + zbase: c.zbase, // Rule #1 for type string + pubkey: c.pubkey.map(|v| PublicKey::from_slice(&v).unwrap()), // Rule #1 for type pubkey? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for requests::CloseRequest { + fn from(c: pb::CloseRequest) -> Self { + Self { + id: c.id, // Rule #1 for type string + unilateraltimeout: c.unilateraltimeout, // Rule #1 for type u32? + destination: c.destination, // Rule #1 for type string? + fee_negotiation_step: c.fee_negotiation_step, // Rule #1 for type string? + wrong_funding: c.wrong_funding.map(|a| a.into()), // Rule #1 for type outpoint? + force_lease_closed: c.force_lease_closed, // Rule #1 for type boolean? + feerange: Some(c.feerange.into_iter().map(|s| s.into()).collect()), // Rule #4 + } + } +} + +#[allow(unused_variables,deprecated)] impl From for requests::ConnectRequest { fn from(c: pb::ConnectRequest) -> Self { Self { @@ -1243,7 +2380,7 @@ impl From for requests::ConnectRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::CreateinvoiceRequest { fn from(c: pb::CreateinvoiceRequest) -> Self { Self { @@ -1254,7 +2391,7 @@ impl From for requests::CreateinvoiceRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::DatastoreRequest { fn from(c: pb::DatastoreRequest) -> Self { Self { @@ -1267,7 +2404,7 @@ impl From for requests::DatastoreRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::CreateonionHops { fn from(c: pb::CreateonionHops) -> Self { Self { @@ -1277,7 +2414,7 @@ impl From for requests::CreateonionHops { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::CreateonionRequest { fn from(c: pb::CreateonionRequest) -> Self { Self { @@ -1289,7 +2426,7 @@ impl From for requests::CreateonionRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::DeldatastoreRequest { fn from(c: pb::DeldatastoreRequest) -> Self { Self { @@ -1299,7 +2436,7 @@ impl From for requests::DeldatastoreRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::DelexpiredinvoiceRequest { fn from(c: pb::DelexpiredinvoiceRequest) -> Self { Self { @@ -1308,7 +2445,7 @@ impl From for requests::DelexpiredinvoiceRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::DelinvoiceRequest { fn from(c: pb::DelinvoiceRequest) -> Self { Self { @@ -1319,7 +2456,7 @@ impl From for requests::DelinvoiceRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::InvoiceRequest { fn from(c: pb::InvoiceRequest) -> Self { Self { @@ -1329,14 +2466,13 @@ impl From for requests::InvoiceRequest { expiry: c.expiry, // Rule #1 for type u64? fallbacks: Some(c.fallbacks.into_iter().map(|s| s.into()).collect()), // Rule #4 preimage: c.preimage.map(|v| hex::encode(v)), // Rule #1 for type hex? - exposeprivatechannels: c.exposeprivatechannels, // Rule #1 for type boolean? cltv: c.cltv, // Rule #1 for type u32? deschashonly: c.deschashonly, // Rule #1 for type boolean? } } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::ListdatastoreRequest { fn from(c: pb::ListdatastoreRequest) -> Self { Self { @@ -1345,7 +2481,7 @@ impl From for requests::ListdatastoreRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::ListinvoicesRequest { fn from(c: pb::ListinvoicesRequest) -> Self { Self { @@ -1357,7 +2493,7 @@ impl From for requests::ListinvoicesRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::SendonionFirst_hop { fn from(c: pb::SendonionFirstHop) -> Self { Self { @@ -1368,7 +2504,7 @@ impl From for requests::SendonionFirst_hop { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::SendonionRequest { fn from(c: pb::SendonionRequest) -> Self { Self { @@ -1387,7 +2523,7 @@ impl From for requests::SendonionRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::ListsendpaysRequest { fn from(c: pb::ListsendpaysRequest) -> Self { Self { @@ -1398,7 +2534,7 @@ impl From for requests::ListsendpaysRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::ListtransactionsRequest { fn from(c: pb::ListtransactionsRequest) -> Self { Self { @@ -1406,7 +2542,7 @@ impl From for requests::ListtransactionsRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::PayRequest { fn from(c: pb::PayRequest) -> Self { Self { @@ -1426,7 +2562,7 @@ impl From for requests::PayRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::ListnodesRequest { fn from(c: pb::ListnodesRequest) -> Self { Self { @@ -1435,7 +2571,7 @@ impl From for requests::ListnodesRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::WaitanyinvoiceRequest { fn from(c: pb::WaitanyinvoiceRequest) -> Self { Self { @@ -1445,7 +2581,7 @@ impl From for requests::WaitanyinvoiceRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::WaitinvoiceRequest { fn from(c: pb::WaitinvoiceRequest) -> Self { Self { @@ -1454,7 +2590,7 @@ impl From for requests::WaitinvoiceRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::WaitsendpayRequest { fn from(c: pb::WaitsendpayRequest) -> Self { Self { @@ -1466,7 +2602,7 @@ impl From for requests::WaitsendpayRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::NewaddrRequest { fn from(c: pb::NewaddrRequest) -> Self { Self { @@ -1475,7 +2611,7 @@ impl From for requests::NewaddrRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::WithdrawRequest { fn from(c: pb::WithdrawRequest) -> Self { Self { @@ -1488,7 +2624,7 @@ impl From for requests::WithdrawRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::KeysendRequest { fn from(c: pb::KeysendRequest) -> Self { Self { @@ -1505,7 +2641,7 @@ impl From for requests::KeysendRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::FundpsbtRequest { fn from(c: pb::FundpsbtRequest) -> Self { Self { @@ -1521,7 +2657,7 @@ impl From for requests::FundpsbtRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::SendpsbtRequest { fn from(c: pb::SendpsbtRequest) -> Self { Self { @@ -1531,7 +2667,7 @@ impl From for requests::SendpsbtRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::SignpsbtRequest { fn from(c: pb::SignpsbtRequest) -> Self { Self { @@ -1541,7 +2677,7 @@ impl From for requests::SignpsbtRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::UtxopsbtRequest { fn from(c: pb::UtxopsbtRequest) -> Self { Self { @@ -1558,7 +2694,7 @@ impl From for requests::UtxopsbtRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::TxdiscardRequest { fn from(c: pb::TxdiscardRequest) -> Self { Self { @@ -1567,7 +2703,7 @@ impl From for requests::TxdiscardRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::TxprepareRequest { fn from(c: pb::TxprepareRequest) -> Self { Self { @@ -1579,7 +2715,7 @@ impl From for requests::TxprepareRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::TxsendRequest { fn from(c: pb::TxsendRequest) -> Self { Self { @@ -1588,7 +2724,44 @@ impl From for requests::TxsendRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] +impl From for requests::ListpeerchannelsRequest { + fn from(c: pb::ListpeerchannelsRequest) -> Self { + Self { + id: c.id.map(|v| PublicKey::from_slice(&v).unwrap()), // Rule #1 for type pubkey? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for requests::ListclosedchannelsRequest { + fn from(c: pb::ListclosedchannelsRequest) -> Self { + Self { + id: c.id.map(|v| PublicKey::from_slice(&v).unwrap()), // Rule #1 for type pubkey? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for requests::DecodepayRequest { + fn from(c: pb::DecodepayRequest) -> Self { + Self { + bolt11: c.bolt11, // Rule #1 for type string + description: c.description, // Rule #1 for type string? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for requests::DecodeRequest { + fn from(c: pb::DecodeRequest) -> Self { + Self { + string: c.string, // Rule #1 for type string + } + } +} + +#[allow(unused_variables,deprecated)] impl From for requests::DisconnectRequest { fn from(c: pb::DisconnectRequest) -> Self { Self { @@ -1598,7 +2771,7 @@ impl From for requests::DisconnectRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::FeeratesRequest { fn from(c: pb::FeeratesRequest) -> Self { Self { @@ -1607,7 +2780,7 @@ impl From for requests::FeeratesRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::FundchannelRequest { fn from(c: pb::FundchannelRequest) -> Self { Self { @@ -1627,7 +2800,7 @@ impl From for requests::FundchannelRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::GetrouteRequest { fn from(c: pb::GetrouteRequest) -> Self { Self { @@ -1643,7 +2816,7 @@ impl From for requests::GetrouteRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::ListforwardsRequest { fn from(c: pb::ListforwardsRequest) -> Self { Self { @@ -1654,7 +2827,7 @@ impl From for requests::ListforwardsRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::ListpaysRequest { fn from(c: pb::ListpaysRequest) -> Self { Self { @@ -1665,7 +2838,7 @@ impl From for requests::ListpaysRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::PingRequest { fn from(c: pb::PingRequest) -> Self { Self { @@ -1676,7 +2849,17 @@ impl From for requests::PingRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] +impl From for requests::SendcustommsgRequest { + fn from(c: pb::SendcustommsgRequest) -> Self { + Self { + node_id: PublicKey::from_slice(&c.node_id).unwrap(), // Rule #1 for type pubkey + msg: hex::encode(&c.msg), // Rule #1 for type hex + } + } +} + +#[allow(unused_variables,deprecated)] impl From for requests::SetchannelRequest { fn from(c: pb::SetchannelRequest) -> Self { Self { @@ -1690,7 +2873,16 @@ impl From for requests::SetchannelRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] +impl From for requests::SigninvoiceRequest { + fn from(c: pb::SigninvoiceRequest) -> Self { + Self { + invstring: c.invstring, // Rule #1 for type string + } + } +} + +#[allow(unused_variables,deprecated)] impl From for requests::SignmessageRequest { fn from(c: pb::SignmessageRequest) -> Self { Self { @@ -1699,7 +2891,7 @@ impl From for requests::SignmessageRequest { } } -#[allow(unused_variables)] +#[allow(unused_variables,deprecated)] impl From for requests::StopRequest { fn from(c: pb::StopRequest) -> Self { Self { @@ -1707,3 +2899,23 @@ impl From for requests::StopRequest { } } +#[allow(unused_variables,deprecated)] +impl From for requests::PreapprovekeysendRequest { + fn from(c: pb::PreapprovekeysendRequest) -> Self { + Self { + destination: c.destination.map(|v| PublicKey::from_slice(&v).unwrap()), // Rule #1 for type pubkey? + payment_hash: c.payment_hash.map(|v| hex::encode(v)), // Rule #1 for type hex? + amount_msat: c.amount_msat.map(|a| a.into()), // Rule #1 for type msat? + } + } +} + +#[allow(unused_variables,deprecated)] +impl From for requests::PreapproveinvoiceRequest { + fn from(c: pb::PreapproveinvoiceRequest) -> Self { + Self { + bolt11: c.bolt11, // Rule #1 for type string? + } + } +} + diff --git a/cln-grpc/src/lib.rs b/cln-grpc/src/lib.rs index f9e2fec5423d..30a14cc5561c 100644 --- a/cln-grpc/src/lib.rs +++ b/cln-grpc/src/lib.rs @@ -1,10 +1,14 @@ // Huge json!() macros require lots of recursion #![recursion_limit = "1024"] +#[cfg(feature = "server")] mod convert; pub mod pb; + +#[cfg(feature = "server")] mod server; +#[cfg(feature = "server")] pub use crate::server::Server; #[cfg(test)] diff --git a/cln-grpc/src/pb.rs b/cln-grpc/src/pb.rs index 7e0cd97227ab..51fd1de3f3ad 100644 --- a/cln-grpc/src/pb.rs +++ b/cln-grpc/src/pb.rs @@ -1,376 +1,454 @@ tonic::include_proto!("cln"); -use bitcoin::hashes::Hash; -use std::str::FromStr; -use cln_rpc::primitives::{ - Amount as JAmount, AmountOrAll as JAmountOrAll, AmountOrAny as JAmountOrAny, - Feerate as JFeerate, Outpoint as JOutpoint, OutputDesc as JOutputDesc, -}; +#[cfg(feature = "server")] +pub use crate::pb::convert::*; -impl From for Amount { - fn from(a: JAmount) -> Self { - Amount { msat: a.msat() } +#[cfg(feature = "server")] +mod convert { + use super::*; + use bitcoin::hashes::Hash; + use std::str::FromStr; + + use cln_rpc::primitives::{ + Amount as JAmount, AmountOrAll as JAmountOrAll, AmountOrAny as JAmountOrAny, + Feerate as JFeerate, Outpoint as JOutpoint, OutputDesc as JOutputDesc, + }; + + impl From for Amount { + fn from(a: JAmount) -> Self { + Amount { msat: a.msat() } + } } -} -impl From for JAmount { - fn from(a: Amount) -> Self { - JAmount::from_msat(a.msat) + impl From for JAmount { + fn from(a: Amount) -> Self { + JAmount::from_msat(a.msat) + } } -} -impl From for Outpoint { - fn from(a: JOutpoint) -> Self { - Outpoint { - txid: a.txid.to_vec(), - outnum: a.outnum, + impl From for Outpoint { + fn from(a: JOutpoint) -> Self { + Outpoint { + txid: a.txid.to_vec(), + outnum: a.outnum, + } } } -} -impl From for JOutpoint { - fn from(a: Outpoint) -> Self { - JOutpoint { - txid: bitcoin::hashes::sha256::Hash::from_slice(&a.txid).unwrap(), - outnum: a.outnum, + impl From for JOutpoint { + fn from(a: Outpoint) -> Self { + JOutpoint { + txid: bitcoin::hashes::sha256::Hash::from_slice(&a.txid).unwrap(), + outnum: a.outnum, + } } } -} -impl From for cln_rpc::primitives::Feerate { - fn from(f: Feerate) -> cln_rpc::primitives::Feerate { - use feerate::Style; - match f.style.unwrap() { - Style::Slow(_) => JFeerate::Slow, - Style::Normal(_) => JFeerate::Normal, - Style::Urgent(_) => JFeerate::Urgent, - Style::Perkw(i) => JFeerate::PerKw(i), - Style::Perkb(i) => JFeerate::PerKb(i), + impl From for cln_rpc::primitives::Feerate { + fn from(f: Feerate) -> cln_rpc::primitives::Feerate { + use feerate::Style; + match f.style.unwrap() { + Style::Slow(_) => JFeerate::Slow, + Style::Normal(_) => JFeerate::Normal, + Style::Urgent(_) => JFeerate::Urgent, + Style::Perkw(i) => JFeerate::PerKw(i), + Style::Perkb(i) => JFeerate::PerKb(i), + } } } -} -impl From for JOutputDesc { - fn from(od: OutputDesc) -> JOutputDesc { - JOutputDesc { - address: od.address, - amount: od.amount.unwrap().into(), + impl From for Feerate { + fn from(f: cln_rpc::primitives::Feerate) -> Feerate { + use feerate::Style; + let style = Some(match f { + JFeerate::Slow => Style::Slow(true), + JFeerate::Normal => Style::Normal(true), + JFeerate::Urgent => Style::Urgent(true), + JFeerate::PerKb(i) => Style::Perkb(i), + JFeerate::PerKw(i) => Style::Perkw(i), + }); + Self { style } } } -} -impl From for AmountOrAll { - fn from(a: JAmountOrAll) -> Self { - match a { - JAmountOrAll::Amount(a) => AmountOrAll { - value: Some(amount_or_all::Value::Amount(a.into())), - }, - JAmountOrAll::All => AmountOrAll { - value: Some(amount_or_all::Value::All(true)), - }, + impl From for JOutputDesc { + fn from(od: OutputDesc) -> JOutputDesc { + JOutputDesc { + address: od.address, + amount: od.amount.unwrap().into(), + } } } -} -impl From for JAmountOrAll { - fn from(a: AmountOrAll) -> Self { - match a.value { - Some(amount_or_all::Value::Amount(a)) => JAmountOrAll::Amount(a.into()), - Some(amount_or_all::Value::All(_)) => JAmountOrAll::All, - None => panic!("AmountOrAll is neither amount nor all: {:?}", a), + impl From for OutputDesc { + fn from(od: JOutputDesc) -> Self { + Self { + address: od.address, + amount: Some(od.amount.into()), + } } } -} -impl From for AmountOrAny { - fn from(a: JAmountOrAny) -> Self { - match a { - JAmountOrAny::Amount(a) => AmountOrAny { - value: Some(amount_or_any::Value::Amount(a.into())), - }, - JAmountOrAny::Any => AmountOrAny { - value: Some(amount_or_any::Value::Any(true)), - }, + impl From for AmountOrAll { + fn from(a: JAmountOrAll) -> Self { + match a { + JAmountOrAll::Amount(a) => AmountOrAll { + value: Some(amount_or_all::Value::Amount(a.into())), + }, + JAmountOrAll::All => AmountOrAll { + value: Some(amount_or_all::Value::All(true)), + }, + } } } -} -impl From for JAmountOrAny { - fn from(a: AmountOrAny) -> Self { - match a.value { - Some(amount_or_any::Value::Amount(a)) => JAmountOrAny::Amount(a.into()), - Some(amount_or_any::Value::Any(_)) => JAmountOrAny::Any, - None => panic!("AmountOrAll is neither amount nor any: {:?}", a), + + impl From for JAmountOrAll { + fn from(a: AmountOrAll) -> Self { + match a.value { + Some(amount_or_all::Value::Amount(a)) => JAmountOrAll::Amount(a.into()), + Some(amount_or_all::Value::All(_)) => JAmountOrAll::All, + None => panic!("AmountOrAll is neither amount nor all: {:?}", a), + } } } -} -impl From for cln_rpc::primitives::Routehop { - fn from(c: RouteHop) -> Self { - Self { - id: cln_rpc::primitives::PublicKey::from_slice(&c.id).unwrap(), - scid: cln_rpc::primitives::ShortChannelId::from_str(&c.short_channel_id).unwrap(), - feebase: c.feebase.unwrap().into(), - feeprop: c.feeprop, - expirydelta: c.expirydelta as u16, + + impl From for AmountOrAny { + fn from(a: JAmountOrAny) -> Self { + match a { + JAmountOrAny::Amount(a) => AmountOrAny { + value: Some(amount_or_any::Value::Amount(a.into())), + }, + JAmountOrAny::Any => AmountOrAny { + value: Some(amount_or_any::Value::Any(true)), + }, + } + } + } + impl From for JAmountOrAny { + fn from(a: AmountOrAny) -> Self { + match a.value { + Some(amount_or_any::Value::Amount(a)) => JAmountOrAny::Amount(a.into()), + Some(amount_or_any::Value::Any(_)) => JAmountOrAny::Any, + None => panic!("AmountOrAll is neither amount nor any: {:?}", a), + } + } + } + impl From for cln_rpc::primitives::Routehop { + fn from(c: RouteHop) -> Self { + Self { + id: cln_rpc::primitives::PublicKey::from_slice(&c.id).unwrap(), + scid: cln_rpc::primitives::ShortChannelId::from_str(&c.short_channel_id).unwrap(), + feebase: c.feebase.unwrap().into(), + feeprop: c.feeprop, + expirydelta: c.expirydelta as u16, + } } } -} -impl From for cln_rpc::primitives::Routehint { - fn from(c: Routehint) -> Self { - Self { - hops: c.hops.into_iter().map(|h| h.into()).collect(), + impl From for cln_rpc::primitives::Routehint { + fn from(c: Routehint) -> Self { + Self { + hops: c.hops.into_iter().map(|h| h.into()).collect(), + } } } -} -impl From for cln_rpc::primitives::RoutehintList { - fn from(c: RoutehintList) -> Self { - Self { - hints: c.hints.into_iter().map(|h| h.into()).collect(), + impl From for cln_rpc::primitives::RoutehintList { + fn from(c: RoutehintList) -> Self { + Self { + hints: c.hints.into_iter().map(|h| h.into()).collect(), + } + } + } + + impl From for RouteHop { + fn from(c: cln_rpc::primitives::Routehop) -> Self { + Self { + id: c.id.serialize().to_vec(), + feebase: Some(c.feebase.into()), + feeprop: c.feeprop, + expirydelta: c.expirydelta as u32, + short_channel_id: c.scid.to_string(), + } } } -} -impl From for cln_rpc::primitives::TlvStream { - fn from(s: TlvStream) -> Self { - Self { - entries: s.entries.into_iter().map(|e| e.into()).collect(), + impl From for Routehint { + fn from(c: cln_rpc::primitives::Routehint) -> Self { + Self { + hops: c.hops.into_iter().map(|h| h.into()).collect(), + } } } -} -impl From for cln_rpc::primitives::TlvEntry { - fn from(e: TlvEntry) -> Self { - Self { - typ: e.r#type, - value: e.value, + impl From for RoutehintList { + fn from(c: cln_rpc::primitives::RoutehintList) -> Self { + Self { + hints: c.hints.into_iter().map(|e| e.into()).collect(), + } } } -} -#[cfg(test)] -mod test { - use super::*; - use serde_json::json; + impl From for cln_rpc::primitives::TlvStream { + fn from(s: TlvStream) -> Self { + Self { + entries: s.entries.into_iter().map(|e| e.into()).collect(), + } + } + } + + impl From for cln_rpc::primitives::TlvEntry { + fn from(e: TlvEntry) -> Self { + Self { + typ: e.r#type, + value: e.value, + } + } + } + + impl From for TlvStream { + fn from(s: cln_rpc::primitives::TlvStream) -> Self { + Self { + entries: s.entries.into_iter().map(|e| e.into()).collect(), + } + } + } - #[test] - fn test_listpeers() { - let j: serde_json::Value = json!({ - "peers": [ - { - "id": "0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518", - "connected": true, - "netaddr": [ - "127.0.0.1:39152" - ], - "features": "8808226aa2", - "channels": [ + impl From for TlvEntry { + fn from(e: cln_rpc::primitives::TlvEntry) -> Self { + Self { + r#type: e.typ, + value: e.value, + } + } + } + + #[cfg(test)] + mod test { + use super::*; + use serde_json::json; + + #[test] + fn test_listpeers() { + let j: serde_json::Value = json!({ + "peers": [ { - "state": "CHANNELD_NORMAL", - "scratch_txid": "fd4659658d235c20c81f96f7bc867c17abbfd20fcdd46c27eaad74ea52eaee90", - "last_tx_fee_msat": "14257000msat", - "feerate": { - "perkw": 11000, - "perkb": 44000 - }, - "owner": "channeld", - "short_channel_id": "103x2x1", - "direction": 0, - "channel_id": "44b77a6d66ca54f0c365c84b13a95fbde462415a0549228baa25ee1bb1dfef66", - "funding_txid": "67efdfb11bee25aa8b2249055a4162e4bd5fa9134bc865c3f054ca666d7ab744", - "funding_outnum": 1, - "close_to_addr": "bcrt1q9tc6q49l6wrrtp8ul45rj92hsleehwwxty32zu", - "close_to": "00142af1a054bfd3863584fcfd6839155787f39bb9c6", - "private": false, - "opener": "remote", - "features": [ - "option_static_remotekey", - "option_anchor_outputs" - ], - "funding": { - "local_msat": "0msat", - "remote_msat": "1000000000msat", - "pushed_msat": "0msat", - "local_funds_msat": "0msat", - "remote_funds_msat": "0msat" - }, - "msatoshi_to_us": 0, - "to_us_msat": "0msat", - "msatoshi_to_us_min": 0, - "min_to_us_msat": "0msat", - "msatoshi_to_us_max": 0, - "max_to_us_msat": "0msat", - "msatoshi_total": 1000000000, - "total_msat": "1000000000msat", - "fee_base_msat": "1msat", - "fee_proportional_millionths": 10, - "dust_limit_satoshis": 546, - "dust_limit_msat": "546000msat", - "max_total_htlc_in_msat": "18446744073709551615msat", - "their_channel_reserve_satoshis": 10000, - "their_reserve_msat": "10000000msat", - "our_channel_reserve_satoshis": 10000, - "our_reserve_msat": "10000000msat", - "spendable_msatoshi": 0, - "spendable_msat": "0msat", - "receivable_msatoshi": 853257998, - "receivable_msat": "853257998msat", - "htlc_minimum_msat": 0, - "minimum_htlc_in_msat": "0msat", - "their_to_self_delay": 5, - "our_to_self_delay": 5, - "max_accepted_htlcs": 483, - "state_changes": [ - { - "timestamp": "2022-03-25T13:57:33.322Z", - "old_state": "CHANNELD_AWAITING_LOCKIN", - "new_state": "CHANNELD_NORMAL", - "cause": "remote", - "message": "Lockin complete" - } - ], - "status": [ - "CHANNELD_NORMAL:Funding transaction locked. Channel announced." + "id": "0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518", + "connected": true, + "netaddr": [ + "127.0.0.1:39152" ], - "in_payments_offered": 1, - "in_msatoshi_offered": 100002002, - "in_offered_msat": "100002002msat", - "in_payments_fulfilled": 0, - "in_msatoshi_fulfilled": 0, - "in_fulfilled_msat": "0msat", - "out_payments_offered": 0, - "out_msatoshi_offered": 0, - "out_offered_msat": "0msat", - "out_payments_fulfilled": 0, - "out_msatoshi_fulfilled": 0, - "out_fulfilled_msat": "0msat", - "htlcs": [ + "features": "8808226aa2", + "num_channels": 0, + "channels": [ { - "direction": "in", - "id": 0, - "msatoshi": 100002002, - "amount_msat": "100002002msat", - "expiry": 131, - "payment_hash": "d17a42c4f7f49648064a0ce7ce848bd92c4c50f24d35fe5c3d1f3a7a9bf474b2", - "state": "RCVD_ADD_ACK_REVOCATION" + "state": "CHANNELD_NORMAL", + "scratch_txid": "fd4659658d235c20c81f96f7bc867c17abbfd20fcdd46c27eaad74ea52eaee90", + "last_tx_fee_msat": "14257000msat", + "feerate": { + "perkw": 11000, + "perkb": 44000 + }, + "owner": "channeld", + "short_channel_id": "103x2x1", + "direction": 0, + "channel_id": "44b77a6d66ca54f0c365c84b13a95fbde462415a0549228baa25ee1bb1dfef66", + "funding_txid": "67efdfb11bee25aa8b2249055a4162e4bd5fa9134bc865c3f054ca666d7ab744", + "funding_outnum": 1, + "close_to_addr": "bcrt1q9tc6q49l6wrrtp8ul45rj92hsleehwwxty32zu", + "close_to": "00142af1a054bfd3863584fcfd6839155787f39bb9c6", + "private": false, + "opener": "remote", + "features": [ + "option_static_remotekey", + "option_anchor_outputs" + ], + "funding": { + "local_msat": "0msat", + "remote_msat": "1000000000msat", + "pushed_msat": "0msat", + "local_funds_msat": "0msat", + "remote_funds_msat": "0msat" + }, + "msatoshi_to_us": 0, + "to_us_msat": "0msat", + "msatoshi_to_us_min": 0, + "min_to_us_msat": "0msat", + "msatoshi_to_us_max": 0, + "max_to_us_msat": "0msat", + "msatoshi_total": 1000000000, + "total_msat": "1000000000msat", + "fee_base_msat": "1msat", + "fee_proportional_millionths": 10, + "dust_limit_satoshis": 546, + "dust_limit_msat": "546000msat", + "max_total_htlc_in_msat": "18446744073709551615msat", + "their_channel_reserve_satoshis": 10000, + "their_reserve_msat": "10000000msat", + "our_channel_reserve_satoshis": 10000, + "our_reserve_msat": "10000000msat", + "spendable_msatoshi": 0, + "spendable_msat": "0msat", + "receivable_msatoshi": 853257998, + "receivable_msat": "853257998msat", + "htlc_minimum_msat": 0, + "minimum_htlc_in_msat": "0msat", + "their_to_self_delay": 5, + "our_to_self_delay": 5, + "max_accepted_htlcs": 483, + "state_changes": [ + { + "timestamp": "2022-03-25T13:57:33.322Z", + "old_state": "CHANNELD_AWAITING_LOCKIN", + "new_state": "CHANNELD_NORMAL", + "cause": "remote", + "message": "Lockin complete" + } + ], + "status": [ + "CHANNELD_NORMAL:Funding transaction locked. Channel announced." + ], + "in_payments_offered": 1, + "in_msatoshi_offered": 100002002, + "in_offered_msat": "100002002msat", + "in_payments_fulfilled": 0, + "in_msatoshi_fulfilled": 0, + "in_fulfilled_msat": "0msat", + "out_payments_offered": 0, + "out_msatoshi_offered": 0, + "out_offered_msat": "0msat", + "out_payments_fulfilled": 0, + "out_msatoshi_fulfilled": 0, + "out_fulfilled_msat": "0msat", + "htlcs": [ + { + "direction": "in", + "id": 0, + "msatoshi": 100002002, + "amount_msat": "100002002msat", + "expiry": 131, + "payment_hash": "d17a42c4f7f49648064a0ce7ce848bd92c4c50f24d35fe5c3d1f3a7a9bf474b2", + "state": "RCVD_ADD_ACK_REVOCATION" + } + ] } ] - } - ] - }, - { - "id": "035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d", - "connected": true, - "netaddr": [ - "127.0.0.1:38321" - ], - "features": "8808226aa2", - "channels": [ + }, { - "state": "CHANNELD_NORMAL", - "scratch_txid": "30530d3f522862773100b7600d8ea8921a5ee84df17a2317326f9aa2c4829326", - "last_tx_fee_msat": "16149000msat", - "feerate": { - "perkw": 11000, - "perkb": 44000 - }, - "owner": "channeld", - "short_channel_id": "103x1x0", - "direction": 0, - "channel_id": "006a2044fc72fa5c4a54c9fddbf208970a7b3b4fd2aaa70a96abba757c01769e", - "funding_txid": "9e76017c75baab960aa7aad24f3b7b0a9708f2dbfdc9544a5cfa72fc44206a00", - "funding_outnum": 0, - "close_to_addr": "bcrt1qhfmyce4ujce2pyugew2435tlwft6p6w4s3py6d", - "close_to": "0014ba764c66bc9632a09388cb9558d17f7257a0e9d5", - "private": false, - "opener": "local", - "features": [ - "option_static_remotekey", - "option_anchor_outputs" + "id": "035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d", + "connected": true, + "netaddr": [ + "127.0.0.1:38321" ], - "funding": { - "local_msat": "1000000000msat", - "remote_msat": "0msat", - "pushed_msat": "0msat", - "local_funds_msat": "0msat", - "remote_funds_msat": "0msat" - }, - "msatoshi_to_us": 1000000000, - "to_us_msat": "1000000000msat", - "msatoshi_to_us_min": 1000000000, - "min_to_us_msat": "1000000000msat", - "msatoshi_to_us_max": 1000000000, - "max_to_us_msat": "1000000000msat", - "msatoshi_total": 1000000000, - "total_msat": "1000000000msat", - "fee_base_msat": "1msat", - "fee_proportional_millionths": 10, - "dust_limit_satoshis": 546, - "dust_limit_msat": "546000msat", - "max_total_htlc_in_msat": "18446744073709551615msat", - "their_channel_reserve_satoshis": 10000, - "their_reserve_msat": "10000000msat", - "our_channel_reserve_satoshis": 10000, - "our_reserve_msat": "10000000msat", - "spendable_msatoshi": 749473998, - "spendable_msat": "749473998msat", - "receivable_msatoshi": 0, - "receivable_msat": "0msat", - "htlc_minimum_msat": 0, - "minimum_htlc_in_msat": "0msat", - "their_to_self_delay": 5, - "our_to_self_delay": 5, - "max_accepted_htlcs": 483, - "state_changes": [ + "features": "8808226aa2", + "num_channels": 0, + "channels": [ { - "timestamp": "2022-03-25T13:57:33.325Z", - "old_state": "CHANNELD_AWAITING_LOCKIN", - "new_state": "CHANNELD_NORMAL", - "cause": "user", - "message": "Lockin complete" - } - ], - "status": [ - "CHANNELD_NORMAL:Funding transaction locked. Channel announced." - ], - "in_payments_offered": 0, - "in_msatoshi_offered": 0, - "in_offered_msat": "0msat", - "in_payments_fulfilled": 0, - "in_msatoshi_fulfilled": 0, - "in_fulfilled_msat": "0msat", - "out_payments_offered": 2, - "out_msatoshi_offered": 200002002, - "out_offered_msat": "200002002msat", - "out_payments_fulfilled": 0, - "out_msatoshi_fulfilled": 0, - "out_fulfilled_msat": "0msat", - "htlcs": [ - { - "direction": "out", - "id": 1, - "msatoshi": 100001001, - "amount_msat": "100001001msat", - "expiry": 125, - "payment_hash": "d17a42c4f7f49648064a0ce7ce848bd92c4c50f24d35fe5c3d1f3a7a9bf474b2", - "state": "SENT_ADD_ACK_REVOCATION" - }, - { - "direction": "out", - "id": 0, - "msatoshi": 100001001, - "amount_msat": "100001001msat", - "expiry": 124, - "payment_hash": "d17a42c4f7f49648064a0ce7ce848bd92c4c50f24d35fe5c3d1f3a7a9bf474b2", - "state": "SENT_ADD_ACK_REVOCATION" + "state": "CHANNELD_NORMAL", + "scratch_txid": "30530d3f522862773100b7600d8ea8921a5ee84df17a2317326f9aa2c4829326", + "last_tx_fee_msat": "16149000msat", + "feerate": { + "perkw": 11000, + "perkb": 44000 + }, + "owner": "channeld", + "short_channel_id": "103x1x0", + "direction": 0, + "channel_id": "006a2044fc72fa5c4a54c9fddbf208970a7b3b4fd2aaa70a96abba757c01769e", + "funding_txid": "9e76017c75baab960aa7aad24f3b7b0a9708f2dbfdc9544a5cfa72fc44206a00", + "funding_outnum": 0, + "close_to_addr": "bcrt1qhfmyce4ujce2pyugew2435tlwft6p6w4s3py6d", + "close_to": "0014ba764c66bc9632a09388cb9558d17f7257a0e9d5", + "private": false, + "opener": "local", + "features": [ + "option_static_remotekey", + "option_anchor_outputs" + ], + "funding": { + "local_msat": "1000000000msat", + "remote_msat": "0msat", + "pushed_msat": "0msat", + "local_funds_msat": "0msat", + "remote_funds_msat": "0msat" + }, + "msatoshi_to_us": 1000000000, + "to_us_msat": "1000000000msat", + "msatoshi_to_us_min": 1000000000, + "min_to_us_msat": "1000000000msat", + "msatoshi_to_us_max": 1000000000, + "max_to_us_msat": "1000000000msat", + "msatoshi_total": 1000000000, + "total_msat": "1000000000msat", + "fee_base_msat": "1msat", + "fee_proportional_millionths": 10, + "dust_limit_satoshis": 546, + "dust_limit_msat": "546000msat", + "max_total_htlc_in_msat": "18446744073709551615msat", + "their_channel_reserve_satoshis": 10000, + "their_reserve_msat": "10000000msat", + "our_channel_reserve_satoshis": 10000, + "our_reserve_msat": "10000000msat", + "spendable_msatoshi": 749473998, + "spendable_msat": "749473998msat", + "receivable_msatoshi": 0, + "receivable_msat": "0msat", + "htlc_minimum_msat": 0, + "minimum_htlc_in_msat": "0msat", + "their_to_self_delay": 5, + "our_to_self_delay": 5, + "max_accepted_htlcs": 483, + "state_changes": [ + { + "timestamp": "2022-03-25T13:57:33.325Z", + "old_state": "CHANNELD_AWAITING_LOCKIN", + "new_state": "CHANNELD_NORMAL", + "cause": "user", + "message": "Lockin complete" + } + ], + "status": [ + "CHANNELD_NORMAL:Funding transaction locked. Channel announced." + ], + "in_payments_offered": 0, + "in_msatoshi_offered": 0, + "in_offered_msat": "0msat", + "in_payments_fulfilled": 0, + "in_msatoshi_fulfilled": 0, + "in_fulfilled_msat": "0msat", + "out_payments_offered": 2, + "out_msatoshi_offered": 200002002, + "out_offered_msat": "200002002msat", + "out_payments_fulfilled": 0, + "out_msatoshi_fulfilled": 0, + "out_fulfilled_msat": "0msat", + "htlcs": [ + { + "direction": "out", + "id": 1, + "msatoshi": 100001001, + "amount_msat": "100001001msat", + "expiry": 125, + "payment_hash": "d17a42c4f7f49648064a0ce7ce848bd92c4c50f24d35fe5c3d1f3a7a9bf474b2", + "state": "SENT_ADD_ACK_REVOCATION" + }, + { + "direction": "out", + "id": 0, + "msatoshi": 100001001, + "amount_msat": "100001001msat", + "expiry": 124, + "payment_hash": "d17a42c4f7f49648064a0ce7ce848bd92c4c50f24d35fe5c3d1f3a7a9bf474b2", + "state": "SENT_ADD_ACK_REVOCATION" + } + ] } ] } ] - } - ] - }); - let u: cln_rpc::model::ListpeersResponse = serde_json::from_value(j).unwrap(); - let _g: ListpeersResponse = u.into(); + }); + let u: cln_rpc::model::ListpeersResponse = serde_json::from_value(j).unwrap(); + let _g: ListpeersResponse = u.into(); + } } } diff --git a/cln-grpc/src/server.rs b/cln-grpc/src/server.rs index 7759ca0a6a3a..a93e55cc7290 100644 --- a/cln-grpc/src/server.rs +++ b/cln-grpc/src/server.rs @@ -1210,6 +1210,134 @@ async fn tx_send( } +async fn list_peer_channels( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::ListpeerchannelsRequest = req.into(); + debug!("Client asked for list_peer_channels"); + trace!("list_peer_channels request: {:?}", req); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::ListPeerChannels(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method ListPeerChannels: {:?}", e)))?; + match result { + Response::ListPeerChannels(r) => { + trace!("list_peer_channels response: {:?}", r); + Ok(tonic::Response::new(r.into())) + }, + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call ListPeerChannels", + r + ) + )), + } + +} + +async fn list_closed_channels( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::ListclosedchannelsRequest = req.into(); + debug!("Client asked for list_closed_channels"); + trace!("list_closed_channels request: {:?}", req); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::ListClosedChannels(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method ListClosedChannels: {:?}", e)))?; + match result { + Response::ListClosedChannels(r) => { + trace!("list_closed_channels response: {:?}", r); + Ok(tonic::Response::new(r.into())) + }, + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call ListClosedChannels", + r + ) + )), + } + +} + +async fn decode_pay( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::DecodepayRequest = req.into(); + debug!("Client asked for decode_pay"); + trace!("decode_pay request: {:?}", req); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::DecodePay(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method DecodePay: {:?}", e)))?; + match result { + Response::DecodePay(r) => { + trace!("decode_pay response: {:?}", r); + Ok(tonic::Response::new(r.into())) + }, + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call DecodePay", + r + ) + )), + } + +} + +async fn decode( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::DecodeRequest = req.into(); + debug!("Client asked for decode"); + trace!("decode request: {:?}", req); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::Decode(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method Decode: {:?}", e)))?; + match result { + Response::Decode(r) => { + trace!("decode response: {:?}", r); + Ok(tonic::Response::new(r.into())) + }, + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call Decode", + r + ) + )), + } + +} + async fn disconnect( &self, request: tonic::Request, @@ -1434,6 +1562,38 @@ async fn ping( } +async fn send_custom_msg( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::SendcustommsgRequest = req.into(); + debug!("Client asked for send_custom_msg"); + trace!("send_custom_msg request: {:?}", req); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::SendCustomMsg(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method SendCustomMsg: {:?}", e)))?; + match result { + Response::SendCustomMsg(r) => { + trace!("send_custom_msg response: {:?}", r); + Ok(tonic::Response::new(r.into())) + }, + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call SendCustomMsg", + r + ) + )), + } + +} + async fn set_channel( &self, request: tonic::Request, @@ -1466,6 +1626,38 @@ async fn set_channel( } +async fn sign_invoice( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::SigninvoiceRequest = req.into(); + debug!("Client asked for sign_invoice"); + trace!("sign_invoice request: {:?}", req); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::SignInvoice(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method SignInvoice: {:?}", e)))?; + match result { + Response::SignInvoice(r) => { + trace!("sign_invoice response: {:?}", r); + Ok(tonic::Response::new(r.into())) + }, + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call SignInvoice", + r + ) + )), + } + +} + async fn sign_message( &self, request: tonic::Request, @@ -1530,4 +1722,68 @@ async fn stop( } +async fn pre_approve_keysend( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::PreapprovekeysendRequest = req.into(); + debug!("Client asked for pre_approve_keysend"); + trace!("pre_approve_keysend request: {:?}", req); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::PreApproveKeysend(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method PreApproveKeysend: {:?}", e)))?; + match result { + Response::PreApproveKeysend(r) => { + trace!("pre_approve_keysend response: {:?}", r); + Ok(tonic::Response::new(r.into())) + }, + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call PreApproveKeysend", + r + ) + )), + } + +} + +async fn pre_approve_invoice( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::PreapproveinvoiceRequest = req.into(); + debug!("Client asked for pre_approve_invoice"); + trace!("pre_approve_invoice request: {:?}", req); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::PreApproveInvoice(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method PreApproveInvoice: {:?}", e)))?; + match result { + Response::PreApproveInvoice(r) => { + trace!("pre_approve_invoice response: {:?}", r); + Ok(tonic::Response::new(r.into())) + }, + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call PreApproveInvoice", + r + ) + )), + } + +} + } diff --git a/cln-grpc/src/test.rs b/cln-grpc/src/test.rs index 4aa33c472dfa..33ee185c296b 100644 --- a/cln-grpc/src/test.rs +++ b/cln-grpc/src/test.rs @@ -12,6 +12,7 @@ fn test_listpeers() { "127.0.0.1:39152" ], "features": "8808226aa2", + "num_channels": 0, "channels": [ { "state": "CHANNELD_NORMAL", @@ -113,6 +114,7 @@ fn test_listpeers() { "127.0.0.1:38321" ], "features": "8808226aa2", + "num_channels": 0, "channels": [ { "state": "CHANNELD_NORMAL", @@ -218,8 +220,13 @@ fn test_listpeers() { } ] }); - let u: cln_rpc::model::ListpeersResponse = serde_json::from_value(j).unwrap(); - let _: ListpeersResponse = u.into(); + let u: cln_rpc::model::ListpeersResponse = serde_json::from_value(j.clone()).unwrap(); + let _l: ListpeersResponse = u.into(); + //let u2: cln_rpc::model::ListpeersResponse = l.into(); + //let j2 = serde_json::to_value(u2).unwrap(); + println!("{}", j); + //println!("{}", j2); + // assert_eq!(j, j2); // TODO, still some differences to fix } #[test] @@ -237,11 +244,13 @@ fn test_getinfo() { "version": "v0.10.2-509-ged26651-modded", "blockheight": 103, "network": "regtest", - "msatoshi_fees_collected": 0, "fees_collected_msat": "0msat", "lightning-dir": "/tmp/ltests-20irp76f/test_pay_variants_1/lightning-1/regtest", "our_features": {"init": "8808226aa2", "node": "80008808226aa2", "channel": "", "invoice": "024200"}}); - let u: cln_rpc::model::GetinfoResponse = serde_json::from_value(j).unwrap(); + let u: cln_rpc::model::GetinfoResponse = serde_json::from_value(j.clone()).unwrap(); let _g: GetinfoResponse = u.into(); + //let u2: cln_rpc::model::GetinfoResponse = g.into(); + //let j2 = serde_json::to_value(u2).unwrap(); + //assert_eq!(j, j2); } #[test] @@ -301,6 +310,11 @@ fn test_keysend() { "status": "complete" }"#; let u: cln_rpc::model::KeysendResponse = serde_json::from_str(j).unwrap(); - let g: KeysendResponse = u.into(); + let g: KeysendResponse = u.clone().into(); println!("{:?}", g); + + let v: serde_json::Value = serde_json::to_value(u.clone()).unwrap(); + let g: cln_rpc::model::KeysendResponse = u.into(); + let v2 = serde_json::to_value(g).unwrap(); + assert_eq!(v, v2); } diff --git a/cln-rpc/Cargo.toml b/cln-rpc/Cargo.toml index b1b3865d2291..2462816f5c55 100644 --- a/cln-rpc/Cargo.toml +++ b/cln-rpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cln-rpc" -version = "0.1.2" +version = "0.1.3" edition = "2021" license = "MIT" description = "An async RPC client for Core Lightning." diff --git a/cln-rpc/Makefile b/cln-rpc/Makefile index 339894ae1341..eff4fdbd41fc 100644 --- a/cln-rpc/Makefile +++ b/cln-rpc/Makefile @@ -16,5 +16,8 @@ target/${RUST_PROFILE}/examples/cln-rpc-getinfo: $(shell find cln-rpc -name *.rs target/${RUST_PROFILE}/examples/cln-plugin-startup: $(shell find cln-rpc -name *.rs) cargo build ${CARGO_OPTS} --example cln-plugin-startup +target/${RUST_PROFILE}/examples/cln-plugin-reentrant: $(shell find plugins/examples -name *.rs) + cargo build ${CARGO_OPTS} --example cln-plugin-reentrant + cln-rpc-all: ${CLN_RPC_GEN_ALL} ${CLN_RPC_EXAMPLES} diff --git a/cln-rpc/src/model.rs b/cln-rpc/src/model.rs index bf4faeba21e1..7c25f20ff57a 100644 --- a/cln-rpc/src/model.rs +++ b/cln-rpc/src/model.rs @@ -53,6 +53,10 @@ pub enum Request { TxDiscard(requests::TxdiscardRequest), TxPrepare(requests::TxprepareRequest), TxSend(requests::TxsendRequest), + ListPeerChannels(requests::ListpeerchannelsRequest), + ListClosedChannels(requests::ListclosedchannelsRequest), + DecodePay(requests::DecodepayRequest), + Decode(requests::DecodeRequest), Disconnect(requests::DisconnectRequest), Feerates(requests::FeeratesRequest), FundChannel(requests::FundchannelRequest), @@ -60,9 +64,13 @@ pub enum Request { ListForwards(requests::ListforwardsRequest), ListPays(requests::ListpaysRequest), Ping(requests::PingRequest), + SendCustomMsg(requests::SendcustommsgRequest), SetChannel(requests::SetchannelRequest), + SignInvoice(requests::SigninvoiceRequest), SignMessage(requests::SignmessageRequest), Stop(requests::StopRequest), + PreApproveKeysend(requests::PreapprovekeysendRequest), + PreApproveInvoice(requests::PreapproveinvoiceRequest), } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -106,6 +114,10 @@ pub enum Response { TxDiscard(responses::TxdiscardResponse), TxPrepare(responses::TxprepareResponse), TxSend(responses::TxsendResponse), + ListPeerChannels(responses::ListpeerchannelsResponse), + ListClosedChannels(responses::ListclosedchannelsResponse), + DecodePay(responses::DecodepayResponse), + Decode(responses::DecodeResponse), Disconnect(responses::DisconnectResponse), Feerates(responses::FeeratesResponse), FundChannel(responses::FundchannelResponse), @@ -113,9 +125,13 @@ pub enum Response { ListForwards(responses::ListforwardsResponse), ListPays(responses::ListpaysResponse), Ping(responses::PingResponse), + SendCustomMsg(responses::SendcustommsgResponse), SetChannel(responses::SetchannelResponse), + SignInvoice(responses::SigninvoiceResponse), SignMessage(responses::SignmessageResponse), Stop(responses::StopResponse), + PreApproveKeysend(responses::PreapprovekeysendResponse), + PreApproveInvoice(responses::PreapproveinvoiceResponse), } @@ -514,8 +530,6 @@ pub mod requests { #[serde(skip_serializing_if = "Option::is_none")] pub preimage: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub exposeprivatechannels: Option, - #[serde(skip_serializing_if = "Option::is_none")] pub cltv: Option, #[serde(skip_serializing_if = "Option::is_none")] pub deschashonly: Option, @@ -998,6 +1012,70 @@ pub mod requests { type Response = super::responses::TxsendResponse; } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListpeerchannelsRequest { + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, + } + + impl From for Request { + fn from(r: ListpeerchannelsRequest) -> Self { + Request::ListPeerChannels(r) + } + } + + impl IntoRequest for ListpeerchannelsRequest { + type Response = super::responses::ListpeerchannelsResponse; + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListclosedchannelsRequest { + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, + } + + impl From for Request { + fn from(r: ListclosedchannelsRequest) -> Self { + Request::ListClosedChannels(r) + } + } + + impl IntoRequest for ListclosedchannelsRequest { + type Response = super::responses::ListclosedchannelsResponse; + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct DecodepayRequest { + pub bolt11: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + } + + impl From for Request { + fn from(r: DecodepayRequest) -> Self { + Request::DecodePay(r) + } + } + + impl IntoRequest for DecodepayRequest { + type Response = super::responses::DecodepayResponse; + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct DecodeRequest { + pub string: String, + } + + impl From for Request { + fn from(r: DecodeRequest) -> Self { + Request::Decode(r) + } + } + + impl IntoRequest for DecodeRequest { + type Response = super::responses::DecodeResponse; + } + #[derive(Clone, Debug, Deserialize, Serialize)] pub struct DisconnectRequest { pub id: PublicKey, @@ -1216,6 +1294,22 @@ pub mod requests { type Response = super::responses::PingResponse; } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct SendcustommsgRequest { + pub node_id: PublicKey, + pub msg: String, + } + + impl From for Request { + fn from(r: SendcustommsgRequest) -> Self { + Request::SendCustomMsg(r) + } + } + + impl IntoRequest for SendcustommsgRequest { + type Response = super::responses::SendcustommsgResponse; + } + #[derive(Clone, Debug, Deserialize, Serialize)] pub struct SetchannelRequest { pub id: String, @@ -1241,6 +1335,21 @@ pub mod requests { type Response = super::responses::SetchannelResponse; } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct SigninvoiceRequest { + pub invstring: String, + } + + impl From for Request { + fn from(r: SigninvoiceRequest) -> Self { + Request::SignInvoice(r) + } + } + + impl IntoRequest for SigninvoiceRequest { + type Response = super::responses::SigninvoiceResponse; + } + #[derive(Clone, Debug, Deserialize, Serialize)] pub struct SignmessageRequest { pub message: String, @@ -1270,6 +1379,42 @@ pub mod requests { type Response = super::responses::StopResponse; } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct PreapprovekeysendRequest { + #[serde(skip_serializing_if = "Option::is_none")] + pub destination: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub payment_hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub amount_msat: Option, + } + + impl From for Request { + fn from(r: PreapprovekeysendRequest) -> Self { + Request::PreApproveKeysend(r) + } + } + + impl IntoRequest for PreapprovekeysendRequest { + type Response = super::responses::PreapprovekeysendResponse; + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct PreapproveinvoiceRequest { + #[serde(skip_serializing_if = "Option::is_none")] + pub bolt11: Option, + } + + impl From for Request { + fn from(r: PreapproveinvoiceRequest) -> Self { + Request::PreApproveInvoice(r) + } + } + + impl IntoRequest for PreapproveinvoiceRequest { + type Response = super::responses::PreapproveinvoiceResponse; + } + } @@ -1288,7 +1433,7 @@ pub mod responses { pub invoice: String, } - /// Type of connection + /// Type of connection (until 23.08, `websocket` was also allowed) #[derive(Copy, Clone, Debug, Deserialize, Serialize)] pub enum GetinfoAddressType { #[serde(rename = "dns")] @@ -1301,8 +1446,6 @@ pub mod responses { TORV2, #[serde(rename = "torv3")] TORV3, - #[serde(rename = "websocket")] - WEBSOCKET, } impl TryFrom for GetinfoAddressType { @@ -1314,7 +1457,6 @@ pub mod responses { 2 => Ok(GetinfoAddressType::IPV6), 3 => Ok(GetinfoAddressType::TORV2), 4 => Ok(GetinfoAddressType::TORV3), - 5 => Ok(GetinfoAddressType::WEBSOCKET), o => Err(anyhow::anyhow!("Unknown variant {} for enum GetinfoAddressType", o)), } } @@ -1334,6 +1476,8 @@ pub mod responses { pub enum GetinfoBindingType { #[serde(rename = "local socket")] LOCAL_SOCKET, + #[serde(rename = "websocket")] + WEBSOCKET, #[serde(rename = "ipv4")] IPV4, #[serde(rename = "ipv6")] @@ -1349,10 +1493,11 @@ pub mod responses { fn try_from(c: i32) -> Result { match c { 0 => Ok(GetinfoBindingType::LOCAL_SOCKET), - 1 => Ok(GetinfoBindingType::IPV4), - 2 => Ok(GetinfoBindingType::IPV6), - 3 => Ok(GetinfoBindingType::TORV2), - 4 => Ok(GetinfoBindingType::TORV3), + 1 => Ok(GetinfoBindingType::WEBSOCKET), + 2 => Ok(GetinfoBindingType::IPV4), + 3 => Ok(GetinfoBindingType::IPV6), + 4 => Ok(GetinfoBindingType::TORV2), + 5 => Ok(GetinfoBindingType::TORV3), o => Err(anyhow::anyhow!("Unknown variant {} for enum GetinfoBindingType", o)), } } @@ -1373,7 +1518,8 @@ pub mod responses { #[derive(Clone, Debug, Deserialize, Serialize)] pub struct GetinfoResponse { pub id: PublicKey, - pub alias: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub alias: Option, pub color: String, pub num_peers: u32, pub num_pending_channels: u32, @@ -1386,11 +1532,9 @@ pub mod responses { pub our_features: Option, pub blockheight: u32, pub network: String, - #[deprecated] - #[serde(skip_serializing_if = "Option::is_none")] - pub msatoshi_fees_collected: Option, pub fees_collected_msat: Amount, - pub address: Vec, + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub address: Option>, #[serde(skip_serializing_if = "crate::is_none_or_empty")] pub binding: Option>, #[serde(skip_serializing_if = "Option::is_none")] @@ -1526,12 +1670,6 @@ pub mod responses { #[derive(Clone, Debug, Deserialize, Serialize)] pub struct ListpeersPeersChannelsFunding { - #[deprecated] - #[serde(skip_serializing_if = "Option::is_none")] - pub local_msat: Option, - #[deprecated] - #[serde(skip_serializing_if = "Option::is_none")] - pub remote_msat: Option, #[serde(skip_serializing_if = "Option::is_none")] pub pushed_msat: Option, pub local_funds_msat: Amount, @@ -1550,18 +1688,6 @@ pub mod responses { pub remote: Option, } - #[derive(Clone, Debug, Deserialize, Serialize)] - pub struct ListpeersPeersChannelsState_changes { - pub timestamp: String, - // Path `ListPeers.peers[].channels[].state_changes[].old_state` - pub old_state: ChannelState, - // Path `ListPeers.peers[].channels[].state_changes[].new_state` - pub new_state: ChannelState, - // Path `ListPeers.peers[].channels[].state_changes[].cause` - pub cause: ChannelStateChangeCause, - pub message: String, - } - /// Whether it came from peer, or is going to peer #[derive(Copy, Clone, Debug, Deserialize, Serialize)] pub enum ListpeersPeersChannelsHtlcsDirection { @@ -1593,6 +1719,8 @@ pub mod responses { pub local_trimmed: Option, #[serde(skip_serializing_if = "Option::is_none")] pub status: Option, + // Path `ListPeers.peers[].channels[].htlcs[].state` + pub state: HtlcState, } #[derive(Clone, Debug, Deserialize, Serialize)] @@ -1673,8 +1801,6 @@ pub mod responses { #[serde(skip_serializing_if = "Option::is_none")] pub alias: Option, #[serde(skip_serializing_if = "crate::is_none_or_empty")] - pub state_changes: Option>, - #[serde(skip_serializing_if = "crate::is_none_or_empty")] pub status: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub in_payments_offered: Option, @@ -1702,6 +1828,8 @@ pub mod responses { pub struct ListpeersPeers { pub id: PublicKey, pub connected: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub num_channels: Option, #[serde(skip_serializing_if = "crate::is_none_or_empty")] pub log: Option>, #[deprecated] @@ -1783,6 +1911,8 @@ pub mod responses { // Path `ListFunds.channels[].state` pub state: ChannelState, #[serde(skip_serializing_if = "Option::is_none")] + pub channel_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub short_channel_id: Option, } @@ -2513,119 +2643,19 @@ pub mod responses { } } - /// the purpose of this input (*EXPERIMENTAL_FEATURES* only) - #[derive(Copy, Clone, Debug, Deserialize, Serialize)] - pub enum ListtransactionsTransactionsInputsType { - #[serde(rename = "theirs")] - THEIRS, - #[serde(rename = "deposit")] - DEPOSIT, - #[serde(rename = "withdraw")] - WITHDRAW, - #[serde(rename = "channel_funding")] - CHANNEL_FUNDING, - #[serde(rename = "channel_mutual_close")] - CHANNEL_MUTUAL_CLOSE, - #[serde(rename = "channel_unilateral_close")] - CHANNEL_UNILATERAL_CLOSE, - #[serde(rename = "channel_sweep")] - CHANNEL_SWEEP, - #[serde(rename = "channel_htlc_success")] - CHANNEL_HTLC_SUCCESS, - #[serde(rename = "channel_htlc_timeout")] - CHANNEL_HTLC_TIMEOUT, - #[serde(rename = "channel_penalty")] - CHANNEL_PENALTY, - #[serde(rename = "channel_unilateral_cheat")] - CHANNEL_UNILATERAL_CHEAT, - } - - impl TryFrom for ListtransactionsTransactionsInputsType { - type Error = anyhow::Error; - fn try_from(c: i32) -> Result { - match c { - 0 => Ok(ListtransactionsTransactionsInputsType::THEIRS), - 1 => Ok(ListtransactionsTransactionsInputsType::DEPOSIT), - 2 => Ok(ListtransactionsTransactionsInputsType::WITHDRAW), - 3 => Ok(ListtransactionsTransactionsInputsType::CHANNEL_FUNDING), - 4 => Ok(ListtransactionsTransactionsInputsType::CHANNEL_MUTUAL_CLOSE), - 5 => Ok(ListtransactionsTransactionsInputsType::CHANNEL_UNILATERAL_CLOSE), - 6 => Ok(ListtransactionsTransactionsInputsType::CHANNEL_SWEEP), - 7 => Ok(ListtransactionsTransactionsInputsType::CHANNEL_HTLC_SUCCESS), - 8 => Ok(ListtransactionsTransactionsInputsType::CHANNEL_HTLC_TIMEOUT), - 9 => Ok(ListtransactionsTransactionsInputsType::CHANNEL_PENALTY), - 10 => Ok(ListtransactionsTransactionsInputsType::CHANNEL_UNILATERAL_CHEAT), - o => Err(anyhow::anyhow!("Unknown variant {} for enum ListtransactionsTransactionsInputsType", o)), - } - } - } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct ListtransactionsTransactionsInputs { pub txid: String, pub index: u32, pub sequence: u32, - #[serde(skip_serializing_if = "Option::is_none")] - pub item_type: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub channel: Option, } - /// the purpose of this output (*EXPERIMENTAL_FEATURES* only) - #[derive(Copy, Clone, Debug, Deserialize, Serialize)] - pub enum ListtransactionsTransactionsOutputsType { - #[serde(rename = "theirs")] - THEIRS, - #[serde(rename = "deposit")] - DEPOSIT, - #[serde(rename = "withdraw")] - WITHDRAW, - #[serde(rename = "channel_funding")] - CHANNEL_FUNDING, - #[serde(rename = "channel_mutual_close")] - CHANNEL_MUTUAL_CLOSE, - #[serde(rename = "channel_unilateral_close")] - CHANNEL_UNILATERAL_CLOSE, - #[serde(rename = "channel_sweep")] - CHANNEL_SWEEP, - #[serde(rename = "channel_htlc_success")] - CHANNEL_HTLC_SUCCESS, - #[serde(rename = "channel_htlc_timeout")] - CHANNEL_HTLC_TIMEOUT, - #[serde(rename = "channel_penalty")] - CHANNEL_PENALTY, - #[serde(rename = "channel_unilateral_cheat")] - CHANNEL_UNILATERAL_CHEAT, - } - - impl TryFrom for ListtransactionsTransactionsOutputsType { - type Error = anyhow::Error; - fn try_from(c: i32) -> Result { - match c { - 0 => Ok(ListtransactionsTransactionsOutputsType::THEIRS), - 1 => Ok(ListtransactionsTransactionsOutputsType::DEPOSIT), - 2 => Ok(ListtransactionsTransactionsOutputsType::WITHDRAW), - 3 => Ok(ListtransactionsTransactionsOutputsType::CHANNEL_FUNDING), - 4 => Ok(ListtransactionsTransactionsOutputsType::CHANNEL_MUTUAL_CLOSE), - 5 => Ok(ListtransactionsTransactionsOutputsType::CHANNEL_UNILATERAL_CLOSE), - 6 => Ok(ListtransactionsTransactionsOutputsType::CHANNEL_SWEEP), - 7 => Ok(ListtransactionsTransactionsOutputsType::CHANNEL_HTLC_SUCCESS), - 8 => Ok(ListtransactionsTransactionsOutputsType::CHANNEL_HTLC_TIMEOUT), - 9 => Ok(ListtransactionsTransactionsOutputsType::CHANNEL_PENALTY), - 10 => Ok(ListtransactionsTransactionsOutputsType::CHANNEL_UNILATERAL_CHEAT), - o => Err(anyhow::anyhow!("Unknown variant {} for enum ListtransactionsTransactionsOutputsType", o)), - } - } - } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct ListtransactionsTransactionsOutputs { pub index: u32, pub amount_msat: Amount, #[serde(rename = "scriptPubKey")] pub script_pub_key: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub item_type: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub channel: Option, } #[derive(Clone, Debug, Deserialize, Serialize)] @@ -2705,7 +2735,7 @@ pub mod responses { } } - /// Type of connection + /// Type of connection (until 23.08, `websocket` was also allowed) #[derive(Copy, Clone, Debug, Deserialize, Serialize)] pub enum ListnodesNodesAddressesType { #[serde(rename = "dns")] @@ -2718,8 +2748,6 @@ pub mod responses { TORV2, #[serde(rename = "torv3")] TORV3, - #[serde(rename = "websocket")] - WEBSOCKET, } impl TryFrom for ListnodesNodesAddressesType { @@ -2731,7 +2759,6 @@ pub mod responses { 2 => Ok(ListnodesNodesAddressesType::IPV6), 3 => Ok(ListnodesNodesAddressesType::TORV2), 4 => Ok(ListnodesNodesAddressesType::TORV3), - 5 => Ok(ListnodesNodesAddressesType::WEBSOCKET), o => Err(anyhow::anyhow!("Unknown variant {} for enum ListnodesNodesAddressesType", o)), } } @@ -3172,142 +3199,808 @@ pub mod responses { } } - #[derive(Clone, Debug, Deserialize, Serialize)] - pub struct DisconnectResponse { + /// the channel state, in particular "CHANNELD_NORMAL" means the channel can be used normally + #[derive(Copy, Clone, Debug, Deserialize, Serialize)] + pub enum ListpeerchannelsChannelsState { + #[serde(rename = "OPENINGD")] + OPENINGD, + #[serde(rename = "CHANNELD_AWAITING_LOCKIN")] + CHANNELD_AWAITING_LOCKIN, + #[serde(rename = "CHANNELD_NORMAL")] + CHANNELD_NORMAL, + #[serde(rename = "CHANNELD_SHUTTING_DOWN")] + CHANNELD_SHUTTING_DOWN, + #[serde(rename = "CLOSINGD_SIGEXCHANGE")] + CLOSINGD_SIGEXCHANGE, + #[serde(rename = "CLOSINGD_COMPLETE")] + CLOSINGD_COMPLETE, + #[serde(rename = "AWAITING_UNILATERAL")] + AWAITING_UNILATERAL, + #[serde(rename = "FUNDING_SPEND_SEEN")] + FUNDING_SPEND_SEEN, + #[serde(rename = "ONCHAIN")] + ONCHAIN, + #[serde(rename = "DUALOPEND_OPEN_INIT")] + DUALOPEND_OPEN_INIT, + #[serde(rename = "DUALOPEND_AWAITING_LOCKIN")] + DUALOPEND_AWAITING_LOCKIN, } - impl TryFrom for DisconnectResponse { - type Error = super::TryFromResponseError; - - fn try_from(response: Response) -> Result { - match response { - Response::Disconnect(response) => Ok(response), - _ => Err(TryFromResponseError) + impl TryFrom for ListpeerchannelsChannelsState { + type Error = anyhow::Error; + fn try_from(c: i32) -> Result { + match c { + 0 => Ok(ListpeerchannelsChannelsState::OPENINGD), + 1 => Ok(ListpeerchannelsChannelsState::CHANNELD_AWAITING_LOCKIN), + 2 => Ok(ListpeerchannelsChannelsState::CHANNELD_NORMAL), + 3 => Ok(ListpeerchannelsChannelsState::CHANNELD_SHUTTING_DOWN), + 4 => Ok(ListpeerchannelsChannelsState::CLOSINGD_SIGEXCHANGE), + 5 => Ok(ListpeerchannelsChannelsState::CLOSINGD_COMPLETE), + 6 => Ok(ListpeerchannelsChannelsState::AWAITING_UNILATERAL), + 7 => Ok(ListpeerchannelsChannelsState::FUNDING_SPEND_SEEN), + 8 => Ok(ListpeerchannelsChannelsState::ONCHAIN), + 9 => Ok(ListpeerchannelsChannelsState::DUALOPEND_OPEN_INIT), + 10 => Ok(ListpeerchannelsChannelsState::DUALOPEND_AWAITING_LOCKIN), + o => Err(anyhow::anyhow!("Unknown variant {} for enum ListpeerchannelsChannelsState", o)), } } } - #[derive(Clone, Debug, Deserialize, Serialize)] - pub struct FeeratesPerkb { - pub min_acceptable: u32, - pub max_acceptable: u32, - #[serde(skip_serializing_if = "Option::is_none")] - pub opening: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub mutual_close: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub unilateral_close: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub delayed_to_us: Option, + pub struct ListpeerchannelsChannelsFeerate { #[serde(skip_serializing_if = "Option::is_none")] - pub htlc_resolution: Option, + pub perkw: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub penalty: Option, + pub perkb: Option, } #[derive(Clone, Debug, Deserialize, Serialize)] - pub struct FeeratesPerkw { - pub min_acceptable: u32, - pub max_acceptable: u32, + pub struct ListpeerchannelsChannelsInflight { #[serde(skip_serializing_if = "Option::is_none")] - pub opening: Option, + pub funding_txid: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub mutual_close: Option, + pub funding_outnum: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub unilateral_close: Option, + pub feerate: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub delayed_to_us: Option, + pub total_funding_msat: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub htlc_resolution: Option, + pub our_funding_msat: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub penalty: Option, - } - - #[derive(Clone, Debug, Deserialize, Serialize)] - pub struct FeeratesOnchain_fee_estimates { - pub opening_channel_satoshis: u64, - pub mutual_close_satoshis: u64, - pub unilateral_close_satoshis: u64, - pub htlc_timeout_satoshis: u64, - pub htlc_success_satoshis: u64, + pub scratch_txid: Option, } #[derive(Clone, Debug, Deserialize, Serialize)] - pub struct FeeratesResponse { + pub struct ListpeerchannelsChannelsFunding { #[serde(skip_serializing_if = "Option::is_none")] - pub warning_missing_feerates: Option, + pub pushed_msat: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub perkb: Option, + pub local_funds_msat: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub perkw: Option, + pub remote_funds_msat: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub onchain_fee_estimates: Option, - } - - impl TryFrom for FeeratesResponse { - type Error = super::TryFromResponseError; - - fn try_from(response: Response) -> Result { - match response { - Response::Feerates(response) => Ok(response), - _ => Err(TryFromResponseError) - } - } + pub fee_paid_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub fee_rcvd_msat: Option, } #[derive(Clone, Debug, Deserialize, Serialize)] - pub struct FundchannelResponse { - pub tx: String, - pub txid: String, - pub outnum: u32, - pub channel_id: String, + pub struct ListpeerchannelsChannelsAlias { #[serde(skip_serializing_if = "Option::is_none")] - pub close_to: Option, + pub local: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub mindepth: Option, - } - - impl TryFrom for FundchannelResponse { - type Error = super::TryFromResponseError; - - fn try_from(response: Response) -> Result { - match response { - Response::FundChannel(response) => Ok(response), - _ => Err(TryFromResponseError) - } - } + pub remote: Option, } - /// The features understood by the destination node + /// Whether it came from peer, or is going to peer #[derive(Copy, Clone, Debug, Deserialize, Serialize)] - pub enum GetrouteRouteStyle { - #[serde(rename = "tlv")] - TLV, + pub enum ListpeerchannelsChannelsHtlcsDirection { + #[serde(rename = "in")] + IN, + #[serde(rename = "out")] + OUT, } - impl TryFrom for GetrouteRouteStyle { + impl TryFrom for ListpeerchannelsChannelsHtlcsDirection { type Error = anyhow::Error; - fn try_from(c: i32) -> Result { + fn try_from(c: i32) -> Result { match c { - 0 => Ok(GetrouteRouteStyle::TLV), - o => Err(anyhow::anyhow!("Unknown variant {} for enum GetrouteRouteStyle", o)), + 0 => Ok(ListpeerchannelsChannelsHtlcsDirection::IN), + 1 => Ok(ListpeerchannelsChannelsHtlcsDirection::OUT), + o => Err(anyhow::anyhow!("Unknown variant {} for enum ListpeerchannelsChannelsHtlcsDirection", o)), } } } #[derive(Clone, Debug, Deserialize, Serialize)] - pub struct GetrouteRoute { - pub id: PublicKey, - pub channel: ShortChannelId, - pub direction: u32, - #[deprecated] + pub struct ListpeerchannelsChannelsHtlcs { #[serde(skip_serializing_if = "Option::is_none")] - pub msatoshi: Option, - pub amount_msat: Amount, - pub delay: u32, - // Path `GetRoute.route[].style` - pub style: GetrouteRouteStyle, - } - + pub direction: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub amount_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub expiry: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub payment_hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub local_trimmed: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub status: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub state: Option, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListpeerchannelsChannels { + #[serde(skip_serializing_if = "Option::is_none")] + pub peer_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub peer_connected: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub state: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub scratch_txid: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub feerate: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub owner: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub short_channel_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub channel_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub funding_txid: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub funding_outnum: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub initial_feerate: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub last_feerate: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub next_feerate: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub next_fee_step: Option, + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub inflight: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub close_to: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub private: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub opener: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub closer: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub funding: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub to_us_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub min_to_us_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub max_to_us_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub total_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub fee_base_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub fee_proportional_millionths: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub dust_limit_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub max_total_htlc_in_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub their_reserve_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub our_reserve_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub spendable_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub receivable_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub minimum_htlc_in_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub minimum_htlc_out_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub maximum_htlc_out_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub their_to_self_delay: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub our_to_self_delay: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub max_accepted_htlcs: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub alias: Option, + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub status: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub in_payments_offered: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub in_offered_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub in_payments_fulfilled: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub in_fulfilled_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub out_payments_offered: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub out_offered_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub out_payments_fulfilled: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub out_fulfilled_msat: Option, + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub htlcs: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub close_to_addr: Option, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListpeerchannelsResponse { + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub channels: Option>, + } + + impl TryFrom for ListpeerchannelsResponse { + type Error = super::TryFromResponseError; + + fn try_from(response: Response) -> Result { + match response { + Response::ListPeerChannels(response) => Ok(response), + _ => Err(TryFromResponseError) + } + } + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListclosedchannelsClosedchannelsAlias { + #[serde(skip_serializing_if = "Option::is_none")] + pub local: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub remote: Option, + } + + /// What caused the channel to close + #[derive(Copy, Clone, Debug, Deserialize, Serialize)] + pub enum ListclosedchannelsClosedchannelsClose_cause { + #[serde(rename = "unknown")] + UNKNOWN, + #[serde(rename = "local")] + LOCAL, + #[serde(rename = "user")] + USER, + #[serde(rename = "remote")] + REMOTE, + #[serde(rename = "protocol")] + PROTOCOL, + #[serde(rename = "onchain")] + ONCHAIN, + } + + impl TryFrom for ListclosedchannelsClosedchannelsClose_cause { + type Error = anyhow::Error; + fn try_from(c: i32) -> Result { + match c { + 0 => Ok(ListclosedchannelsClosedchannelsClose_cause::UNKNOWN), + 1 => Ok(ListclosedchannelsClosedchannelsClose_cause::LOCAL), + 2 => Ok(ListclosedchannelsClosedchannelsClose_cause::USER), + 3 => Ok(ListclosedchannelsClosedchannelsClose_cause::REMOTE), + 4 => Ok(ListclosedchannelsClosedchannelsClose_cause::PROTOCOL), + 5 => Ok(ListclosedchannelsClosedchannelsClose_cause::ONCHAIN), + o => Err(anyhow::anyhow!("Unknown variant {} for enum ListclosedchannelsClosedchannelsClose_cause", o)), + } + } + } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListclosedchannelsClosedchannels { + #[serde(skip_serializing_if = "Option::is_none")] + pub peer_id: Option, + pub channel_id: Sha256, + #[serde(skip_serializing_if = "Option::is_none")] + pub short_channel_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub alias: Option, + // Path `ListClosedChannels.closedchannels[].opener` + pub opener: ChannelSide, + #[serde(skip_serializing_if = "Option::is_none")] + pub closer: Option, + pub private: bool, + pub total_local_commitments: u64, + pub total_remote_commitments: u64, + pub total_htlcs_sent: u64, + pub funding_txid: String, + pub funding_outnum: u32, + pub leased: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub funding_fee_paid_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub funding_fee_rcvd_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub funding_pushed_msat: Option, + pub total_msat: Amount, + pub final_to_us_msat: Amount, + pub min_to_us_msat: Amount, + pub max_to_us_msat: Amount, + #[serde(skip_serializing_if = "Option::is_none")] + pub last_commitment_txid: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub last_commitment_fee_msat: Option, + // Path `ListClosedChannels.closedchannels[].close_cause` + pub close_cause: ListclosedchannelsClosedchannelsClose_cause, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListclosedchannelsResponse { + pub closedchannels: Vec, + } + + impl TryFrom for ListclosedchannelsResponse { + type Error = super::TryFromResponseError; + + fn try_from(response: Response) -> Result { + match response { + Response::ListClosedChannels(response) => Ok(response), + _ => Err(TryFromResponseError) + } + } + } + + /// the address type (if known) + #[derive(Copy, Clone, Debug, Deserialize, Serialize)] + pub enum DecodepayFallbacksType { + #[serde(rename = "P2PKH")] + P2PKH, + #[serde(rename = "P2SH")] + P2SH, + #[serde(rename = "P2WPKH")] + P2WPKH, + #[serde(rename = "P2WSH")] + P2WSH, + } + + impl TryFrom for DecodepayFallbacksType { + type Error = anyhow::Error; + fn try_from(c: i32) -> Result { + match c { + 0 => Ok(DecodepayFallbacksType::P2PKH), + 1 => Ok(DecodepayFallbacksType::P2SH), + 2 => Ok(DecodepayFallbacksType::P2WPKH), + 3 => Ok(DecodepayFallbacksType::P2WSH), + o => Err(anyhow::anyhow!("Unknown variant {} for enum DecodepayFallbacksType", o)), + } + } + } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct DecodepayFallbacks { + // Path `DecodePay.fallbacks[].type` + #[serde(rename = "type")] + pub item_type: DecodepayFallbacksType, + #[serde(skip_serializing_if = "Option::is_none")] + pub addr: Option, + pub hex: String, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct DecodepayExtra { + pub tag: String, + pub data: String, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct DecodepayResponse { + pub currency: String, + pub created_at: u64, + pub expiry: u64, + pub payee: PublicKey, + #[serde(skip_serializing_if = "Option::is_none")] + pub amount_msat: Option, + pub payment_hash: Sha256, + pub signature: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub description_hash: Option, + pub min_final_cltv_expiry: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub payment_secret: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub features: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub payment_metadata: Option, + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub fallbacks: Option>, + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub extra: Option>, + } + + impl TryFrom for DecodepayResponse { + type Error = super::TryFromResponseError; + + fn try_from(response: Response) -> Result { + match response { + Response::DecodePay(response) => Ok(response), + _ => Err(TryFromResponseError) + } + } + } + + /// what kind of object it decoded to + #[derive(Copy, Clone, Debug, Deserialize, Serialize)] + pub enum DecodeType { + #[serde(rename = "bolt12 offer")] + BOLT12_OFFER, + #[serde(rename = "bolt12 invoice")] + BOLT12_INVOICE, + #[serde(rename = "bolt12 invoice_request")] + BOLT12_INVOICE_REQUEST, + #[serde(rename = "bolt11 invoice")] + BOLT11_INVOICE, + #[serde(rename = "rune")] + RUNE, + } + + impl TryFrom for DecodeType { + type Error = anyhow::Error; + fn try_from(c: i32) -> Result { + match c { + 0 => Ok(DecodeType::BOLT12_OFFER), + 1 => Ok(DecodeType::BOLT12_INVOICE), + 2 => Ok(DecodeType::BOLT12_INVOICE_REQUEST), + 3 => Ok(DecodeType::BOLT11_INVOICE), + 4 => Ok(DecodeType::RUNE), + o => Err(anyhow::anyhow!("Unknown variant {} for enum DecodeType", o)), + } + } + } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct DecodeOffer_paths { + pub first_node_id: PublicKey, + pub blinding: PublicKey, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct DecodeInvoice_fallbacks { + pub version: u8, + pub hex: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub address: Option, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct DecodeFallbacks { + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_invoice_fallbacks_version_invalid: Option, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct DecodeExtra { + pub tag: String, + pub data: String, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct DecodeRestrictions { + pub alternatives: Vec, + pub summary: String, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct DecodeResponse { + // Path `Decode.type` + #[serde(rename = "type")] + pub item_type: DecodeType, + pub valid: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub offer_id: Option, + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub offer_chains: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub offer_metadata: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub offer_currency: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_unknown_offer_currency: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub currency_minor_unit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub offer_amount: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub offer_amount_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub offer_description: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub offer_issuer: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub offer_features: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub offer_absolute_expiry: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub offer_quantity_max: Option, + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub offer_paths: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub offer_node_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_missing_offer_node_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_invalid_offer_description: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_missing_offer_description: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_invalid_offer_currency: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_invalid_offer_issuer: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invreq_metadata: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invreq_payer_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invreq_chain: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invreq_amount_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invreq_features: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invreq_quantity: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invreq_payer_note: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invreq_recurrence_counter: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invreq_recurrence_start: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_missing_invreq_metadata: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_missing_invreq_payer_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_invalid_invreq_payer_note: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_missing_invoice_request_signature: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_invalid_invoice_request_signature: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invoice_created_at: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invoice_relative_expiry: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invoice_payment_hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invoice_amount_msat: Option, + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub invoice_fallbacks: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub invoice_features: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invoice_node_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub invoice_recurrence_basetime: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_missing_invoice_paths: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_missing_invoice_blindedpay: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_missing_invoice_created_at: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_missing_invoice_payment_hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_missing_invoice_amount: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_missing_invoice_recurrence_basetime: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_missing_invoice_node_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_missing_invoice_signature: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_invalid_invoice_signature: Option, + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub fallbacks: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub created_at: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub expiry: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub payee: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub payment_hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub description_hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub min_final_cltv_expiry: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub payment_secret: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub payment_metadata: Option, + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub extra: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub unique_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub string: Option, + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub restrictions: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_rune_invalid_utf8: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub hex: Option, + } + + impl TryFrom for DecodeResponse { + type Error = super::TryFromResponseError; + + fn try_from(response: Response) -> Result { + match response { + Response::Decode(response) => Ok(response), + _ => Err(TryFromResponseError) + } + } + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct DisconnectResponse { + } + + impl TryFrom for DisconnectResponse { + type Error = super::TryFromResponseError; + + fn try_from(response: Response) -> Result { + match response { + Response::Disconnect(response) => Ok(response), + _ => Err(TryFromResponseError) + } + } + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct FeeratesPerkbEstimates { + #[serde(skip_serializing_if = "Option::is_none")] + pub blockcount: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub feerate: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub smoothed_feerate: Option, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct FeeratesPerkb { + pub min_acceptable: u32, + pub max_acceptable: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub floor: Option, + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub estimates: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub opening: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub mutual_close: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub unilateral_close: Option, + #[deprecated] + #[serde(skip_serializing_if = "Option::is_none")] + pub delayed_to_us: Option, + #[deprecated] + #[serde(skip_serializing_if = "Option::is_none")] + pub htlc_resolution: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub penalty: Option, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct FeeratesPerkwEstimates { + #[serde(skip_serializing_if = "Option::is_none")] + pub blockcount: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub feerate: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub smoothed_feerate: Option, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct FeeratesPerkw { + pub min_acceptable: u32, + pub max_acceptable: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub floor: Option, + #[serde(skip_serializing_if = "crate::is_none_or_empty")] + pub estimates: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub opening: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub mutual_close: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub unilateral_close: Option, + #[deprecated] + #[serde(skip_serializing_if = "Option::is_none")] + pub delayed_to_us: Option, + #[deprecated] + #[serde(skip_serializing_if = "Option::is_none")] + pub htlc_resolution: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub penalty: Option, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct FeeratesOnchain_fee_estimates { + pub opening_channel_satoshis: u64, + pub mutual_close_satoshis: u64, + pub unilateral_close_satoshis: u64, + pub htlc_timeout_satoshis: u64, + pub htlc_success_satoshis: u64, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct FeeratesResponse { + #[serde(skip_serializing_if = "Option::is_none")] + pub warning_missing_feerates: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub perkb: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub perkw: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub onchain_fee_estimates: Option, + } + + impl TryFrom for FeeratesResponse { + type Error = super::TryFromResponseError; + + fn try_from(response: Response) -> Result { + match response { + Response::Feerates(response) => Ok(response), + _ => Err(TryFromResponseError) + } + } + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct FundchannelResponse { + pub tx: String, + pub txid: String, + pub outnum: u32, + pub channel_id: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub close_to: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub mindepth: Option, + } + + impl TryFrom for FundchannelResponse { + type Error = super::TryFromResponseError; + + fn try_from(response: Response) -> Result { + match response { + Response::FundChannel(response) => Ok(response), + _ => Err(TryFromResponseError) + } + } + } + + /// The features understood by the destination node + #[derive(Copy, Clone, Debug, Deserialize, Serialize)] + pub enum GetrouteRouteStyle { + #[serde(rename = "tlv")] + TLV, + } + + impl TryFrom for GetrouteRouteStyle { + type Error = anyhow::Error; + fn try_from(c: i32) -> Result { + match c { + 0 => Ok(GetrouteRouteStyle::TLV), + o => Err(anyhow::anyhow!("Unknown variant {} for enum GetrouteRouteStyle", o)), + } + } + } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct GetrouteRoute { + pub id: PublicKey, + pub channel: ShortChannelId, + pub direction: u32, + pub amount_msat: Amount, + pub delay: u32, + // Path `GetRoute.route[].style` + pub style: GetrouteRouteStyle, + } + #[derive(Clone, Debug, Deserialize, Serialize)] pub struct GetrouteResponse { pub route: Vec, @@ -3485,6 +4178,22 @@ pub mod responses { } } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct SendcustommsgResponse { + pub status: String, + } + + impl TryFrom for SendcustommsgResponse { + type Error = super::TryFromResponseError; + + fn try_from(response: Response) -> Result { + match response { + Response::SendCustomMsg(response) => Ok(response), + _ => Err(TryFromResponseError) + } + } + } + #[derive(Clone, Debug, Deserialize, Serialize)] pub struct SetchannelChannels { pub peer_id: PublicKey, @@ -3517,6 +4226,22 @@ pub mod responses { } } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct SigninvoiceResponse { + pub bolt11: String, + } + + impl TryFrom for SigninvoiceResponse { + type Error = super::TryFromResponseError; + + fn try_from(response: Response) -> Result { + match response { + Response::SignInvoice(response) => Ok(response), + _ => Err(TryFromResponseError) + } + } + } + #[derive(Clone, Debug, Deserialize, Serialize)] pub struct SignmessageResponse { pub signature: String, @@ -3550,5 +4275,35 @@ pub mod responses { } } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct PreapprovekeysendResponse { + } + + impl TryFrom for PreapprovekeysendResponse { + type Error = super::TryFromResponseError; + + fn try_from(response: Response) -> Result { + match response { + Response::PreApproveKeysend(response) => Ok(response), + _ => Err(TryFromResponseError) + } + } + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct PreapproveinvoiceResponse { + } + + impl TryFrom for PreapproveinvoiceResponse { + type Error = super::TryFromResponseError; + + fn try_from(response: Response) -> Result { + match response { + Response::PreApproveInvoice(response) => Ok(response), + _ => Err(TryFromResponseError) + } + } + } + } diff --git a/cln-rpc/src/primitives.rs b/cln-rpc/src/primitives.rs index 4dbc97079678..1d8058cd62ee 100644 --- a/cln-rpc/src/primitives.rs +++ b/cln-rpc/src/primitives.rs @@ -13,17 +13,42 @@ pub use bitcoin::secp256k1::PublicKey; #[derive(Copy, Clone, Serialize, Deserialize, Debug)] #[allow(non_camel_case_types)] pub enum ChannelState { - OPENINGD, - CHANNELD_AWAITING_LOCKIN, - CHANNELD_NORMAL, - CHANNELD_SHUTTING_DOWN, - CLOSINGD_SIGEXCHANGE, - CLOSINGD_COMPLETE, - AWAITING_UNILATERAL, - FUNDING_SPEND_SEEN, - ONCHAIN, - DUALOPEND_OPEN_INIT, - DUALOPEND_AWAITING_LOCKIN, + OPENINGD = 0, + CHANNELD_AWAITING_LOCKIN = 1, + CHANNELD_NORMAL = 2, + CHANNELD_SHUTTING_DOWN = 3, + CLOSINGD_SIGEXCHANGE = 4, + CLOSINGD_COMPLETE = 5, + AWAITING_UNILATERAL = 6, + FUNDING_SPEND_SEEN = 7, + ONCHAIN = 8, + DUALOPEND_OPEN_INIT = 9, + DUALOPEND_AWAITING_LOCKIN = 10, +} + +#[derive(Copy, Clone, Serialize, Deserialize, Debug)] +#[allow(non_camel_case_types)] +pub enum HtlcState { + SENT_ADD_HTLC = 0, + SENT_ADD_COMMIT = 1, + RCVD_ADD_REVOCATION = 2, + RCVD_ADD_ACK_COMMIT = 3, + SENT_ADD_ACK_REVOCATION = 4, + RCVD_ADD_ACK_REVOCATION = 5, + RCVD_REMOVE_HTLC = 6, + RCVD_REMOVE_COMMIT = 7, + SENT_REMOVE_REVOCATION = 8, + SENT_REMOVE_ACK_COMMIT = 9, + RCVD_REMOVE_ACK_REVOCATION = 10, + RCVD_ADD_HTLC = 11, + RCVD_ADD_COMMIT = 12, + SENT_ADD_REVOCATION = 13, + SENT_ADD_ACK_COMMIT = 14, + SENT_REMOVE_HTLC = 15, + SENT_REMOVE_COMMIT = 16, + RCVD_REMOVE_REVOCATION = 17, + RCVD_REMOVE_ACK_COMMIT = 18, + SENT_REMOVE_ACK_REVOCATION = 19, } #[derive(Copy, Clone, Serialize, Deserialize, Debug)] @@ -254,6 +279,70 @@ pub enum ChannelSide { REMOTE, } +impl TryFrom for ChannelSide { + type Error = crate::Error; + + fn try_from(value: i32) -> std::result::Result { + match value { + 0 => Ok(ChannelSide::LOCAL), + 1 => Ok(ChannelSide::REMOTE), + _ => Err(anyhow!( + "Invalid ChannelSide mapping, only 0 or 1 are allowed" + )), + } + } +} + +impl TryFrom for ChannelState { + type Error = crate::Error; + + fn try_from(value: i32) -> std::result::Result { + match value { + 0 => Ok(ChannelState::OPENINGD), + 1 => Ok(ChannelState::CHANNELD_AWAITING_LOCKIN), + 2 => Ok(ChannelState::CHANNELD_NORMAL), + 3 => Ok(ChannelState::CHANNELD_SHUTTING_DOWN), + 4 => Ok(ChannelState::CLOSINGD_SIGEXCHANGE), + 5 => Ok(ChannelState::CLOSINGD_COMPLETE), + 6 => Ok(ChannelState::AWAITING_UNILATERAL), + 7 => Ok(ChannelState::FUNDING_SPEND_SEEN), + 8 => Ok(ChannelState::ONCHAIN), + 9 => Ok(ChannelState::DUALOPEND_OPEN_INIT), + 10 => Ok(ChannelState::DUALOPEND_AWAITING_LOCKIN), + _ => Err(anyhow!("Invalid channel state {}", value)), + } + } +} + +impl From for HtlcState { + fn from(value: i32) -> Self { + match value { + 0 => HtlcState::SENT_ADD_HTLC, + 1 => HtlcState::SENT_ADD_COMMIT, + 2 => HtlcState::RCVD_ADD_REVOCATION, + 3 => HtlcState::RCVD_ADD_ACK_COMMIT, + 4 => HtlcState::SENT_ADD_ACK_REVOCATION, + 5 => HtlcState::RCVD_ADD_ACK_REVOCATION, + 6 => HtlcState::RCVD_REMOVE_HTLC, + 7 => HtlcState::RCVD_REMOVE_COMMIT, + 8 => HtlcState::SENT_REMOVE_REVOCATION, + 9 => HtlcState::SENT_REMOVE_ACK_COMMIT, + 10 => HtlcState::RCVD_REMOVE_ACK_REVOCATION, + 11 => HtlcState::RCVD_ADD_HTLC, + 12 => HtlcState::RCVD_ADD_COMMIT, + 13 => HtlcState::SENT_ADD_REVOCATION, + 14 => HtlcState::SENT_ADD_ACK_COMMIT, + 15 => HtlcState::SENT_REMOVE_HTLC, + 16 => HtlcState::SENT_REMOVE_COMMIT, + 17 => HtlcState::RCVD_REMOVE_REVOCATION, + 18 => HtlcState::RCVD_REMOVE_ACK_COMMIT, + 19 => HtlcState::SENT_REMOVE_ACK_REVOCATION, + + n => panic!("Unmapped HtlcState variant: {}", n), + } + } +} + impl<'de> Deserialize<'de> for Amount { fn deserialize(deserializer: D) -> Result where @@ -617,16 +706,62 @@ pub struct Routehop { pub expirydelta: u16, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug)] pub struct Routehint { pub hops: Vec, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug)] pub struct RoutehintList { pub hints: Vec, } +use serde::ser::SerializeSeq; + +impl Serialize for Routehint { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(Some(self.hops.len()))?; + for e in self.hops.iter() { + seq.serialize_element(e)?; + } + seq.end() + } +} + +impl Serialize for RoutehintList { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(Some(self.hints.len()))?; + for e in self.hints.iter() { + seq.serialize_element(e)?; + } + seq.end() + } +} + +impl<'de> Deserialize<'de> for RoutehintList { + fn deserialize(_deserializer: D) -> Result + where + D: Deserializer<'de>, + { + todo!("Required once we roundtrip, but not necessary for cln-rpc itself") + } +} + +impl<'de> Deserialize<'de> for Routehint { + fn deserialize(_deserializer: D) -> Result + where + D: Deserializer<'de>, + { + todo!("Required once we roundtrip, but not necessary for cln-rpc itself") + } +} + /// An error returned by the lightningd RPC consisting of a code and a /// message #[derive(Clone, Serialize, Deserialize, Debug)] diff --git a/common/Makefile b/common/Makefile index 273bd153c653..1944a5f15936 100644 --- a/common/Makefile +++ b/common/Makefile @@ -23,6 +23,7 @@ COMMON_SRC_NOGEN := \ common/close_tx.c \ common/coin_mvt.c \ common/configdir.c \ + common/configvar.c \ common/cryptomsg.c \ common/daemon.c \ common/daemon_conn.c \ @@ -87,6 +88,7 @@ COMMON_SRC_NOGEN := \ common/status_wire.c \ common/subdaemon.c \ common/timeout.c \ + common/tx_roles.c \ common/type_to_string.c \ common/utils.c \ common/utxo.c \ @@ -108,8 +110,7 @@ COMMON_HEADERS_NOGEN := $(COMMON_SRC_NOGEN:.c=.h) \ common/htlc.h \ common/json_command.h \ common/jsonrpc_errors.h \ - common/overflows.h \ - common/tx_roles.h + common/overflows.h COMMON_HEADERS_GEN := common/htlc_state_names_gen.h common/status_wiregen.h common/peer_status_wiregen.h common/scb_wiregen.h diff --git a/common/bech32.c b/common/bech32.c index 7e949f6c3400..ccf79d5b159c 100644 --- a/common/bech32.c +++ b/common/bech32.c @@ -55,7 +55,7 @@ const int8_t bech32_charset_rev[128] = { 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 }; -int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len, size_t max_input_len, bech32_encoding enc) { +int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len, size_t max_output_len, bech32_encoding enc) { uint32_t chk = 1; size_t i = 0; while (hrp[i] != 0) { @@ -68,7 +68,7 @@ int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t dat chk = bech32_polymod_step(chk) ^ (ch >> 5); ++i; } - if (i + 7 + data_len > max_input_len) return 0; + if (i + 7 + data_len > max_output_len) return 0; chk = bech32_polymod_step(chk); while (*hrp != 0) { chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f); diff --git a/common/bech32.h b/common/bech32.h index 614ad321e3df..794510be2755 100644 --- a/common/bech32.h +++ b/common/bech32.h @@ -83,7 +83,7 @@ typedef enum { * In: hrp : Pointer to the null-terminated human readable part. * data : Pointer to an array of 5-bit values. * data_len: Length of the data array. - * max_input_len: Maximum valid length of input (90 for segwit usage). + * max_output_len: Maximum valid length of output (90 for segwit usage). * enc: Which encoding to use (BECH32_ENCODING_BECH32{,M}). * Returns 1 if successful. */ @@ -92,7 +92,7 @@ int bech32_encode( const char *hrp, const uint8_t *data, size_t data_len, - size_t max_input_len, + size_t max_output_len, bech32_encoding enc ); diff --git a/common/blindedpath.c b/common/blindedpath.c index 44a1d7ed9827..5721c36ad7f4 100644 --- a/common/blindedpath.c +++ b/common/blindedpath.c @@ -27,7 +27,7 @@ static bool blind_node(const struct privkey *blinding, SUPERVERBOSE("\t\"blinded_node_id\": \"%s\",\n", type_to_string(tmpctx, struct pubkey, node_alias)); - /* BOLT-route-blinding #4: + /* BOLT #4: * - `E(i+1) = SHA256(E(i) || ss(i)) * E(i)` * (NB: `N(i)` MUST NOT learn `e(i)`) */ @@ -36,7 +36,7 @@ static bool blind_node(const struct privkey *blinding, SUPERVERBOSE("\t\"E\": \"%s\",\n", type_to_string(tmpctx, struct pubkey, &blinding_pubkey)); - /* BOLT-route-blinding #4: + /* BOLT #4: * - `e(i+1) = SHA256(E(i) || ss(i)) * e(i)` * (blinding ephemeral private key, only known by `N(r)`) */ @@ -63,7 +63,7 @@ static u8 *enctlv_from_encmsg_raw(const tal_t *ctx, /* All-zero npub */ static const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES]; - /* BOLT-route-blinding #4: + /* BOLT #4: * - `ss(i) = SHA256(e(i) * N(i)) = SHA256(k(i) * E(i))` * (ECDH shared secret known only by `N(r)` and `N(i)`) */ @@ -80,7 +80,7 @@ static u8 *enctlv_from_encmsg_raw(const tal_t *ctx, ret = tal_dup_talarr(ctx, u8, raw_encmsg); - /* BOLT-route-blinding #4: + /* BOLT #4: * - `rho(i) = HMAC256("rho", ss(i))` * (key used to encrypt the payload for `N(i)` by `N(r)`) */ @@ -88,10 +88,10 @@ static u8 *enctlv_from_encmsg_raw(const tal_t *ctx, SUPERVERBOSE("\t\"rho\": \"%s\",\n", type_to_string(tmpctx, struct secret, &rho)); - /* BOLT-route-blinding #4: - * - MUST encrypt each `encrypted_data_tlv(i)` with ChaCha20-Poly1305 - * using the corresponding `rho(i)` key and an all-zero nonce to - * produce `encrypted_recipient_data(i)` + /* BOLT #4: + * - MUST encrypt each `encrypted_data_tlv(i)` with ChaCha20-Poly1305 using + * the corresponding `rho(i)` key and an all-zero nonce to produce + * `encrypted_recipient_data(i)` */ /* Encrypt in place */ towire_pad(&ret, crypto_aead_chacha20poly1305_ietf_ABYTES); @@ -132,7 +132,7 @@ bool unblind_onion(const struct pubkey *blinding, { struct secret hmac; - /* BOLT-route-blinding #4: + /* BOLT #4: * A reader: *... * - MUST compute: @@ -145,7 +145,7 @@ bool unblind_onion(const struct pubkey *blinding, /* We instead tweak the *ephemeral* key from the onion and use * our normal privkey: since hsmd knows only how to ECDH with * our real key. IOW: */ - /* BOLT-route-blinding #4: + /* BOLT #4: * - MUST use `b(i)` instead of its private key `k(i)` to decrypt the onion. Note * that the node may instead tweak the onion ephemeral key with * `HMAC256("blinded_node_id", ss(i))` which achieves the same result. @@ -165,7 +165,7 @@ static u8 *decrypt_encmsg_raw(const tal_t *ctx, /* All-zero npub */ static const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES]; - /* BOLT-route-blinding #4: + /* BOLT #4: * A reader: *... *- MUST decrypt the `encrypted_data` field using `rho(i)` and use @@ -222,7 +222,7 @@ bool blindedpath_get_alias(const struct secret *ss, { struct secret node_id_blinding; - /* BOLT-route-blinding #4: + /* BOLT #4: * - `B(i) = HMAC256("blinded_node_id", ss(i)) * N(i)` * (blinded `node_id` for `N(i)`, private key known only by `N(i)`) */ @@ -242,13 +242,13 @@ void blindedpath_next_blinding(const struct tlv_encrypted_data_tlv *enc, const struct secret *ss, struct pubkey *next_blinding) { - /* BOLT-route - * - `E(1) = SHA256(E(0) || ss(0)) * E(0)` + /* BOLT #4: + * - `E(i+1) = SHA256(E(i) || ss(i)) * E(i)` * ... * - If `encrypted_data` contains a `next_blinding_override`: - * - MUST use it as the next blinding point instead of `E(1)` + * - MUST use it as the next blinding point instead of `E(i+1)` * - Otherwise: - * - MUST use `E(1)` as the next blinding point + * - MUST use `E(i+1)` as the next blinding point */ if (enc->next_blinding_override) *next_blinding = *enc->next_blinding_override; diff --git a/common/blindedpay.c b/common/blindedpay.c index d959f8f55d94..a9a9aa0cf61b 100644 --- a/common/blindedpay.c +++ b/common/blindedpay.c @@ -18,7 +18,7 @@ u8 **blinded_onion_hops(const tal_t *ctx, bool first = (i == 0); bool final = (i == tal_count(onions) - 1); - /* BOLT-route-blinding #4: + /* BOLT-blinded-payments #4: * - For every node inside a blinded route: * - MUST include the `encrypted_recipient_data` provided by the * recipient diff --git a/common/bolt11.c b/common/bolt11.c index c2c7c3db136e..ce8532971947 100644 --- a/common/bolt11.c +++ b/common/bolt11.c @@ -284,7 +284,7 @@ static const char *decode_x(struct bolt11 *b11, /* BOLT #11: * - * `c` (24): `data_length` variable. `min_final_cltv_expiry` to use for the + * `c` (24): `data_length` variable. `min_final_cltv_expiry_delta` to use for the * last HTLC in the route. Default is 18 if not specified. */ static const char *decode_c(struct bolt11 *b11, @@ -594,7 +594,7 @@ struct bolt11 *new_bolt11(const tal_t *ctx, b11->expiry = DEFAULT_X; b11->features = tal_arr(b11, u8, 0); /* BOLT #11: - * - if the `c` field (`min_final_cltv_expiry`) is not provided: + * - if the `c` field (`min_final_cltv_expiry_delta`) is not provided: * - MUST use an expiry delta of at least 18 when making the payment */ b11->min_final_cltv_expiry = 18; @@ -1009,7 +1009,7 @@ static void push_field(u5 **data, char type, const void *src, size_t nbits) * * - if `x` is included: * - SHOULD use the minimum `data_length` possible. - * - MUST include one `c` field (`min_final_cltv_expiry`). + * - MUST include one `c` field (`min_final_cltv_expiry_delta`). *... * - SHOULD use the minimum `data_length` possible. */ @@ -1278,7 +1278,7 @@ char *bolt11_encode_(const tal_t *ctx, encode_x(&data, b11->expiry); /* BOLT #11: - * - MUST include one `c` field (`min_final_cltv_expiry`). + * - MUST include one `c` field (`min_final_cltv_expiry_delta`). */ encode_c(&data, b11->min_final_cltv_expiry); diff --git a/common/bolt11.h b/common/bolt11.h index 37bcd085e8a4..ebcf991926cc 100644 --- a/common/bolt11.h +++ b/common/bolt11.h @@ -13,7 +13,7 @@ /* BOLT #11: * * `c` (24): `data_length` variable. - * `min_final_cltv_expiry` to use for the last HTLC in the route. + * `min_final_cltv_expiry_delta` to use for the last HTLC in the route. * Default is 18 if not specified. */ #define DEFAULT_FINAL_CLTV_DELTA 18 diff --git a/common/bolt11_json.c b/common/bolt11_json.c index dde88c6dd78a..7fcdfd786381 100644 --- a/common/bolt11_json.c +++ b/common/bolt11_json.c @@ -51,8 +51,7 @@ void json_add_bolt11(struct json_stream *response, json_add_u64(response, "expiry", b11->expiry); json_add_node_id(response, "payee", &b11->receiver_id); if (b11->msat) - json_add_amount_msat_compat(response, *b11->msat, - "msatoshi", "amount_msat"); + json_add_amount_msat(response, "amount_msat", *b11->msat); if (b11->description) json_add_string(response, "description", b11->description); if (b11->description_hash) diff --git a/common/bolt12.h b/common/bolt12.h index 277a3f80bf31..e8213a56ae49 100644 --- a/common/bolt12.h +++ b/common/bolt12.h @@ -1,11 +1,7 @@ #ifndef LIGHTNING_COMMON_BOLT12_H #define LIGHTNING_COMMON_BOLT12_H #include "config.h" -#if EXPERIMENTAL_FEATURES -#include -#else #include -#endif struct feature_set; diff --git a/common/channel_type.c b/common/channel_type.c index 07c815217c40..80a9138f706a 100644 --- a/common/channel_type.c +++ b/common/channel_type.c @@ -43,6 +43,18 @@ struct channel_type *channel_type_anchor_outputs(const tal_t *ctx) return type; } +void channel_type_set_zeroconf(struct channel_type *type) +{ + set_feature_bit(&type->features, + COMPULSORY_FEATURE(OPT_ZEROCONF)); +} + +void channel_type_set_scid_alias(struct channel_type *type) +{ + set_feature_bit(&type->features, + COMPULSORY_FEATURE(OPT_SCID_ALIAS)); +} + struct channel_type *default_channel_type(const tal_t *ctx, const struct feature_set *our_features, const u8 *their_features) @@ -61,6 +73,10 @@ struct channel_type *default_channel_type(const tal_t *ctx, if (feature_negotiated(our_features, their_features, OPT_ANCHOR_OUTPUTS)) return channel_type_anchor_outputs(ctx); + else if (feature_negotiated(our_features, their_features, + OPT_DUAL_FUND)) + /* OPT_DUAL_FUND implies static remotekey */ + return channel_type_static_remotekey(ctx); /* BOLT #2: * - otherwise, if `option_static_remotekey` was negotiated: * - the `channel_type` is `option_static_remotekey` (bit 12) @@ -106,7 +122,8 @@ struct channel_type *channel_type_from(const tal_t *ctx, struct channel_type *channel_type_accept(const tal_t *ctx, const u8 *t, const struct feature_set *our_features, - const u8 *their_features) + const u8 *their_features, + bool accept_zeroconf) { struct channel_type *ctype, proposed; /* Need to copy since we're going to blank variant bits for equality. */ @@ -115,6 +132,7 @@ struct channel_type *channel_type_accept(const tal_t *ctx, static const size_t feats[] = { OPT_ANCHOR_OUTPUTS, OPT_STATIC_REMOTEKEY, + OPT_SCID_ALIAS, OPT_ZEROCONF, }; @@ -124,6 +142,7 @@ struct channel_type *channel_type_accept(const tal_t *ctx, * - `option_zeroconf` (bit 50) */ static const size_t variants[] = { + OPT_SCID_ALIAS, OPT_ZEROCONF, }; @@ -143,6 +162,15 @@ struct channel_type *channel_type_accept(const tal_t *ctx, } } + /* BOLT #2: + * The receiving node MUST fail the channel if: + *... + * - if `type` includes `option_zeroconf` and it does not trust the + * sender to open an unconfirmed channel. + */ + if (feature_is_set(t, OPT_ZEROCONF) && !accept_zeroconf) + return NULL; + /* Blank variants so we can just check for equality. */ for (size_t i = 0; i< ARRAY_SIZE(variants); i++) featurebits_unset(&proposed.features, variants[i]); @@ -162,3 +190,17 @@ struct channel_type *channel_type_accept(const tal_t *ctx, return NULL; } + +/* Return an array of feature strings indicating channel type. */ +const char **channel_type_name(const tal_t *ctx, const struct channel_type *t) +{ + const char **names = tal_arr(ctx, const char *, 0); + + for (size_t i = 0; i < tal_bytelen(t->features) * CHAR_BIT; i++) { + if (!feature_is_set(t->features, i)) + continue; + tal_arr_expand(&names, + feature_name(names, i) + strlen("option_")); + } + return names; +} diff --git a/common/channel_type.h b/common/channel_type.h index 858dc6471448..28096f3c253b 100644 --- a/common/channel_type.h +++ b/common/channel_type.h @@ -10,6 +10,10 @@ struct channel_type *channel_type_none(const tal_t *ctx); struct channel_type *channel_type_static_remotekey(const tal_t *ctx); struct channel_type *channel_type_anchor_outputs(const tal_t *ctx); +/* channel_type variants */ +void channel_type_set_zeroconf(struct channel_type *channel_type); +void channel_type_set_scid_alias(struct channel_type *channel_type); + /* Duplicate a channel_type */ struct channel_type *channel_type_dup(const tal_t *ctx, const struct channel_type *t); @@ -34,5 +38,9 @@ bool channel_type_eq(const struct channel_type *a, struct channel_type *channel_type_accept(const tal_t *ctx, const u8 *t, const struct feature_set *our_features, - const u8 *their_features); + const u8 *their_features, + bool accept_zeroconf); + +/* Return an array of feature strings indicating channel type. */ +const char **channel_type_name(const tal_t *ctx, const struct channel_type *t); #endif /* LIGHTNING_COMMON_CHANNEL_TYPE_H */ diff --git a/common/configdir.c b/common/configdir.c index c03abe18cf9e..bff259c329fe 100644 --- a/common/configdir.c +++ b/common/configdir.c @@ -4,17 +4,21 @@ #include #include #include +#include #include #include #include #include +#include #include #include bool deprecated_apis = true; +int opt_exitcode = 1; /* The regrettable globals */ static const tal_t *options_ctx; +static struct configvar *current_cv; /* Override a tal string; frees the old one. */ char *opt_set_talstr(const char *arg, char **p) @@ -50,113 +54,55 @@ static void tal_freefn(void *ptr) tal_free(ptr); } -static int config_parse_line_number; - -static void config_log_stderr_exit(const char *fmt, ...) -{ - char *msg; - va_list ap; - - va_start(ap, fmt); - - /* This is the format we expect:*/ - if (streq(fmt, "%s: %.*s: %s")) { - const char *argv0 = va_arg(ap, const char *); - unsigned int len = va_arg(ap, unsigned int); - const char *arg = va_arg(ap, const char *); - const char *problem = va_arg(ap, const char *); - - assert(argv0 != NULL); - assert(arg != NULL); - assert(problem != NULL); - /*mangle it to remove '--' and add the line number.*/ - msg = tal_fmt(NULL, "%s line %d: %.*s: %s", - argv0, - config_parse_line_number, len-2, arg+2, problem); - } else { - msg = tal_vfmt(NULL, fmt, ap); - } - va_end(ap); - - errx(1, "%s", msg); -} - -static void parse_include(const char *filename, bool must_exist, bool early, - size_t depth) +static struct configvar **gather_file_configvars(const tal_t *ctx, + enum configvar_src src, + const char *filename, + bool must_exist, + size_t include_depth) { char *contents, **lines; - char **all_args; /*For each line: either `--`argument, include file, or NULL*/ - char *argv[3]; - int i, argc; + struct configvar **cvs = tal_arr(ctx, struct configvar *, 0); - contents = grab_file(NULL, filename); + contents = grab_file(tmpctx, filename); /* The default config doesn't have to exist, but if the config was * specified on the command line it has to exist. */ if (!contents) { if (must_exist) err(1, "Opening and reading %s", filename); - return; + return cvs; } + /* Break into lines. */ lines = tal_strsplit(contents, contents, "\r\n", STR_EMPTY_OK); + for (size_t i = 0; i < tal_count(lines) - 1; i++) { + /* Comments & blank lines*/ + if (strstarts(lines[i], "#") || streq(lines[i], "")) + continue; - /* We have to keep all_args around, since opt will point into it: use - * magic tal name to tell memleak this isn't one. */ - all_args = tal_arr_label(options_ctx, char *, tal_count(lines) - 1, - TAL_LABEL(options_array_notleak, "")); + if (strstarts(lines[i], "include ")) { + const char *included = lines[i] + strlen("include "); + struct configvar **sub; - for (i = 0; i < tal_count(lines) - 1; i++) { - if (strstarts(lines[i], "#")) { - all_args[i] = NULL; - } else if (strstarts(lines[i], "include ")) { - /* If relative, it's relative to current config file */ - all_args[i] = path_join(all_args, - take(path_dirname(NULL, - filename)), - lines[i] + strlen("include ")); - } else { - /* Only valid forms are "foo" and "foo=bar" */ - all_args[i] = tal_fmt(all_args, "--%s", lines[i]); - } - /* This isn't a leak either */ - if (all_args[i]) - tal_set_name(all_args[i], TAL_LABEL(config_notleak, "")); - } - - /* - For each line we construct a fake argc,argv commandline. - argv[1] is the only element that changes between iterations. - */ - argc = 2; - argv[0] = cast_const(char *, filename); - argv[argc] = NULL; + if (include_depth > 100) + errx(1, "Include loop with %s and %s", filename, included); - for (i = 0; i < tal_count(all_args); i++) { - if (all_args[i] == NULL) - continue; - - if (!strstarts(all_args[i], "--")) { - /* There could be more, but this gives a hint. */ - if (depth > 100) - errx(1, "Include loop with %s and %s", - filename, all_args[i]); - parse_include(all_args[i], true, early, ++depth); + /* If relative, it's relative to current config file */ + sub = gather_file_configvars(NULL, + src, + path_join(tmpctx, + take(path_dirname(NULL, filename)), + included), + true, + include_depth + 1); + cvs = configvar_join(ctx, take(cvs), take(sub)); continue; } - config_parse_line_number = i + 1; - argv[1] = all_args[i]; - if (early) { - opt_early_parse_incomplete(argc, argv, - config_log_stderr_exit); - } else { - opt_parse(&argc, argv, config_log_stderr_exit); - argc = 2; /* opt_parse might have changed it */ - } + tal_arr_expand(&cvs, + configvar_new(cvs, src, filename, i+1, lines[i])); } - - tal_free(contents); + return cvs; } static char *default_base_configdir(const tal_t *ctx) @@ -179,6 +125,12 @@ static char *opt_set_network(const char *arg, void *unused) { assert(arg != NULL); + /* Ignore if called directly from opt (e.g. lightning-cli) */ + if (!current_cv) + return NULL; + + if (current_cv->src == CONFIGVAR_NETWORK_CONF) + return "not permitted in network-specific configuration files"; /* Set the global chainparams instance */ chainparams = chainparams_for_network(arg); if (!chainparams) @@ -191,159 +143,190 @@ static char *opt_set_specific_network(const char *network) return opt_set_network(network, NULL); } -static void opt_show_network(char buf[OPT_SHOW_LEN], const void *unused) +static bool opt_show_network(char *buf, size_t len, const void *unused) { - snprintf(buf, OPT_SHOW_LEN, "%s", chainparams->network_name); + snprintf(buf, len, "%s", chainparams->network_name); + return true; } -/* We track where we're getting options from, so we can detect misuse */ -enum parse_state { - CMDLINE = 1, - FORCED_CONFIG = 2, - TOPLEVEL_CONFIG = 4, - NETWORK_CONFIG = 8, -}; -static enum parse_state parse_state = CMDLINE; - -static char *opt_restricted_cmdline(const char *arg, const void *unused) +static char *opt_set_config_filename(const char *arg, char **p) { - if (parse_state != CMDLINE) - return "not permitted in configuration files"; - return NULL; -} + /* Ignore if called directly from opt (e.g. lightning-cli) */ + if (!current_cv) + return NULL; -static char *opt_restricted_toplevel_noarg(const void *unused) -{ - if (parse_state == NETWORK_CONFIG) - return "not permitted in network-specific configuration files"; - return NULL; + if (current_cv->src == CONFIGVAR_CMDLINE) + return opt_set_abspath(arg, p); + return "not permitted in configuration files"; } -static char *opt_restricted_toplevel(const char *arg, const void *unused) +static char *opt_set_lightning_dir(const char *arg, char **p) { - return opt_restricted_toplevel_noarg(NULL); + /* Ignore if called directly from opt (e.g. lightning-cli) */ + if (!current_cv) + return NULL; + + if (current_cv->src == CONFIGVAR_CMDLINE + || current_cv->src == CONFIGVAR_EXPLICIT_CONF) + return opt_set_abspath(arg, p); + return "not permitted in implicit configuration files"; } -static char *opt_restricted_forceconf_only(const char *arg, const void *unused) +void setup_option_allocators(void) { - if (parse_state != CMDLINE && parse_state != FORCED_CONFIG) - return "not permitted in implicit configuration files"; - return NULL; + /*~ These functions make ccan/opt use tal for allocations */ + opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn); } -bool is_restricted_ignored(const void *fn) +static void parse_configvars(struct configvar **cvs, + bool early, + bool full_knowledge) { - return fn == opt_restricted_toplevel_noarg - || fn == opt_restricted_toplevel - || fn == opt_restricted_forceconf_only; -} + for (size_t i = 0; i < tal_count(cvs); i++) { + const char *problem; + bool should_know; + + should_know = full_knowledge; + /* We should always know cmdline args in final parse */ + if (!early && cvs[i]->src == CONFIGVAR_CMDLINE) + should_know = true; + + current_cv = cvs[i]; + problem = configvar_parse(cvs[i], + early, + should_know, + IFDEV(true, false)); + current_cv = NULL; + if (!problem) + continue; -bool is_restricted_print_if_nonnull(const void *fn) -{ - return fn == opt_restricted_cmdline; + if (cvs[i]->file) { + errx(opt_exitcode, "Config file %s line %u: %s: %s", + cvs[i]->file, cvs[i]->linenum, + cvs[i]->configline, problem); + } else { + errx(opt_exitcode, "--%s: %s", cvs[i]->configline, problem); + } + } } -void setup_option_allocators(void) +static void finished_arg(int *argc, char **argv, size_t *idx, + bool remove_args) { - /*~ These functions make ccan/opt use tal for allocations */ - opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn); + if (!remove_args) { + (*idx)++; + return; + } + memmove(argv + *idx, argv + 1 + *idx, (*argc - *idx) * sizeof(char *)); + (*argc)--; } -/* network is NULL for parsing top-level config file. */ -static void parse_implied_config_file(const char *config_basedir, - const char *network, - bool early) +/* Now all options are known, we can turn cmdline into configvars */ +static struct configvar **gather_cmdline_args(const tal_t *ctx, + int *argc, char **argv, + bool remove_args) { - const char *dir, *filename; + struct configvar **cvs = tal_arr(ctx, struct configvar *, 0); - if (config_basedir) - dir = path_join(NULL, take(path_cwd(NULL)), config_basedir); - else - dir = default_base_configdir(NULL); + assert(argv[*argc] == NULL); + for (size_t i = 1; argv[i];) { + struct opt_table *ot; + const char *configline, *arg, *optarg; + enum configvar_src src; + bool extra_arg; - if (network) - dir = path_join(NULL, take(dir), network); + /* End of options? */ + if (streq(argv[i], "--")) + break; - filename = path_join(NULL, take(dir), "config"); - parse_include(filename, false, early, 0); - tal_free(filename); -} + if (!strstarts(argv[i], "-")) { + i++; + continue; + } -/* If they specify --conf, we just read that. - * Otherwise we read /config then //config - */ -void parse_config_files(const char *config_filename, - const char *config_basedir, - bool early) -{ - if (config_filename) { - parse_state = FORCED_CONFIG; - parse_include(config_filename, true, early, 0); - parse_state = CMDLINE; - return; + if (strstarts(argv[i], "--")) { + arg = argv[i] + 2; + ot = opt_find_long(arg, &optarg); + src = CONFIGVAR_CMDLINE; + } else { + /* FIXME: We don't handle multiple short + * options here! */ + arg = argv[i] + 1; + ot = opt_find_short(arg[0]); + optarg = NULL; + src = CONFIGVAR_CMDLINE_SHORT; + } + if (ot) { + extra_arg = (ot->type & OPT_HASARG) && !optarg; + } else { + /* Unknown (yet!). Guess if next arg is for this! */ + extra_arg = ((src == CONFIGVAR_CMDLINE_SHORT + || !strchr(arg, '=')) + && argv[i+1] + && !strstarts(argv[i+1], "-")); + } + finished_arg(argc, argv, &i, remove_args); + /* We turn `--foo bar` into `--foo=bar` here */ + if (extra_arg) { + configline = tal_fmt(tmpctx, "%s=%s", arg, argv[i]); + finished_arg(argc, argv, &i, remove_args); + } else { + configline = arg; + } + tal_arr_expand(&cvs, configvar_new(cvs, src, + NULL, 0, configline)); } - - parse_state = TOPLEVEL_CONFIG; - parse_implied_config_file(config_basedir, NULL, early); - parse_state = NETWORK_CONFIG; - parse_implied_config_file(config_basedir, chainparams->network_name, early); - parse_state = CMDLINE; + assert(argv[*argc] == NULL); + return cvs; } -void initial_config_opts(const tal_t *ctx, +void minimal_config_opts(const tal_t *ctx, int argc, char *argv[], - char **config_filename, - char **config_basedir, char **config_netdir, char **rpc_filename) { - options_ctx = ctx; - - /* First, they could specify a config, which specifies a lightning dir - * or a network. */ - *config_filename = NULL; - opt_register_early_arg("--conf=", opt_set_abspath, NULL, - config_filename, - "Specify configuration file"); + char *unused_filename, *unused_basedir; + + initial_config_opts(tmpctx, &argc, argv, false, + &unused_filename, + &unused_basedir, + config_netdir, + rpc_filename); + tal_steal(ctx, *config_netdir); + tal_steal(ctx, *rpc_filename); +} - /* Cmdline can also set lightning-dir. */ - *config_basedir = NULL; - opt_register_early_arg("--lightning-dir=", - opt_set_abspath, NULL, - config_basedir, - "Set base directory: network-specific subdirectory is under here"); +struct configvar **initial_config_opts(const tal_t *ctx, + int *argc, char *argv[], + bool remove_args, + char **config_filename, + char **config_basedir, + char **config_netdir, + char **rpc_filename) +{ + struct configvar **cmdline_cvs, **config_cvs, **cvs; - /* Handle --version (and exit) here too */ - opt_register_version(); + options_ctx = ctx; - opt_early_parse_incomplete(argc, argv, opt_log_stderr_exit); + /* This helps opt_usage. */ + opt_argv0 = argv[0]; - /* Now, reset and ignore --conf option from now on. */ - opt_free_table(); + /* Default chain (a global) is bitcoin. */ + chainparams = chainparams_for_network("bitcoin"); - /* This is only ever valid on cmdline */ + /* First, they could specify a config, or base dir. */ + *config_filename = NULL; opt_register_early_arg("--conf=", - opt_restricted_cmdline, NULL, + opt_set_config_filename, + /* Doesn't show if it's NULL! */ + opt_show_charp, config_filename, "Specify configuration file"); - - /* If they set --conf it can still set --lightning-dir */ - if (!*config_filename) { - opt_register_early_arg("--lightning-dir=", - opt_restricted_forceconf_only, opt_show_charp, - config_basedir, - "Set base directory: network-specific subdirectory is under here"); - } else { - opt_register_early_arg("--lightning-dir=", - opt_set_abspath, NULL, - config_basedir, - "Set base directory: network-specific subdirectory is under here"); - } - - /* Now, config file (or cmdline) can set network and lightning-dir */ - - /* We need to know network early, so we can set defaults (which normal - * options can change) and default config_netdir */ + *config_basedir = default_base_configdir(ctx); + opt_register_early_arg("--lightning-dir=", + opt_set_lightning_dir, opt_show_charp, + config_basedir, + "Set base directory: network-specific subdirectory is under here"); opt_register_early_arg("--network", opt_set_network, opt_show_network, NULL, "Select the network parameters (bitcoin, testnet," @@ -357,68 +340,85 @@ void initial_config_opts(const tal_t *ctx, opt_register_early_noarg("--mainnet", opt_set_specific_network, "bitcoin", "Alias for --network=bitcoin"); - opt_register_early_arg("--allow-deprecated-apis", - opt_set_bool_arg, opt_show_bool, - &deprecated_apis, - "Enable deprecated options, JSONRPC commands, fields, etc."); - - /* Read config file first, since cmdline must override */ - if (*config_filename) - parse_include(*config_filename, true, true, 0); - else - parse_implied_config_file(*config_basedir, NULL, true); - opt_early_parse_incomplete(argc, argv, opt_log_stderr_exit); - - /* We use a global (in common/utils.h) for the chainparams. */ - if (!chainparams) - chainparams = chainparams_for_network("bitcoin"); + opt_register_early_noarg("--regtest", + opt_set_specific_network, "regtest", + "Alias for --network=regtest"); + /* Handle --version (and exit) here too */ + opt_register_version(); + + /* For convenience, we set deprecated_apis and rpc_filename now, too */ + clnopt_witharg("--allow-deprecated-apis", + OPT_EARLY|OPT_SHOWBOOL, + opt_set_bool_arg, opt_show_bool, + &deprecated_apis, + "Enable deprecated options, JSONRPC commands, fields, etc."); - if (!*config_basedir) - *config_basedir = default_base_configdir(ctx); + /* Allow them to override rpc-file too. */ + *rpc_filename = default_rpcfile(ctx); + opt_register_early_arg("--rpc-file", opt_set_talstr, opt_show_charp, + rpc_filename, + "Set JSON-RPC socket (or /dev/tty)"); + + cmdline_cvs = gather_cmdline_args(tmpctx, argc, argv, remove_args); + parse_configvars(cmdline_cvs, true, false); + + /* Base default or direct config can set network */ + if (*config_filename) { + config_cvs = gather_file_configvars(NULL, + CONFIGVAR_EXPLICIT_CONF, + *config_filename, true, 0); + } else { + struct configvar **base_cvs, **net_cvs; + char *dir = path_join(tmpctx, take(path_cwd(NULL)), *config_basedir); + /* Optional: .lightning/config */ + base_cvs = gather_file_configvars(tmpctx, + CONFIGVAR_BASE_CONF, + path_join(tmpctx, dir, "config"), + false, 0); + /* This might set network! */ + parse_configvars(configvar_join(tmpctx, base_cvs, cmdline_cvs), + true, false); + + /* Now, we can get network config */ + dir = path_join(tmpctx, dir, chainparams->network_name); + net_cvs = gather_file_configvars(tmpctx, + CONFIGVAR_NETWORK_CONF, + path_join(tmpctx, dir, "config"), + false, 0); + config_cvs = configvar_join(NULL, take(base_cvs), take(net_cvs)); + } + cvs = configvar_join(ctx, take(config_cvs), cmdline_cvs); + + /* This will be called again, once caller has added their own + * early vars! */ + parse_configvars_early(cvs); *config_netdir = path_join(NULL, *config_basedir, chainparams->network_name); /* Make sure it's absolute */ *config_netdir = path_join(ctx, take(path_cwd(NULL)), take(*config_netdir)); + return cvs; +} - /* Now, reset and ignore those options from now on. */ - opt_free_table(); - - opt_register_early_arg("--conf=", - opt_restricted_cmdline, NULL, - config_filename, - "Specify configuration file"); +void parse_configvars_early(struct configvar **cvs) +{ + parse_configvars(cvs, true, false); +} - /* This is never in a default config file (since we used the defaults to find it!). */ - opt_register_early_arg("--lightning-dir=", - opt_restricted_forceconf_only, opt_show_charp, - config_basedir, - "Set base directory: network-specific subdirectory is under here"); - opt_register_early_arg("--network", - opt_restricted_toplevel, opt_show_network, - NULL, - "Select the network parameters (bitcoin, testnet," - " signet, regtest, litecoin or litecoin-testnet)"); - opt_register_early_noarg("--mainnet", - opt_restricted_toplevel_noarg, NULL, - "Alias for --network=bitcoin"); - opt_register_early_noarg("--testnet", - opt_restricted_toplevel_noarg, NULL, - "Alias for --network=testnet"); - opt_register_early_noarg("--signet", - opt_restricted_toplevel_noarg, NULL, - "Alias for --network=signet"); +void parse_configvars_final(struct configvar **cvs, + bool full_knowledge) +{ + parse_configvars(cvs, false, full_knowledge); + configvar_finalize_overrides(cvs); +} - /* They can set this later, it's just less effective. */ - opt_register_early_arg("--allow-deprecated-apis", - opt_set_bool_arg, opt_show_bool, - &deprecated_apis, - "Enable deprecated options, JSONRPC commands, fields, etc."); +bool is_restricted_ignored(const void *fn) +{ + return fn == opt_set_specific_network; +} - /* Set this up for when they parse cmdline proper. */ - *rpc_filename = default_rpcfile(ctx); - opt_register_arg("--rpc-file", opt_set_talstr, opt_show_charp, - rpc_filename, - "Set JSON-RPC socket (or /dev/tty)"); +bool is_restricted_print_if_nonnull(const void *fn) +{ + return fn == opt_set_config_filename; } diff --git a/common/configdir.h b/common/configdir.h index 1f2d713d2299..d50a0d04773d 100644 --- a/common/configdir.h +++ b/common/configdir.h @@ -7,26 +7,37 @@ * them early. */ extern bool deprecated_apis; +/* Unless overridden, we exit with status 1 when option parsing fails */ +extern int opt_exitcode; + /* Helper for options which are tal() strings. */ char *opt_set_talstr(const char *arg, char **p); /* Initial options setup */ void setup_option_allocators(void); -/* Parse minimal config options and files */ -void initial_config_opts(const tal_t *ctx, +/* Minimal config parsing for tools: use opt_early_parse/opt_parse after */ +void minimal_config_opts(const tal_t *ctx, int argc, char *argv[], - char **config_filename, - char **config_basedir, char **config_netdir, char **rpc_filename); -/* If they specify --conf, we just read that. - * Otherwise, we read basedir/config (toplevel), and basedir//config - * (network-level) */ -void parse_config_files(const char *config_filename, - const char *config_basedir, - bool early); +/* Parse initial config options and files */ +struct configvar **initial_config_opts(const tal_t *ctx, + int *argc, char *argv[], + bool remove_args, + char **config_filename, + char **config_basedir, + char **config_netdir, + char **rpc_filename); + +/* This is called before we know all the options. */ +void parse_configvars_early(struct configvar **cvs); + +/* This is called once, after we know all the options (if full_knowledge + * is false, ignore unknown non-cmdline options). */ +void parse_configvars_final(struct configvar **cvs, + bool full_knowledge); /* For listconfigs to detect. */ bool is_restricted_ignored(const void *fn); diff --git a/common/configvar.c b/common/configvar.c new file mode 100644 index 000000000000..c58d840bf854 --- /dev/null +++ b/common/configvar.c @@ -0,0 +1,231 @@ +#include "config.h" +#include +#include +#include +#include +#include + +struct configvar *configvar_new(const tal_t *ctx, + enum configvar_src src, + const char *file, + size_t linenum, + const char *configline) +{ + struct configvar *cv = tal(ctx, struct configvar); + if (file) + cv->file = tal_strdup(cv, file); + else + cv->file = NULL; + cv->src = src; + cv->linenum = linenum; + cv->configline = tal_strdup(cv, configline); + cv->overridden = false; + cv->optvar = NULL; + /* We fill in cv->optvar and cv->optarg when parsing! */ + return cv; +} + +const struct opt_table *configvar_unparsed(struct configvar *cv) +{ + const struct opt_table *ot; + + if (cv->src == CONFIGVAR_CMDLINE_SHORT) { + ot = opt_find_short(cv->configline[0]); + cv->optarg = NULL; + } else { + ot = opt_find_long(cv->configline, &cv->optarg); + } + if (!ot) + return NULL; + + /* We get called multiple times, but we're expected to always + * finish the cv vars, even if they're added at the last minute + * on the cmdline, so we check this is only done once, and we + * do it even if we're not going to use it now. */ + if (!cv->optvar) { + /* optvar is up to the = (i.e. one char before optarg) */ + if (!cv->optarg) + cv->optvar = cv->configline; + else + cv->optvar = tal_strndup(cv, cv->configline, + cv->optarg - cv->configline - 1); + } + return ot; +} + +const char *configvar_parse(struct configvar *cv, + bool early, + bool full_knowledge, + bool developer) +{ + const struct opt_table *ot; + + ot = configvar_unparsed(cv); + if (!ot) { + /* Do we ignore unknown entries? */ + if (!full_knowledge) + return NULL; + return "unknown option"; + } + + if ((ot->type & OPT_DEV) && !developer) + return "requires DEVELOPER"; + + /* If we're early and we want late, or vv, ignore. */ + if (!!(ot->type & OPT_EARLY) != early) + return NULL; + + if (ot->type & OPT_NOARG) { + /* MULTI doesn't make sense with single args */ + assert(!(ot->type & OPT_MULTI)); + if (cv->optarg) + return "doesn't allow an argument"; + return ot->cb(ot->u.arg); + } else { + if (!cv->optarg) + return "requires an argument"; + return ot->cb_arg(cv->optarg, ot->u.arg); + } +} + +/* This is O(N^2) but nobody cares */ +void configvar_finalize_overrides(struct configvar **cvs) +{ + /* Map to options: two different names can be the same option, + * given aliases! */ + const struct opt_table **opts; + + opts = tal_arr(tmpctx, const struct opt_table *, tal_count(cvs)); + for (size_t i = 0; i < tal_count(cvs); i++) { + opts[i] = opt_find_long(cvs[i]->optvar, NULL); + /* If you're allowed multiple, they don't override */ + if (opts[i]->type & OPT_MULTI) + continue; + for (size_t j = 0; j < i; j++) { + if (opts[j] == opts[i]) + cvs[j]->overridden = true; + } + } +} + +void configvar_remove(struct configvar ***cvs, + const char *name, + enum configvar_src src, + const char *optarg) +{ + /* We remove all from this source, potentially restoring an overridden */ + ssize_t prev = -1; + bool removed; + + removed = false; + for (size_t i = 0; i < tal_count(*cvs); i++) { + /* This can happen if plugin fails during startup! */ + if ((*cvs)[i]->optvar == NULL) + continue; + if (!streq((*cvs)[i]->optvar, name)) + continue; + if (optarg && !streq((*cvs)[i]->optarg, optarg)) + continue; + + if ((*cvs)[i]->src == src) { + tal_free((*cvs)[i]); + tal_arr_remove(cvs, i); + i--; + removed = true; + continue; + } + /* Wrong type, correct name. */ + prev = i; + } + + /* Unmark prev if we removed overriding ones. If it's multi, + * this is a noop. */ + if (removed && prev != -1) + (*cvs)[prev]->overridden = false; +} + +struct configvar *configvar_dup(const tal_t *ctx, const struct configvar *cv) +{ + struct configvar *ret; + + if (taken(cv)) + return tal_steal(ctx, cast_const(struct configvar *, cv)); + + ret = tal_dup(ctx, struct configvar, cv); + if (ret->file) + ret->file = tal_strdup(ret, ret->file); + if (ret->configline) + ret->configline = tal_strdup(ret, ret->configline); + if (ret->optvar) { + ret->optvar = tal_strdup(ret, ret->optvar); + /* Optarg, if non-NULL, points into cmdline! */ + if (ret->optarg) { + size_t off = cv->optarg - cv->configline; + assert(off < strlen(cv->configline)); + ret->optarg = ret->configline + off; + } + } + return ret; +} + +struct configvar **configvar_join(const tal_t *ctx, + struct configvar **first, + struct configvar **second) +{ + struct configvar **cvs; + size_t n = tal_count(first); + + if (taken(first)) { + cvs = tal_steal(ctx, first); + tal_resize(&cvs, n + tal_count(second)); + } else { + cvs = tal_arr(ctx, struct configvar *, n + tal_count(second)); + for (size_t i = 0; i < n; i++) { + cvs[i] = configvar_dup(cvs, first[i]); + } + } + if (taken(second)) { + for (size_t i = 0; i < tal_count(second); i++) + cvs[n + i] = tal_steal(cvs, second[i]); + tal_free(second); + } else { + for (size_t i = 0; i < tal_count(second); i++) + cvs[n + i] = configvar_dup(cvs, second[i]); + } + + return cvs; +} + +static struct configvar *configvar_iter(struct configvar **cvs, + const char **names, + const struct configvar *firstcv) +{ + for (size_t i = 0; i < tal_count(cvs); i++) { + /* Wait until we reach firstcv, if any */ + if (firstcv) { + if (cvs[i] == firstcv) + firstcv = NULL; + continue; + } + for (size_t j = 0; j < tal_count(names); j++) { + /* In case we iterate before initialization! */ + if (!cvs[i]->optvar) + continue; + if (streq(cvs[i]->optvar, names[j]) && !cvs[i]->overridden) + return cvs[i]; + } + } + return NULL; +} + +struct configvar *configvar_first(struct configvar **cvs, const char **names) +{ + return configvar_iter(cvs, names, NULL); +} + +struct configvar *configvar_next(struct configvar **cvs, + const struct configvar *cv, + const char **names) +{ + return configvar_iter(cvs, names, cv); +} diff --git a/common/configvar.h b/common/configvar.h new file mode 100644 index 000000000000..dcfe5d3ace09 --- /dev/null +++ b/common/configvar.h @@ -0,0 +1,185 @@ +#ifndef LIGHTNING_COMMON_CONFIGVAR_H +#define LIGHTNING_COMMON_CONFIGVAR_H +#include "config.h" +#include +#include +#include + +/* There are five possible sources of config options: + * 1. The cmdline (and the cmdline, but it's a short option!) + * 2. An explicitly named config (--conf=) (and its includes) + * 3. An implied config (~/.lightning/config) (and includes) + * 4. A network config ((~/.lightning//config) (and includes) + * 5. A plugin start parameter. + * + * Turns out we care: you can't set network in a network config for + * example. + */ +enum configvar_src { + CONFIGVAR_CMDLINE, + CONFIGVAR_CMDLINE_SHORT, + CONFIGVAR_EXPLICIT_CONF, + CONFIGVAR_BASE_CONF, + CONFIGVAR_NETWORK_CONF, + CONFIGVAR_PLUGIN_START, +}; + +/* This represents the configuration variables specified; they are + * matched with ccan/option's opt_table which contains the + * available options. */ +struct configvar { + /* NULL if CONFIGVAR_CMDLINE* or CONFIGVAR_PLUGIN_START */ + const char *file; + /* 1-based line number (unused if !file) */ + u32 linenum; + /* Where did we get this from? */ + enum configvar_src src; + /* Never NULL, the whole line */ + const char *configline; + + /* These are filled in by configvar_parse */ + /* The variable name (without any =) */ + const char *optvar; + /* NULL for no-arg options, otherwise points after =. */ + const char *optarg; + /* Was this overridden by a following option? */ + bool overridden; +}; + +/* Set if multiple options accumulate (for listconfigs) */ +#define OPT_MULTI (1 << OPT_USER_START) +/* Set if developer-only */ +#define OPT_DEV (1 << (OPT_USER_START+1)) +/* Doesn't return, so don't show in listconfigs */ +#define OPT_EXITS (1 << (OPT_USER_START+2)) +/* listconfigs should treat as a literal number */ +#define OPT_SHOWINT (1 << (OPT_USER_START+3)) +/* listconfigs should treat as a literal msat number */ +#define OPT_SHOWMSATS (1 << (OPT_USER_START+4)) +/* listconfigs should treat as a literal boolean `true` or `false` */ +#define OPT_SHOWBOOL (1 << (OPT_USER_START+5)) + +/* Use this instead of opt_register_*_arg if you want OPT_* from above */ +#define clnopt_witharg(names, type, cb, show, arg, desc) \ + _opt_register((names), \ + OPT_CB_ARG((cb), (type), (show), (arg)), \ + (arg), (desc)) + +#define clnopt_noarg(names, type, cb, arg, desc) \ + _opt_register((names), \ + OPT_CB_NOARG((cb), (type), (arg)), \ + (arg), (desc)) + +/** + * configvar_new: allocate a fresh configvar + * @ctx: parent to tallocate off + * @src: where this came from + * @file: filename (or NULL if cmdline) + * @linenum: 1-based line number (or 0 for cmdline) + * @configline: literal option (for argv[], after `--`) + * + * optvar/optarg/multi/overridden are only set by configvar_parse. + */ +struct configvar *configvar_new(const tal_t *ctx, + enum configvar_src src, + const char *file TAKES, + size_t linenum, + const char *configline TAKES) + NON_NULL_ARGS(5); + +/** + * configvar_dup: copy a configvar + * @ctx: parent to tallocate off + * @cv: configvar to copy. + */ +struct configvar *configvar_dup(const tal_t *ctx, + const struct configvar *cv TAKES) + NON_NULL_ARGS(2); + +/** + * configvar_join: join two configvar arrays + * @ctx: parent to tallocate off + * @first: configvars to copy first + * @second: configvars to copy second. + */ +struct configvar **configvar_join(const tal_t *ctx, + struct configvar **first TAKES, + struct configvar **second TAKES); + +/** + * configvar_parse: parse this configuration variable + * @cv: the configuration setting. + * @early: if we're doing early parsing. + * @full_knowledge: error if we don't know this option. + * @developer: if we're in developer mode (allow OPT_DEV options). + * + * This returns a string if parsing failed: if early_and_incomplete is + * set, it doesn't complain about unknown options, and only parses + * OPT_EARLY options. Otherwise it parses all non-OPT_EARLY options, + * and returns an error if they don't exist. + * + * On NULL return (success), cv->optvar, cv->optarg, cv->mult are set. + */ +const char *configvar_parse(struct configvar *cv, + bool early, + bool full_knowledge, + bool developer) + NON_NULL_ARGS(1); + +/** + * configvar_unparsed: set up configuration variable, but don't parse it + * @cv: the configuration setting. + * + * This returns the opt_table which matches this configvar, if any, + * and if successful initializes cv->optvar and cv->optarg. + */ +const struct opt_table *configvar_unparsed(struct configvar *cv) + NON_NULL_ARGS(1); + +/** + * configvar_finalize_overrides: figure out which vars were overridden + * @cvs: the tal_arr of configuration settings. + * + * Any non-multi variables are overridden by successive ones. Sets + * cv->overridden for each configvar. + */ +void configvar_finalize_overrides(struct configvar **cvs); + +/** + * configvar_remove: remove the last configvar with this name if any. + * @cvs: pointer to tal_arr of configuration settings. + * @name: name to remove. + * @src: source type to remove. + * @optarg: if non-NULL, the argument to match too. + * + * We have to un-override the now-last setting, if any. + */ +void configvar_remove(struct configvar ***cvs, + const char *name, + enum configvar_src src, + const char *optarg) + NON_NULL_ARGS(1, 2); + +/** + * configvar_first: get the first non-overridden configvar of this name. + * @cvs: the tal_arr of configuration settings. + * @names: the tal_arr() of names to look for. + * + * Returns NULL if it wasn't set. + */ +struct configvar *configvar_first(struct configvar **cvs, const char **names); + +/** + * configvar_next: get the next non-overridden configvar of same name. + * @cvs: the tal_arr of configuration settings. + * @prev: the non-NULL return from configvar_first/configvar_next + * @names: the tal_arr() of names to look for. + * + * This can only return non-NULL for OPT_MULTI options which are actually + * specified multiple times. + */ +struct configvar *configvar_next(struct configvar **cvs, + const struct configvar *prev, + const char **names); + +#endif /* LIGHTNING_COMMON_CONFIGVAR_H */ diff --git a/common/daemon.c b/common/daemon.c index 83b0ff12af70..e8f40f5340ad 100644 --- a/common/daemon.c +++ b/common/daemon.c @@ -38,6 +38,35 @@ void send_backtrace(const char *why) backtrace_full(backtrace_state, 0, backtrace_status, NULL, NULL); } +static void extract_symname(void *data, uintptr_t pc, + const char *symname, + uintptr_t symval, + uintptr_t symsize) +{ + const char **ret = data; + + /* ret is context to alloc off, and value to set */ + if (symname) + *ret = tal_strdup(*ret, symname); + else + *ret = NULL; +} + +const char *backtrace_symname(const tal_t *ctx, const void *addr) +{ + const char *ret = ctx; + if (!backtrace_state) + return tal_fmt(ctx, "%p (backtrace disabled)", addr); + + if (!backtrace_syminfo(backtrace_state, (uintptr_t)addr, + extract_symname, NULL, &ret)) + ret = NULL; + + if (ret) + return ret; + return tal_fmt(ctx, "%p", addr); +} + static void crashdump(int sig) { char why[100]; @@ -71,6 +100,11 @@ static void crashlog_activate(void) void send_backtrace(const char *why) { } + +const char *backtrace_symname(const tal_t *ctx, const void *addr) +{ + return "unknown (backtrace unsupported)"; +} #endif int daemon_poll(struct pollfd *fds, nfds_t nfds, int timeout) diff --git a/common/daemon.h b/common/daemon.h index b1703685d1aa..2db8cf4376cf 100644 --- a/common/daemon.h +++ b/common/daemon.h @@ -1,6 +1,7 @@ #ifndef LIGHTNING_COMMON_DAEMON_H #define LIGHTNING_COMMON_DAEMON_H #include "config.h" +#include #include /* Common setup for all daemons */ @@ -14,6 +15,9 @@ int daemon_poll(struct pollfd *fds, nfds_t nfds, int timeout); /* Print a backtrace to stderr, and via backtrace_print */ void send_backtrace(const char *why); +/* Try to extract a name for this function/var/etc */ +const char *backtrace_symname(const tal_t *ctx, const void *addr); + /* Shutdown for a valgrind-clean exit (frees everything) */ void daemon_shutdown(void); diff --git a/common/features.c b/common/features.c index 2a090f1e80f9..8e0918db117c 100644 --- a/common/features.c +++ b/common/features.c @@ -136,6 +136,12 @@ static const struct feature_style feature_styles[] = { [NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT, [BOLT11_FEATURE] = FEATURE_DONT_REPRESENT, [CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT } }, + { OPT_WANT_PEER_BACKUP_STORAGE, + .copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT, + [NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT } }, + { OPT_PROVIDE_PEER_BACKUP_STORAGE, + .copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT, + [NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT } }, }; struct dependency { @@ -168,13 +174,7 @@ static const struct dependency feature_deps[] = { * `option_anchors_zero_fee_htlc_tx` | ... | ... | `option_static_remotekey` */ { OPT_ANCHORS_ZERO_FEE_HTLC_TX, OPT_STATIC_REMOTEKEY }, - /* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #9: - * Name | Description | Context | Dependencies | - * ... - * `option_dual_fund` | ... | ... | `option_anchor_outputs` - */ - { OPT_DUAL_FUND, OPT_ANCHOR_OUTPUTS }, - /* BOLT-route-blinding #9: + /* BOLT #9: * Name | Description | Context | Dependencies | * ... * `option_route_blinding` | ... | ... | `var_onion_optin` @@ -456,8 +456,8 @@ const char *feature_name(const tal_t *ctx, size_t f) "option_quiesce", /* https://github.com/lightning/bolts/pull/869 */ NULL, "option_onion_messages", /* https://github.com/lightning/bolts/pull/759 */ - "option_want_peer_backup", /* 40/41 */ /* https://github.com/lightning/bolts/pull/881 */ - "option_provide_peer_backup", /* https://github.com/lightning/bolts/pull/881 */ + "option_want_peer_backup_storage", /* 40/41 */ /* https://github.com/lightning/bolts/pull/881/files */ + "option_provide_peer_backup_storage", /* https://github.com/lightning/bolts/pull/881/files */ "option_channel_type", "option_scid_alias", /* https://github.com/lightning/bolts/pull/910 */ "option_payment_metadata", diff --git a/common/features.h b/common/features.h index a862bafe1c53..768cd0f68f3a 100644 --- a/common/features.h +++ b/common/features.h @@ -15,7 +15,6 @@ enum feature_place { BOLT12_INVOICE_FEATURE, }; #define NUM_FEATURE_PLACE (BOLT12_INVOICE_FEATURE+1) - extern const char *feature_place_names[NUM_FEATURE_PLACE]; /* The complete set of features for all contexts */ @@ -115,6 +114,7 @@ struct feature_set *feature_set_dup(const tal_t *ctx, * | 18/19 | `option_support_large_channel` |... IN ... * | 20/21 | `option_anchor_outputs` |... IN ... * | 22/23 | `option_anchors_zero_fee_htlc_tx` |... IN ... + * | 24/25 | `option_route_blinding` |...IN9 ... * | 26/27 | `option_shutdown_anysegwit` |... IN ... * | 44/45 | `option_channel_type` |... IN ... * | 48/49 | `option_payment_metadata` |... 9 ... @@ -131,15 +131,11 @@ struct feature_set *feature_set_dup(const tal_t *ctx, #define OPT_LARGE_CHANNELS 18 #define OPT_ANCHOR_OUTPUTS 20 #define OPT_ANCHORS_ZERO_FEE_HTLC_TX 22 +#define OPT_ROUTE_BLINDING 24 #define OPT_SHUTDOWN_ANYSEGWIT 26 #define OPT_CHANNEL_TYPE 44 #define OPT_PAYMENT_METADATA 48 -/* BOLT-route-blinding #9: - * | 24/25 | `option_route_blinding` | Node supports blinded paths | IN9 | `var_onion_optin` | ... - */ -#define OPT_ROUTE_BLINDING 24 - /* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #9: * | 28/29 | `option_dual_fund` | ... IN9 ... */ @@ -165,4 +161,12 @@ struct feature_set *feature_set_dup(const tal_t *ctx, #define OPT_SHUTDOWN_WRONG_FUNDING 104 +/* BOLT-peer-storage #9: + * + * | 40/41 | `want_peer_backup_storage` | Want to use other nodes to store encrypted backup data | IN ... + * | 42/43 | `provide_peer_backup_storage` | Can store other nodes' encrypted backup data | IN ... + */ +#define OPT_WANT_PEER_BACKUP_STORAGE 40 +#define OPT_PROVIDE_PEER_BACKUP_STORAGE 42 + #endif /* LIGHTNING_COMMON_FEATURES_H */ diff --git a/common/gossip_constants.h b/common/gossip_constants.h index c407f302381e..ebfa8ed58217 100644 --- a/common/gossip_constants.h +++ b/common/gossip_constants.h @@ -3,11 +3,8 @@ #include "config.h" #include -/* BOLT #4: - * - * - a 1300-byte `hop_payloads` consisting of multiple, variable length, - * `hop_payload` payloads or up to 20 fixed sized legacy `hop_data` payloads. - */ +/* FIXME: This is a legacy concept, which should be eliminated now we have + * only onion tlv payloads. */ #define ROUTING_MAX_HOPS 20 /* BOLT #7: diff --git a/common/gossmap.c b/common/gossmap.c index c7e2d348b678..a1f70eda8f6b 100644 --- a/common/gossmap.c +++ b/common/gossmap.c @@ -582,8 +582,8 @@ static void node_announcement(struct gossmap *map, size_t nann_off) feature_len = map_be16(map, nann_off + feature_len_off); map_nodeid(map, nann_off + feature_len_off + 2 + feature_len + 4, &id); - n = gossmap_find_node(map, &id); - n->nann_off = nann_off; + if ((n = gossmap_find_node(map, &id))) + n->nann_off = nann_off; } static void reopen_store(struct gossmap *map, size_t ended_off) @@ -808,7 +808,9 @@ bool gossmap_local_addchan(struct gossmap_localmods *localmods, be16 = cpu_to_be16(tal_bytelen(features)); memcpy(localmods->local + off, &be16, sizeof(be16)); off += sizeof(be16); - memcpy(localmods->local + off, features, tal_bytelen(features)); + /* Damn you, C committee! */ + if (features) + memcpy(localmods->local + off, features, tal_bytelen(features)); off += tal_bytelen(features); /* Skip chain_hash */ diff --git a/common/hsm_version.h b/common/hsm_version.h index 9a67b3c3978d..5c5c22af01c9 100644 --- a/common/hsm_version.h +++ b/common/hsm_version.h @@ -5,13 +5,15 @@ /* We give a maximum and minimum compatibility version to HSM, to allow * some API adaptation. */ -/* wire/hsmd_wire.csv contents version: - * 409cffa355ab6cc76bd298910adca9936a68223267ddc4815ba16aeac5d0acc3 +/* wire/hsmd_wire.csv contents by version: + * v1: 409cffa355ab6cc76bd298910adca9936a68223267ddc4815ba16aeac5d0acc3 + * v2: dd89bf9323dff42200003fb864abb6608f3aa645b636fdae3ec81d804ac05196 + * v3: edd3d288fc88a5470adc2f99abcbfe4d4af29fae0c7a80b4226f28810a815524 + * v3 without v1: 3f813898f7de490e9126ab817e1c9a29af79c0413d5e37068acedce3ea7b5429 + * v4: 41a730986c51b930e2d8d12b3169d24966c2004e08d424bdda310edbbde5ba70 + * v4 with check_pubkey: 48b3992745aa3c6ab6ce5cdaee9082cb7d70017f523d322015e9710bf49fd193 + * v4 with sign_any_penalty_to_us: ead7963185194a515d1f14d2c44401392575299d68ce9a13d8a12baff3cf4f35 */ -#define HSM_MIN_VERSION 1 - -/* wire/hsmd_wire.csv contents version: - * edd3d288fc88a5470adc2f99abcbfe4d4af29fae0c7a80b4226f28810a815524 - */ -#define HSM_MAX_VERSION 3 +#define HSM_MIN_VERSION 3 +#define HSM_MAX_VERSION 4 #endif /* LIGHTNING_COMMON_HSM_VERSION_H */ diff --git a/common/htlc_tx.c b/common/htlc_tx.c index 5be4b47f2ba2..7427b2e152f4 100644 --- a/common/htlc_tx.c +++ b/common/htlc_tx.c @@ -4,24 +4,21 @@ #include #include -static struct bitcoin_tx *htlc_tx(const tal_t *ctx, - const struct chainparams *chainparams, - const struct bitcoin_outpoint *commit, - const u8 *commit_wscript, - struct amount_msat msat, - u16 to_self_delay, - const struct pubkey *revocation_pubkey, - const struct pubkey *local_delayedkey, - struct amount_sat htlc_fee, - u32 locktime, - bool option_anchor_outputs) +/* Low-level tx creator: used when onchaind has done most of the work! */ +struct bitcoin_tx *htlc_tx(const tal_t *ctx, + const struct chainparams *chainparams, + const struct bitcoin_outpoint *commit, + const u8 *commit_wscript, + struct amount_sat amount, + const u8 *htlc_tx_wscript, + struct amount_sat htlc_fee, + u32 locktime, + bool option_anchor_outputs) { /* BOLT #3: * * locktime: `0` for HTLC-success, `cltv_expiry` for HTLC-timeout */ struct bitcoin_tx *tx = bitcoin_tx(ctx, chainparams, 1, 1, locktime); - u8 *wscript; - struct amount_sat amount; /* BOLT #3: * @@ -45,7 +42,6 @@ static struct bitcoin_tx *htlc_tx(const tal_t *ctx, * transaction * * `txin[0]` sequence: `0` (set to `1` for `option_anchors`) */ - amount = amount_msat_to_sat_round_down(msat); bitcoin_tx_add_input(tx, commit, option_anchor_outputs ? 1 : 0, NULL, amount, NULL, commit_wscript); @@ -59,18 +55,14 @@ static struct bitcoin_tx *htlc_tx(const tal_t *ctx, * below */ if (!amount_sat_sub(&amount, amount, htlc_fee)) - abort(); + return tal_free(tx); - wscript = bitcoin_wscript_htlc_tx(tx, to_self_delay, revocation_pubkey, - local_delayedkey); - bitcoin_tx_add_output(tx, scriptpubkey_p2wsh(tmpctx, wscript), - wscript, amount); + bitcoin_tx_add_output(tx, scriptpubkey_p2wsh(tmpctx, htlc_tx_wscript), + htlc_tx_wscript, amount); bitcoin_tx_finalize(tx); assert(bitcoin_tx_check(tx)); - tal_free(wscript); - return tx; } @@ -84,14 +76,19 @@ struct bitcoin_tx *htlc_success_tx(const tal_t *ctx, const struct keyset *keyset, bool option_anchor_outputs) { + const u8 *htlc_wscript; + + htlc_wscript = bitcoin_wscript_htlc_tx(tmpctx, + to_self_delay, + &keyset->self_revocation_key, + &keyset->self_delayed_payment_key); /* BOLT #3: * * locktime: `0` for HTLC-success, `cltv_expiry` for HTLC-timeout */ return htlc_tx(ctx, chainparams, commit, - commit_wscript, htlc_msatoshi, - to_self_delay, - &keyset->self_revocation_key, - &keyset->self_delayed_payment_key, + commit_wscript, + amount_msat_to_sat_round_down(htlc_msatoshi), + htlc_wscript, htlc_success_fee(feerate_per_kw, option_anchor_outputs), 0, @@ -137,13 +134,19 @@ struct bitcoin_tx *htlc_timeout_tx(const tal_t *ctx, const struct keyset *keyset, bool option_anchor_outputs) { + const u8 *htlc_wscript; + + htlc_wscript = bitcoin_wscript_htlc_tx(tmpctx, + to_self_delay, + &keyset->self_revocation_key, + &keyset->self_delayed_payment_key); /* BOLT #3: * * locktime: `0` for HTLC-success, `cltv_expiry` for HTLC-timeout */ return htlc_tx(ctx, chainparams, commit, - commit_wscript, htlc_msatoshi, to_self_delay, - &keyset->self_revocation_key, - &keyset->self_delayed_payment_key, + commit_wscript, + amount_msat_to_sat_round_down(htlc_msatoshi), + htlc_wscript, htlc_timeout_fee(feerate_per_kw, option_anchor_outputs), cltv_expiry, diff --git a/common/htlc_tx.h b/common/htlc_tx.h index 188b6d34db38..f58608376456 100644 --- a/common/htlc_tx.h +++ b/common/htlc_tx.h @@ -115,4 +115,14 @@ u8 *htlc_offered_wscript(const tal_t *ctx, const struct keyset *keyset, bool option_anchor_outputs); +/* Low-level HTLC tx creator */ +struct bitcoin_tx *htlc_tx(const tal_t *ctx, + const struct chainparams *chainparams, + const struct bitcoin_outpoint *commit, + const u8 *commit_wscript, + struct amount_sat amount, + const u8 *htlc_tx_wscript, + struct amount_sat htlc_fee, + u32 locktime, + bool option_anchor_outputs); #endif /* LIGHTNING_COMMON_HTLC_TX_H */ diff --git a/common/initial_commit_tx.c b/common/initial_commit_tx.c index 97afedb15059..5d6ade5b37d1 100644 --- a/common/initial_commit_tx.c +++ b/common/initial_commit_tx.c @@ -247,7 +247,7 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, amount = amount_msat_to_sat_round_down(other_pay); if (option_anchor_outputs) { - redeem = anchor_to_remote_redeem(tmpctx, + redeem = bitcoin_wscript_to_remote_anchored(tmpctx, &keyset->other_payment_key, (!side) == lessor ? csv_lock : 1); scriptpubkey = scriptpubkey_p2wsh(tmpctx, redeem); diff --git a/common/initial_commit_tx.h b/common/initial_commit_tx.h index 7a5edf0f226f..4e7e39b3b106 100644 --- a/common/initial_commit_tx.h +++ b/common/initial_commit_tx.h @@ -28,6 +28,7 @@ static inline size_t commit_tx_base_weight(size_t num_untrimmed_htlcs, bool option_anchor_outputs) { size_t weight; + size_t num_outputs; /* BOLT #3: * @@ -35,11 +36,13 @@ static inline size_t commit_tx_base_weight(size_t num_untrimmed_htlcs, * - MUST be calculated to match: * 1. Start with `weight` = 724 (1124 if `option_anchors` applies). */ - if (option_anchor_outputs) + if (option_anchor_outputs) { weight = 1124; - else + num_outputs = 4; + } else { weight = 724; - + num_outputs = 2; + } /* BOLT #3: * * 2. For each committed HTLC, if that output is not trimmed as @@ -47,9 +50,10 @@ static inline size_t commit_tx_base_weight(size_t num_untrimmed_htlcs, * to `weight`. */ weight += 172 * num_untrimmed_htlcs; + num_outputs += num_untrimmed_htlcs; /* Extra fields for Elements */ - weight += elements_tx_overhead(chainparams, 1, 1); + weight += elements_tx_overhead(chainparams, 1, num_outputs); return weight; } diff --git a/common/interactivetx.c b/common/interactivetx.c index 76b6de927678..ed8db0984a89 100644 --- a/common/interactivetx.c +++ b/common/interactivetx.c @@ -196,9 +196,7 @@ static u8 *read_next_msg(const tal_t *ctx, case WIRE_PING: case WIRE_PONG: case WIRE_SHUTDOWN: -#if EXPERIMENTAL_FEATURES case WIRE_STFU: -#endif *error = tal_fmt(ctx, "Received invalid message from peer: %d", t); return NULL; @@ -715,11 +713,9 @@ char *process_interactivetx_updates(const tal_t *ctx, case WIRE_REPLY_SHORT_CHANNEL_IDS_END: case WIRE_PING: case WIRE_PONG: -#if EXPERIMENTAL_FEATURES + case WIRE_STFU: case WIRE_SPLICE: case WIRE_SPLICE_ACK: - case WIRE_STFU: -#endif return tal_fmt(ctx, "Unexpected wire message %s", tal_hex(ctx, msg)); } diff --git a/common/json_parse.c b/common/json_parse.c index e4776d87b5f1..dc89a41a5539 100644 --- a/common/json_parse.c +++ b/common/json_parse.c @@ -193,6 +193,9 @@ static const char *handle_percent(const char *buffer, void **p; p = va_arg(*ap, void **); talfmt = va_arg(*ap, void *(*)(void *, const char *, const jsmntok_t *)); + /* If we're skipping this, don't call fmt! */ + if (!tok) + return NULL; *p = talfmt(ctx, buffer, tok); if (*p != NULL) return NULL; @@ -202,6 +205,9 @@ static const char *handle_percent(const char *buffer, p = va_arg(*ap, void *); fmt = va_arg(*ap, bool (*)(const char *, const jsmntok_t *, void *)); + /* If we're skipping this, don't call fmt! */ + if (!tok) + return NULL; if (fmt(buffer, tok, p)) return NULL; } @@ -215,7 +221,8 @@ static const char *handle_percent(const char *buffer, /* GUIDE := OBJ | ARRAY | '%' * OBJ := '{' FIELDLIST '}' * FIELDLIST := FIELD [',' FIELD]* - * FIELD := LITERAL ':' FIELDVAL + * FIELD := MEMBER ':' FIELDVAL + * MEMBER := LITERAL | LITERAL '?' * FIELDVAL := OBJ | ARRAY | LITERAL | '%' * ARRAY := '[' ARRLIST ']' * ARRLIST := ARRELEM [',' ARRELEM]* @@ -264,6 +271,15 @@ static void guide_must_be(const char **guide, char c) assert(actual == c); } +static bool guide_maybe_optional(const char **guide) +{ + if (**guide == '?') { + guide_consume_one(guide); + return true; + } + return false; +} + /* Recursion: return NULL on success, errmsg on fail */ static const char *parse_obj(const char *buffer, const jsmntok_t *tok, @@ -325,8 +341,8 @@ static const char *parse_fieldval(const char *buffer, /* Literal must match exactly (modulo quotes for strings) */ parse_literal(guide, &literal, &len); - if (!memeq(buffer + tok->start, tok->end - tok->start, - literal, len)) { + if (tok && !memeq(buffer + tok->start, tok->end - tok->start, + literal, len)) { return tal_fmt(tmpctx, "%.*s does not match expected %.*s", json_tok_full_len(tok), @@ -345,14 +361,20 @@ static const char *parse_field(const char *buffer, const jsmntok_t *member; size_t len; const char *memname; + bool optional; parse_literal(guide, &memname, &len); + optional = guide_maybe_optional(guide); guide_must_be(guide, ':'); - member = json_get_membern(buffer, tok, memname, len); - if (!member) { - return tal_fmt(tmpctx, "object does not have member %.*s", - (int)len, memname); + if (tok) { + member = json_get_membern(buffer, tok, memname, len); + if (!member && !optional) { + return tal_fmt(tmpctx, "object does not have member %.*s", + (int)len, memname); + } + } else { + member = NULL; } return parse_fieldval(buffer, member, guide, ap); @@ -385,7 +407,7 @@ static const char *parse_obj(const char *buffer, guide_must_be(guide, '{'); - if (tok->type != JSMN_OBJECT) { + if (tok && tok->type != JSMN_OBJECT) { return tal_fmt(tmpctx, "token is not an object: %.*s", json_tok_full_len(tok), json_tok_full(buffer, tok)); @@ -410,12 +432,16 @@ static const char *parse_arrelem(const char *buffer, parse_number(guide, &idx); guide_must_be(guide, ':'); - member = json_get_arr(tok, idx); - if (!member) { - return tal_fmt(tmpctx, "token has no index %u: %.*s", - idx, - json_tok_full_len(tok), - json_tok_full(buffer, tok)); + if (tok) { + member = json_get_arr(tok, idx); + if (!member) { + return tal_fmt(tmpctx, "token has no index %u: %.*s", + idx, + json_tok_full_len(tok), + json_tok_full(buffer, tok)); + } + } else { + member = NULL; } return parse_fieldval(buffer, member, guide, ap); @@ -448,7 +474,7 @@ static const char *parse_arr(const char *buffer, guide_must_be(guide, '['); - if (tok->type != JSMN_ARRAY) { + if (tok && tok->type != JSMN_ARRAY) { return tal_fmt(tmpctx, "token is not an array: %.*s", json_tok_full_len(tok), json_tok_full(buffer, tok)); @@ -683,7 +709,6 @@ json_to_blinded_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok) return rpath; } - bool json_tok_channel_id(const char *buffer, const jsmntok_t *tok, struct channel_id *cid) diff --git a/common/json_stream.c b/common/json_stream.c index 59c80fbaf1a6..16fd5472c7a6 100644 --- a/common/json_stream.c +++ b/common/json_stream.c @@ -95,13 +95,6 @@ static bool json_stream_still_writing(const struct json_stream *js) return js->writer != NULL; } -void json_stream_log_suppress(struct json_stream *js, const char *cmd_name) -{ - /* Really shouldn't be used for anything else */ - assert(streq(cmd_name, "getlog")); - js->log = NULL; -} - void json_stream_append(struct json_stream *js, const char *str, size_t len) { @@ -493,38 +486,54 @@ void json_add_short_channel_id(struct json_stream *response, short_channel_id_outnum(scid)); } -void json_add_address(struct json_stream *response, const char *fieldname, - const struct wireaddr *addr) +static void json_add_address_fields(struct json_stream *response, + const struct wireaddr *addr, + const char *typefield) { - json_object_start(response, fieldname); - if (addr->type == ADDR_TYPE_IPV4) { + switch (addr->type) { + case ADDR_TYPE_IPV4: { char addrstr[INET_ADDRSTRLEN]; inet_ntop(AF_INET, addr->addr, addrstr, INET_ADDRSTRLEN); - json_add_string(response, "type", "ipv4"); + json_add_string(response, typefield, "ipv4"); json_add_string(response, "address", addrstr); json_add_num(response, "port", addr->port); - } else if (addr->type == ADDR_TYPE_IPV6) { + return; + } + case ADDR_TYPE_IPV6: { char addrstr[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, addr->addr, addrstr, INET6_ADDRSTRLEN); - json_add_string(response, "type", "ipv6"); + json_add_string(response, typefield, "ipv6"); json_add_string(response, "address", addrstr); json_add_num(response, "port", addr->port); - } else if (addr->type == ADDR_TYPE_TOR_V2_REMOVED) { - json_add_string(response, "type", "torv2"); + return; + } + case ADDR_TYPE_TOR_V2_REMOVED: { + json_add_string(response, typefield, "torv2"); json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); json_add_num(response, "port", addr->port); - } else if (addr->type == ADDR_TYPE_TOR_V3) { - json_add_string(response, "type", "torv3"); + return; + } + case ADDR_TYPE_TOR_V3: { + json_add_string(response, typefield, "torv3"); json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); json_add_num(response, "port", addr->port); - } else if (addr->type == ADDR_TYPE_DNS) { - json_add_string(response, "type", "dns"); + return; + } + case ADDR_TYPE_DNS: { + json_add_string(response, typefield, "dns"); json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); json_add_num(response, "port", addr->port); - } else if (addr->type == ADDR_TYPE_WEBSOCKET) { - json_add_string(response, "type", "websocket"); - json_add_num(response, "port", addr->port); + return; + } } + abort(); +} + +void json_add_address(struct json_stream *response, const char *fieldname, + const struct wireaddr *addr) +{ + json_object_start(response, fieldname); + json_add_address_fields(response, addr, "type"); json_object_end(response); } @@ -541,8 +550,13 @@ void json_add_address_internal(struct json_stream *response, return; case ADDR_INTERNAL_ALLPROTO: json_object_start(response, fieldname); - json_add_string(response, "type", "any protocol"); - json_add_num(response, "port", addr->u.port); + if (addr->u.allproto.is_websocket) { + json_add_string(response, "type", "websocket"); + json_add_string(response, "subtype", "any protocol"); + } else { + json_add_string(response, "type", "any protocol"); + } + json_add_num(response, "port", addr->u.allproto.port); json_object_end(response); return; case ADDR_INTERNAL_AUTOTOR: @@ -565,7 +579,14 @@ void json_add_address_internal(struct json_stream *response, json_object_end(response); return; case ADDR_INTERNAL_WIREADDR: - json_add_address(response, fieldname, &addr->u.wireaddr); + json_object_start(response, fieldname); + if (addr->u.wireaddr.is_websocket) { + json_add_string(response, "type", "websocket"); + json_add_address_fields(response, &addr->u.wireaddr.wireaddr, "subtype"); + } else { + json_add_address_fields(response, &addr->u.wireaddr.wireaddr, "type"); + } + json_object_end(response); return; } abort(); @@ -589,37 +610,12 @@ void json_add_psbt(struct json_stream *stream, tal_free(psbt); } -void json_add_amount_msat_compat(struct json_stream *result, - struct amount_msat msat, - const char *rawfieldname, - const char *msatfieldname) -{ - if (deprecated_apis) - json_add_u64(result, rawfieldname, msat.millisatoshis); /* Raw: low-level helper */ - json_add_amount_msat_only(result, msatfieldname, msat); -} - -void json_add_amount_msat_only(struct json_stream *result, +void json_add_amount_msat(struct json_stream *result, const char *msatfieldname, struct amount_msat msat) { - if (!deprecated_apis) - assert(strends(msatfieldname, "_msat")); - if (deprecated_apis) - json_add_string(result, msatfieldname, - type_to_string(tmpctx, struct amount_msat, &msat)); - else - json_add_u64(result, msatfieldname, msat.millisatoshis); /* Raw: low-level helper */ -} - -void json_add_amount_sat_compat(struct json_stream *result, - struct amount_sat sat, - const char *rawfieldname, - const char *msatfieldname) -{ - if (deprecated_apis) - json_add_u64(result, rawfieldname, sat.satoshis); /* Raw: low-level helper */ - json_add_amount_sat_msat(result, msatfieldname, sat); + assert(strends(msatfieldname, "_msat")); + json_add_u64(result, msatfieldname, msat.millisatoshis); /* Raw: low-level helper */ } void json_add_amount_sat_msat(struct json_stream *result, @@ -629,23 +625,7 @@ void json_add_amount_sat_msat(struct json_stream *result, struct amount_msat msat; assert(strends(msatfieldname, "_msat")); if (amount_sat_to_msat(&msat, sat)) - json_add_amount_msat_only(result, msatfieldname, msat); -} - -/* When I noticed that we were adding "XXXmsat" fields *not* ending in _msat */ -void json_add_amount_sats_deprecated(struct json_stream *result, - const char *fieldname, - const char *msatfieldname, - struct amount_sat sat) -{ - if (deprecated_apis) { - struct amount_msat msat; - assert(!strends(fieldname, "_msat")); - if (amount_sat_to_msat(&msat, sat)) - json_add_string(result, fieldname, - take(fmt_amount_msat(NULL, msat))); - } - json_add_amount_sat_msat(result, msatfieldname, sat); + json_add_amount_msat(result, msatfieldname, msat); } void json_add_sats(struct json_stream *result, @@ -680,9 +660,9 @@ void json_add_lease_rates(struct json_stream *result, amount_sat(rates->lease_fee_base_sat)); json_add_num(result, "lease_fee_basis", rates->lease_fee_basis); json_add_num(result, "funding_weight", rates->funding_weight); - json_add_amount_msat_only(result, - "channel_fee_max_base_msat", - amount_msat(rates->channel_fee_max_base_msat)); + json_add_amount_msat(result, + "channel_fee_max_base_msat", + amount_msat(rates->channel_fee_max_base_msat)); json_add_num(result, "channel_fee_max_proportional_thousandths", rates->channel_fee_max_proportional_thousandths); } diff --git a/common/json_stream.h b/common/json_stream.h index 31c73c1ef134..8420c530bb0b 100644 --- a/common/json_stream.h +++ b/common/json_stream.h @@ -97,9 +97,6 @@ const char *json_stream_detach_filter(const tal_t *ctx, struct json_stream *js); */ void json_stream_close(struct json_stream *js, struct command *writer); -/* For low-level JSON stream access: */ -void json_stream_log_suppress(struct json_stream *js, const char *cmd_name); - /* '"fieldname" : [ ' or '[ ' if fieldname is NULL */ void json_array_start(struct json_stream *js, const char *fieldname); /* '"fieldname" : { ' or '{ ' if fieldname is NULL */ @@ -324,45 +321,18 @@ void json_add_address_internal(struct json_stream *response, const char *fieldname, const struct wireaddr_internal *addr); -/* Adds both a 'raw' number field and an 'amount_msat' field */ -void json_add_amount_msat_compat(struct json_stream *result, - struct amount_msat msat, - const char *rawfieldname, - const char *msatfieldname) - NO_NULL_ARGS; - -/* Adds both a 'raw' number field and an 'amount_msat' field */ -void json_add_amount_sat_compat(struct json_stream *result, - struct amount_sat sat, - const char *rawfieldname, - const char *msatfieldname) - NO_NULL_ARGS; - /* Adds an 'msat' field */ -void json_add_amount_msat_only(struct json_stream *result, +void json_add_amount_msat(struct json_stream *result, const char *msatfieldname, struct amount_msat msat) NO_NULL_ARGS; -/* Adds an 'msat' field */ -void json_add_amount_sat_only(struct json_stream *result, - const char *msatfieldname, - struct amount_sat sat) - NO_NULL_ARGS; - /* Adds an 'msat' field */ void json_add_amount_sat_msat(struct json_stream *result, const char *msatfieldname, struct amount_sat sat) NO_NULL_ARGS; -/* Adds an 'msat' field, and an older deprecated field. */ -void json_add_amount_sats_deprecated(struct json_stream *result, - const char *fieldname, - const char *msatfieldname, - struct amount_sat sat) - NO_NULL_ARGS; - /* This is used to create requests, *never* for output (output is always * msat!) */ void json_add_sats(struct json_stream *result, diff --git a/common/jsonrpc_errors.h b/common/jsonrpc_errors.h index 899081765ed6..6744e87d30c6 100644 --- a/common/jsonrpc_errors.h +++ b/common/jsonrpc_errors.h @@ -71,6 +71,7 @@ enum jsonrpc_errcode { /* bitcoin-cli plugin errors */ BCLI_ERROR = 500, + BCLI_NO_FEE_ESTIMATES = 501, /* Errors from `invoice` or `delinvoice` commands */ INVOICE_LABEL_ALREADY_EXISTS = 900, diff --git a/common/key_derive.c b/common/key_derive.c index bdf87d99382c..52c78ac5e9ad 100644 --- a/common/key_derive.c +++ b/common/key_derive.c @@ -248,22 +248,3 @@ bool derive_revocation_privkey(const struct secret *base_secret, #endif return true; } - - -bool bip32_pubkey(const struct ext_key *bip32_base, - struct pubkey *pubkey, u32 index) -{ - const uint32_t flags = BIP32_FLAG_KEY_PUBLIC | BIP32_FLAG_SKIP_HASH; - struct ext_key ext; - - if (index >= BIP32_INITIAL_HARDENED_CHILD) - return false; - - if (bip32_key_from_parent(bip32_base, index, flags, &ext) != WALLY_OK) - return false; - - if (!secp256k1_ec_pubkey_parse(secp256k1_ctx, &pubkey->pubkey, - ext.pub_key, sizeof(ext.pub_key))) - return false; - return true; -} diff --git a/common/key_derive.h b/common/key_derive.h index 59be4794a7f7..b078cc9261e0 100644 --- a/common/key_derive.h +++ b/common/key_derive.h @@ -28,9 +28,4 @@ bool derive_revocation_privkey(const struct secret *base_secret, const struct pubkey *basepoint, const struct pubkey *per_commitment_point, struct privkey *key); - - -struct ext_key; -bool bip32_pubkey(const struct ext_key *bip32_base, - struct pubkey *pubkey, u32 index); #endif /* LIGHTNING_COMMON_KEY_DERIVE_H */ diff --git a/common/onion_decode.c b/common/onion_decode.c index 77b78a25103b..57e78df2b23c 100644 --- a/common/onion_decode.c +++ b/common/onion_decode.c @@ -9,20 +9,20 @@ #include #include -/* BOLT-route-blinding #4: +/* BOLT #4: * - If `encrypted_recipient_data` is present: *... * - If it is not the final node: * - MUST return an error if the payload contains other tlv fields than * `encrypted_recipient_data` and `current_blinding_point`. */ -static bool check_nonfinal_tlv(const struct tlv_tlv_payload *tlv, +static bool check_nonfinal_tlv(const struct tlv_payload *tlv, u64 *failtlvtype) { for (size_t i = 0; i < tal_count(tlv->fields); i++) { switch (tlv->fields[i].numtype) { - case TLV_TLV_PAYLOAD_BLINDING_POINT: - case TLV_TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA: + case TLV_PAYLOAD_BLINDING_POINT: + case TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA: continue; } *failtlvtype = tlv->fields[i].numtype; @@ -31,7 +31,7 @@ static bool check_nonfinal_tlv(const struct tlv_tlv_payload *tlv, return true; } -/* BOLT-route-blinding #4: +/* BOLT #4: * - If `encrypted_recipient_data` is present: *... * - If it is the final node: @@ -39,16 +39,16 @@ static bool check_nonfinal_tlv(const struct tlv_tlv_payload *tlv, * `encrypted_recipient_data`, `current_blinding_point`, `amt_to_forward`, * `outgoing_cltv_value` and `total_amount_msat`. */ -static bool check_final_tlv(const struct tlv_tlv_payload *tlv, +static bool check_final_tlv(const struct tlv_payload *tlv, u64 *failtlvtype) { for (size_t i = 0; i < tal_count(tlv->fields); i++) { switch (tlv->fields[i].numtype) { - case TLV_TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA: - case TLV_TLV_PAYLOAD_BLINDING_POINT: - case TLV_TLV_PAYLOAD_AMT_TO_FORWARD: - case TLV_TLV_PAYLOAD_OUTGOING_CLTV_VALUE: - case TLV_TLV_PAYLOAD_TOTAL_AMOUNT_MSAT: + case TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA: + case TLV_PAYLOAD_BLINDING_POINT: + case TLV_PAYLOAD_AMT_TO_FORWARD: + case TLV_PAYLOAD_OUTGOING_CLTV_VALUE: + case TLV_PAYLOAD_TOTAL_AMOUNT_MSAT: continue; } *failtlvtype = tlv->fields[i].numtype; @@ -65,7 +65,7 @@ static u64 ceil_div(u64 a, u64 b) static bool handle_blinded_forward(struct onion_payload *p, struct amount_msat amount_in, u32 cltv_expiry, - const struct tlv_tlv_payload *tlv, + const struct tlv_payload *tlv, const struct tlv_encrypted_data_tlv *enc, u64 *failtlvtype) { @@ -74,14 +74,14 @@ static bool handle_blinded_forward(struct onion_payload *p, if (!check_nonfinal_tlv(tlv, failtlvtype)) return false; - /* BOLT-route-blinding #4: + /* BOLT #4: * - If it is not the final node: *... * - MUST return an error if `encrypted_recipient_data` does not * contain either `short_channel_id` or `next_node_id`. */ if (!enc->short_channel_id && !enc->next_node_id) { - *failtlvtype = TLV_TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; + *failtlvtype = TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; return false; } @@ -97,14 +97,14 @@ static bool handle_blinded_forward(struct onion_payload *p, p->total_msat = NULL; - /* BOLT-route-blinding #4: + /* BOLT #4: * - If it is not the final node: *... * - MUST return an error if `encrypted_recipient_data` does not * contain `payment_relay`. */ if (!enc->payment_relay) { - *failtlvtype = TLV_TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; + *failtlvtype = TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; return false; } @@ -118,31 +118,31 @@ static bool handle_blinded_forward(struct onion_payload *p, } static bool handle_blinded_terminal(struct onion_payload *p, - const struct tlv_tlv_payload *tlv, + const struct tlv_payload *tlv, const struct tlv_encrypted_data_tlv *enc, u64 *failtlvtype) { if (!check_final_tlv(tlv, failtlvtype)) return false; - /* BOLT-route-blinding #4: + /* BOLT #4: * - MUST return an error if `amt_to_forward`, `outgoing_cltv_value` * or `total_amount_msat` are not present. * - MUST return an error if `amt_to_forward` is below what it expects * for the payment. */ if (!tlv->amt_to_forward) { - *failtlvtype = TLV_TLV_PAYLOAD_AMT_TO_FORWARD; + *failtlvtype = TLV_PAYLOAD_AMT_TO_FORWARD; return false; } if (!tlv->outgoing_cltv_value) { - *failtlvtype = TLV_TLV_PAYLOAD_OUTGOING_CLTV_VALUE; + *failtlvtype = TLV_PAYLOAD_OUTGOING_CLTV_VALUE; return false; } if (!tlv->total_amount_msat) { - *failtlvtype = TLV_TLV_PAYLOAD_TOTAL_AMOUNT_MSAT; + *failtlvtype = TLV_PAYLOAD_TOTAL_AMOUNT_MSAT; return false; } @@ -157,7 +157,7 @@ static bool handle_blinded_terminal(struct onion_payload *p, *p->total_msat = amount_msat(*tlv->total_amount_msat); } else { /* BOLT #4: - * - if it is the final node: + * - If it is the final node: * - MUST treat `total_msat` as if it were equal to * `amt_to_forward` if it is not present. */ p->total_msat = tal_dup(p, struct amount_msat, @@ -182,7 +182,7 @@ struct onion_payload *onion_decode(const tal_t *ctx, p->final = (rs->nextcase == ONION_END); - /* BOLT-remove-legacy-onion #4: + /* BOLT #4: * 1. type: `hop_payloads` * 2. data: * * [`bigsize`:`length`] @@ -197,15 +197,15 @@ struct onion_payload *onion_decode(const tal_t *ctx, /* We do this manually so we can accept extra types, and get * error off and type. */ - p->tlv = tlv_tlv_payload_new(p); - if (!fromwire_tlv(&cursor, &max, tlvs_tlv_tlv_payload, - TLVS_ARRAY_SIZE_tlv_tlv_payload, + p->tlv = tlv_payload_new(p); + if (!fromwire_tlv(&cursor, &max, tlvs_tlv_payload, + TLVS_ARRAY_SIZE_tlv_payload, p->tlv, &p->tlv->fields, accepted_extra_tlvs, failtlvpos, failtlvtype)) { return tal_free(p); } - /* BOLT-route-blinding #4: + /* BOLT #4: * * The reader: * @@ -216,11 +216,11 @@ struct onion_payload *onion_decode(const tal_t *ctx, /* Only supported with --experimental-onion-messages! */ if (!blinding_support) { - *failtlvtype = TLV_TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; + *failtlvtype = TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; goto field_bad; } - /* BOLT-route-blinding #4: + /* BOLT #4: * * - If `blinding_point` is set in the incoming `update_add_htlc`: * - MUST return an error if `current_blinding_point` is present. @@ -231,20 +231,20 @@ struct onion_payload *onion_decode(const tal_t *ctx, */ if (blinding) { if (p->tlv->blinding_point) { - *failtlvtype = TLV_TLV_PAYLOAD_BLINDING_POINT; + *failtlvtype = TLV_PAYLOAD_BLINDING_POINT; goto field_bad; } p->blinding = tal_dup(p, struct pubkey, blinding); } else { if (!p->tlv->blinding_point) { - *failtlvtype = TLV_TLV_PAYLOAD_BLINDING_POINT; + *failtlvtype = TLV_PAYLOAD_BLINDING_POINT; goto field_bad; } p->blinding = tal_dup(p, struct pubkey, p->tlv->blinding_point); } - /* BOLT-route-blinding #4: + /* BOLT #4: * The reader: *... * - MUST return an error if `encrypted_recipient_data` does @@ -255,22 +255,22 @@ struct onion_payload *onion_decode(const tal_t *ctx, enc = decrypt_encrypted_data(tmpctx, p->blinding, &p->blinding_ss, p->tlv->encrypted_recipient_data); if (!enc) { - *failtlvtype = TLV_TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; + *failtlvtype = TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; goto field_bad; } if (enc->payment_constraints) { - /* BOLT-route-blinding #4: + /* BOLT #4: * - MUST return an error if: * - the expiry is greater than * `encrypted_recipient_data.payment_constraints.max_cltv_expiry`. */ if (cltv_expiry > enc->payment_constraints->max_cltv_expiry) { - *failtlvtype = TLV_TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; + *failtlvtype = TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; goto field_bad; } - /* BOLT-route-blinding #4: + /* BOLT #4: * - MUST return an error if: *... * - the amount is below @@ -278,12 +278,11 @@ struct onion_payload *onion_decode(const tal_t *ctx, */ if (amount_msat_less(amount_in, amount_msat(enc->payment_constraints->htlc_minimum_msat))) { - *failtlvtype = TLV_TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; + *failtlvtype = TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; goto field_bad; } - /* BOLT-route-blinding #4: - * - If `allowed_features` is present: + /* BOLT #4: * - MUST return an error if: *... * - the payment uses a feature not included in @@ -292,8 +291,10 @@ struct onion_payload *onion_decode(const tal_t *ctx, /* We don't have any features yet... */ } - /* BOLT-route-blinding #4: - * - If `allowed_features` is present: + /* BOLT #4: + * - If `allowed_features` is missing: + * - MUST process the message as if it were present and contained an + * empty array. * - MUST return an error if: * - `encrypted_recipient_data.allowed_features.features` * contains an unknown feature bit (even if it is odd). @@ -303,7 +304,7 @@ struct onion_payload *onion_decode(const tal_t *ctx, /* No features, this is easy */ if (!memeqzero(enc->allowed_features, tal_bytelen(enc->allowed_features))) { - *failtlvtype = TLV_TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; + *failtlvtype = TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; goto field_bad; } @@ -328,29 +329,30 @@ struct onion_payload *onion_decode(const tal_t *ctx, return p; } - /* BOLT-route-blinding-fix #4: + /* BOLT #4: * - Otherwise (it is not part of a blinded route): * - MUST return an error if `blinding_point` is set in the * incoming `update_add_htlc` or `current_blinding_point` * is present. */ if (blinding || p->tlv->blinding_point) { - *failtlvtype = TLV_TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; + *failtlvtype = TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA; goto field_bad; } /* BOLT #4: * - * The reader: + * - Otherwise (it is not part of a blinded route): + *... * - MUST return an error if `amt_to_forward` or * `outgoing_cltv_value` are not present. */ if (!p->tlv->amt_to_forward) { - *failtlvtype = TLV_TLV_PAYLOAD_AMT_TO_FORWARD; + *failtlvtype = TLV_PAYLOAD_AMT_TO_FORWARD; goto field_bad; } if (!p->tlv->outgoing_cltv_value) { - *failtlvtype = TLV_TLV_PAYLOAD_OUTGOING_CLTV_VALUE; + *failtlvtype = TLV_PAYLOAD_OUTGOING_CLTV_VALUE; goto field_bad; } @@ -359,14 +361,13 @@ struct onion_payload *onion_decode(const tal_t *ctx, /* BOLT #4: * - * The writer: - *... - * - For every non-final node: - * - MUST include `short_channel_id` + * - if it is not the final node: + * - MUST return an error if: + * - `short_channel_id` is not present, */ if (!p->final) { if (!p->tlv->short_channel_id) { - *failtlvtype = TLV_TLV_PAYLOAD_SHORT_CHANNEL_ID; + *failtlvtype = TLV_PAYLOAD_SHORT_CHANNEL_ID; goto field_bad; } p->forward_channel = tal_dup(p, struct short_channel_id, @@ -375,7 +376,7 @@ struct onion_payload *onion_decode(const tal_t *ctx, } else { p->forward_channel = NULL; /* BOLT #4: - * - if it is the final node: + * - If it is the final node: * - MUST treat `total_msat` as if it were equal to * `amt_to_forward` if it is not present. */ p->total_msat = tal_dup(p, struct amount_msat, diff --git a/common/onion_encode.c b/common/onion_encode.c index f5facf75ec7f..2a32c5ee5f77 100644 --- a/common/onion_encode.c +++ b/common/onion_encode.c @@ -11,20 +11,18 @@ /* BOLT #4: * - * ### `tlv_payload` format + * ### `payload` format * - * This is a more flexible format, which avoids the redundant - * `short_channel_id` field for the final node. It is formatted - * according to the Type-Length-Value format defined in [BOLT - * #1](01-messaging.md#type-length-value-format). + * This is formatted according to the Type-Length-Value format defined + * in [BOLT #1](01-messaging.md#type-length-value-format). */ static u8 *make_tlv_hop(const tal_t *ctx, - const struct tlv_tlv_payload *tlv) + const struct tlv_payload *tlv) { /* We can't have over 64k anyway */ u8 *tlvs = tal_arr(ctx, u8, 3); - towire_tlv_tlv_payload(&tlvs, tlv); + towire_tlv_payload(&tlvs, tlv); switch (bigsize_put(tlvs, tal_bytelen(tlvs) - 3)) { case 1: @@ -43,13 +41,13 @@ u8 *onion_nonfinal_hop(const tal_t *ctx, struct amount_msat forward, u32 outgoing_cltv) { - struct tlv_tlv_payload *tlv = tlv_tlv_payload_new(tmpctx); + struct tlv_payload *tlv = tlv_payload_new(tmpctx); /* BOLT #4: * - * The writer: + * The writer of `tlv_payload`: *... - * - For every node: + * - For every node outside of a blinded route: * - MUST include `amt_to_forward` and `outgoing_cltv_value`. * - For every non-final node: * - MUST include `short_channel_id` @@ -68,8 +66,8 @@ u8 *onion_final_hop(const tal_t *ctx, const struct secret *payment_secret, const u8 *payment_metadata) { - struct tlv_tlv_payload *tlv = tlv_tlv_payload_new(tmpctx); - struct tlv_tlv_payload_payment_data tlv_pdata; + struct tlv_payload *tlv = tlv_payload_new(tmpctx); + struct tlv_payload_payment_data tlv_pdata; /* These go together! */ if (!payment_secret) @@ -77,9 +75,9 @@ u8 *onion_final_hop(const tal_t *ctx, /* BOLT #4: * - * The writer: + * The writer of `tlv_payload`: *... - * - For every node: + * - For every node outside of a blinded route: * - MUST include `amt_to_forward` and `outgoing_cltv_value`. *... * - For the final node: @@ -108,7 +106,7 @@ u8 *onion_blinded_hop(const tal_t *ctx, const u8 *enctlv, const struct pubkey *blinding) { - struct tlv_tlv_payload *tlv = tlv_tlv_payload_new(tmpctx); + struct tlv_payload *tlv = tlv_payload_new(tmpctx); if (amt_to_forward) { tlv->amt_to_forward diff --git a/common/onion_encode.h b/common/onion_encode.h index 2892cbc8c748..2e3ccdf36704 100644 --- a/common/onion_encode.h +++ b/common/onion_encode.h @@ -33,7 +33,7 @@ struct onion_payload { struct secret blinding_ss; /* The raw TLVs contained in the payload. */ - struct tlv_tlv_payload *tlv; + struct tlv_payload *tlv; }; u8 *onion_nonfinal_hop(const tal_t *ctx, diff --git a/common/peer_failed.c b/common/peer_failed.c index d3d60114e16f..5281bf86da9f 100644 --- a/common/peer_failed.c +++ b/common/peer_failed.c @@ -11,7 +11,7 @@ #include /* Fatal error here, return peer control to lightningd */ -static void NORETURN +void NORETURN peer_fatal_continue(const u8 *msg TAKES, const struct per_peer_state *pps) { int reason = fromwire_peektype(msg); diff --git a/common/peer_failed.h b/common/peer_failed.h index 51fc8a7fae81..db1ff26a2827 100644 --- a/common/peer_failed.h +++ b/common/peer_failed.h @@ -7,6 +7,9 @@ struct channel_id; struct per_peer_state; +/* peer_fatal_continue - Send a message to master, we've failed */ +void NORETURN peer_fatal_continue(const u8 *msg TAKES, const struct per_peer_state *pps); + /** * peer_failed_warn - Send a warning msg and close the connection. * @pps: the per-peer state. diff --git a/common/permute_tx.c b/common/permute_tx.c index 75fdf6140a71..ab76e3106299 100644 --- a/common/permute_tx.c +++ b/common/permute_tx.c @@ -3,7 +3,6 @@ #include static void swap_wally_outputs(struct wally_tx_output *outputs, - struct wally_tx_output *psbt_global_outs, struct wally_psbt_output *psbt_outs, const void **map, u32 *cltvs, size_t i1, size_t i2) @@ -18,12 +17,6 @@ static void swap_wally_outputs(struct wally_tx_output *outputs, outputs[i1] = outputs[i2]; outputs[i2] = tmpoutput; - /* For the PSBT, we swap the psbt outputs and - * the global tx's outputs */ - tmpoutput = psbt_global_outs[i1]; - psbt_global_outs[i1] = psbt_global_outs[i2]; - psbt_global_outs[i2] = tmpoutput; - tmppsbtout = psbt_outs[i1]; psbt_outs[i1] = psbt_outs[i2]; psbt_outs[i2] = tmppsbtout; @@ -106,7 +99,6 @@ void permute_outputs(struct bitcoin_tx *tx, u32 *cltvs, const void **map) /* Swap best into first place. */ swap_wally_outputs(tx->wtx->outputs, - tx->psbt->tx->outputs, tx->psbt->outputs, map, cltvs, i, best_pos); } diff --git a/common/psbt_internal.c b/common/psbt_internal.c index 46bb0d134fd2..475b4cabc3ae 100644 --- a/common/psbt_internal.c +++ b/common/psbt_internal.c @@ -17,8 +17,8 @@ psbt_input_set_final_witness_stack(const tal_t *ctx, for (size_t i = 0; i < tal_count(elements); i++) wally_tx_witness_stack_add(in->final_witness, - elements[i]->witness, - tal_bytelen(elements[i]->witness)); + elements[i]->witness_data, + tal_bytelen(elements[i]->witness_data)); tal_wally_end(ctx); } @@ -26,6 +26,7 @@ void psbt_finalize_input(const tal_t *ctx, struct wally_psbt_input *in, const struct witness_element **elements) { + const struct wally_map_item *redeem_script; psbt_input_set_final_witness_stack(ctx, in, elements); /* There's this horrible edgecase where we set the final_witnesses @@ -35,18 +36,16 @@ void psbt_finalize_input(const tal_t *ctx, * on these just .. ignores it!? Murder. Anyway, here we do a final * scriptsig check -- if there's a redeemscript field still around we * just go ahead and mush it into the final_scriptsig field. */ - if (in->redeem_script) { + redeem_script = wally_map_get_integer(&in->psbt_fields, /* PSBT_IN_REDEEM_SCRIPT */ 0x04); + if (redeem_script) { u8 *redeemscript = tal_dup_arr(NULL, u8, - in->redeem_script, - in->redeem_script_len, 0); - in->final_scriptsig = + redeem_script->value, + redeem_script->value_len, 0); + u8 *final_scriptsig = bitcoin_scriptsig_redeem(NULL, take(redeemscript)); - in->final_scriptsig_len = - tal_bytelen(in->final_scriptsig); - - in->redeem_script = tal_free(in->redeem_script); - in->redeem_script_len = 0; + wally_psbt_input_set_final_scriptsig(in, final_scriptsig, tal_bytelen(final_scriptsig)); + wally_psbt_input_set_redeem_script(in, tal_arr(NULL, u8, 0), 0); } } @@ -78,13 +77,13 @@ psbt_to_witness_stacks(const tal_t *ctx, tal(stacks, struct witness_stack); /* Convert the wally_tx_witness_stack to * a witness_stack entry */ - stack->witness_element = + stack->witness_elements = tal_arr(stack, struct witness_element *, wtx_s->num_items); - for (size_t j = 0; j < tal_count(stack->witness_element); j++) { - stack->witness_element[j] = tal(stack, + for (size_t j = 0; j < tal_count(stack->witness_elements); j++) { + stack->witness_elements[j] = tal(stack, struct witness_element); - stack->witness_element[j]->witness = + stack->witness_elements[j]->witness_data = tal_dup_arr(stack, u8, wtx_s->items[j].witness, wtx_s->items[j].witness_len, diff --git a/common/psbt_keypath.c b/common/psbt_keypath.c index 5037a0a405fc..f163614e4926 100644 --- a/common/psbt_keypath.c +++ b/common/psbt_keypath.c @@ -14,7 +14,7 @@ void psbt_set_keypath(u32 index, const struct ext_key *ext, struct wally_map *ma u32 path[1]; path[0] = index; - if (wally_map_add_keypath_item(map_in, + if (wally_map_keypath_add(map_in, ext->pub_key, sizeof(ext->pub_key), fingerprint, sizeof(fingerprint), path, 1) != WALLY_OK) diff --git a/common/psbt_open.c b/common/psbt_open.c index 646b4ea029a5..80cbe7fb4b3d 100644 --- a/common/psbt_open.c +++ b/common/psbt_open.c @@ -58,17 +58,11 @@ static int compare_outputs_at(const struct output_set *a, } static const u8 *linearize_input(const tal_t *ctx, - const struct wally_psbt_input *in, - const struct wally_tx_input *tx_in) + const struct wally_psbt_input *in) { struct wally_psbt *psbt = create_psbt(NULL, 1, 0, 0); size_t byte_len; - tal_wally_start(); - if (wally_tx_add_input(psbt->tx, tx_in) != WALLY_OK) - abort(); - tal_wally_end(psbt->tx); - psbt->inputs[0] = *in; psbt->num_inputs++; @@ -77,11 +71,10 @@ static const u8 *linearize_input(const tal_t *ctx, wally_map_sort(&psbt->inputs[0].unknowns, 0); /* signatures, keypaths, etc - we dont care if they change */ - psbt->inputs[0].final_witness = NULL; - psbt->inputs[0].final_scriptsig_len = 0; - psbt->inputs[0].witness_script = NULL; - psbt->inputs[0].witness_script_len = 0; - psbt->inputs[0].redeem_script_len = 0; + wally_psbt_input_set_final_witness(&psbt->inputs[0], NULL); + wally_psbt_input_set_final_scriptsig(&psbt->inputs[0], NULL, 0); + wally_psbt_input_set_witness_script(&psbt->inputs[0], NULL, 0); + wally_psbt_input_set_redeem_script(&psbt->inputs[0], NULL, 0); psbt->inputs[0].keypaths.num_items = 0; psbt->inputs[0].signatures.num_items = 0; @@ -94,22 +87,16 @@ static const u8 *linearize_input(const tal_t *ctx, } static const u8 *linearize_output(const tal_t *ctx, - const struct wally_psbt_output *out, - const struct wally_tx_output *tx_out) + const struct wally_psbt_output *out) { struct wally_psbt *psbt = create_psbt(NULL, 1, 1, 0); size_t byte_len; struct bitcoin_outpoint outpoint; - /* Add a 'fake' input so this will linearize the tx */ - memset(&outpoint, 0, sizeof(outpoint)); + /* Add a 'fake' non-zero input so libwally will agree to linearize the tx */ + memset(&outpoint, 1, sizeof(outpoint)); psbt_append_input(psbt, &outpoint, 0, NULL, NULL, NULL); - tal_wally_start(); - if (wally_tx_add_output(psbt->tx, tx_out) != WALLY_OK) - abort(); - tal_wally_end(psbt->tx); - psbt->outputs[0] = *out; psbt->num_outputs++; /* Sort the outputs, so serializing them is ok */ @@ -118,8 +105,8 @@ static const u8 *linearize_output(const tal_t *ctx, /* We don't care if the keypaths change */ psbt->outputs[0].keypaths.num_items = 0; /* And you can add scripts, no problem */ - psbt->outputs[0].witness_script_len = 0; - psbt->outputs[0].redeem_script_len = 0; + wally_psbt_output_set_witness_script(&psbt->outputs[0], NULL, 0); + wally_psbt_output_set_redeem_script(&psbt->outputs[0], NULL, 0); const u8 *bytes = psbt_get_bytes(ctx, psbt, &byte_len); @@ -135,11 +122,9 @@ static bool input_identical(const struct wally_psbt *a, size_t b_index) { const u8 *a_in = linearize_input(tmpctx, - &a->inputs[a_index], - &a->tx->inputs[a_index]); + &a->inputs[a_index]); const u8 *b_in = linearize_input(tmpctx, - &b->inputs[b_index], - &b->tx->inputs[b_index]); + &b->inputs[b_index]); return memeq(a_in, tal_bytelen(a_in), b_in, tal_bytelen(b_in)); @@ -151,11 +136,9 @@ static bool output_identical(const struct wally_psbt *a, size_t b_index) { const u8 *a_out = linearize_output(tmpctx, - &a->outputs[a_index], - &a->tx->outputs[a_index]); + &a->outputs[a_index]); const u8 *b_out = linearize_output(tmpctx, - &b->outputs[b_index], - &b->tx->outputs[b_index]); + &b->outputs[b_index]); return memeq(a_out, tal_bytelen(a_out), b_out, tal_bytelen(b_out)); } @@ -168,7 +151,6 @@ static void sort_inputs(struct wally_psbt *psbt) psbt->num_inputs); for (size_t i = 0; i < tal_count(set); i++) { - set[i].tx_input = psbt->tx->inputs[i]; set[i].input = psbt->inputs[i]; } @@ -178,7 +160,6 @@ static void sort_inputs(struct wally_psbt *psbt) /* Put PSBT parts into place */ for (size_t i = 0; i < tal_count(set); i++) { psbt->inputs[i] = set[i].input; - psbt->tx->inputs[i] = set[i].tx_input; } tal_free(set); @@ -191,7 +172,6 @@ static void sort_outputs(struct wally_psbt *psbt) struct output_set, psbt->num_outputs); for (size_t i = 0; i < tal_count(set); i++) { - set[i].tx_output = psbt->tx->outputs[i]; set[i].output = psbt->outputs[i]; } @@ -201,7 +181,6 @@ static void sort_outputs(struct wally_psbt *psbt) /* Put PSBT parts into place */ for (size_t i = 0; i < tal_count(set); i++) { psbt->outputs[i] = set[i].output; - psbt->tx->outputs[i] = set[i].tx_output; } tal_free(set); @@ -217,7 +196,6 @@ void psbt_sort_by_serial_id(struct wally_psbt *psbt) do { \ struct type##_set a; \ a.type = from->type##s[index]; \ - a.tx_##type = from->tx->type##s[index]; \ a.idx = index; \ tal_arr_expand(&add_to, a); \ } while (0) @@ -398,6 +376,7 @@ bool psbt_has_required_fields(struct wally_psbt *psbt) { u64 serial_id; for (size_t i = 0; i < psbt->num_inputs; i++) { + const struct wally_map_item *redeem_script; struct wally_psbt_input *input = &psbt->inputs[i]; if (!psbt_get_serial_id(&input->unknowns, &serial_id)) @@ -408,13 +387,13 @@ bool psbt_has_required_fields(struct wally_psbt *psbt) return false; /* If is P2SH, redeemscript must be present */ - assert(psbt->tx->inputs[i].index < input->utxo->num_outputs); + assert(psbt->inputs[i].index < input->utxo->num_outputs); const u8 *outscript = wally_tx_output_get_script(tmpctx, - &input->utxo->outputs[psbt->tx->inputs[i].index]); - if (is_p2sh(outscript, NULL) && input->redeem_script_len == 0) + &input->utxo->outputs[psbt->inputs[i].index]); + redeem_script = wally_map_get_integer(&psbt->inputs[i].psbt_fields, /* PSBT_IN_REDEEM_SCRIPT */ 0x04); + if (is_p2sh(outscript, NULL) && (!redeem_script || redeem_script->value_len == 0)) return false; - } for (size_t i = 0; i < psbt->num_outputs; i++) { @@ -511,6 +490,8 @@ bool psbt_output_to_external(const struct wally_psbt_output *output) bool psbt_contribs_changed(struct wally_psbt *orig, struct wally_psbt *new) { + assert(orig->version == 2 && new->version == 2); + struct psbt_changeset *cs; bool ok; cs = psbt_get_changeset(NULL, orig, new); diff --git a/common/psbt_open.h b/common/psbt_open.h index 134a5da65754..be3c4995b46f 100644 --- a/common/psbt_open.h +++ b/common/psbt_open.h @@ -15,14 +15,12 @@ struct wally_psbt_output; struct wally_map; struct input_set { - struct wally_tx_input tx_input; struct wally_psbt_input input; /* index on PSBT of this input */ size_t idx; }; struct output_set { - struct wally_tx_output tx_output; struct wally_psbt_output output; /* index on PSBT of this output */ size_t idx; diff --git a/common/scb_wire.csv b/common/scb_wire.csv index f27667caf5fb..6410ff4942e6 100644 --- a/common/scb_wire.csv +++ b/common/scb_wire.csv @@ -10,10 +10,12 @@ subtype,scb_chan subtypedata,scb_chan,id,u64, subtypedata,scb_chan,cid,channel_id, subtypedata,scb_chan,node_id,node_id, -subtypedata,scb_chan,addr,wireaddr_internal, +subtypedata,scb_chan,unused,u8, +subtypedata,scb_chan,addr,wireaddr, subtypedata,scb_chan,funding,bitcoin_outpoint, subtypedata,scb_chan,funding_sats,amount_sat, subtypedata,scb_chan,type,channel_type, + msgtype,static_chan_backup,6135, msgdata,static_chan_backup,version,u64, msgdata,static_chan_backup,timestamp,u32, diff --git a/common/sphinx.c b/common/sphinx.c index 19d50ba89f10..d908f622eeb0 100644 --- a/common/sphinx.c +++ b/common/sphinx.c @@ -651,7 +651,7 @@ struct route_step *process_onionpacket( cursor - paddedheader, 0); fromwire_hmac(&cursor, &max, &step->next->hmac); - /* BOLT-remove-legacy-onion #4: + /* BOLT #4: * Since no `payload` TLV value can ever be shorter than 2 bytes, `length` values of 0 and 1 are * reserved. (`0` indicated a legacy format no longer supported, and `1` is reserved for future * use). */ @@ -694,10 +694,11 @@ struct onionreply *create_onionreply(const tal_t *ctx, /* BOLT #4: * The _erring node_: - * - SHOULD set `pad` such that the `failure_len` plus `pad_len` - * is equal to 256. - * - Note: this value is 118 bytes longer than the longest - * currently-defined message. + * - MUST set `pad` such that the `failure_len` plus `pad_len` + * is at least 256. + * - SHOULD set `pad` such that the `failure_len` plus `pad_len` is equal + * to 256. Deviating from this may cause older nodes to be unable to parse + * the return message. */ const u16 onion_reply_size = IFDEV(dev_onion_reply_length, 256); diff --git a/common/test/Makefile b/common/test/Makefile index 2df9e1284cad..5f644f178603 100644 --- a/common/test/Makefile +++ b/common/test/Makefile @@ -1,9 +1,5 @@ COMMON_TEST_SRC := $(wildcard common/test/run-*.c) -ifeq ($(EXPERIMENTAL_FEATURES),1) -COMMON_TEST_SRC += $(wildcard common/test/exp-run-*.c) -endif - COMMON_TEST_OBJS := $(COMMON_TEST_SRC:.c=.o) COMMON_TEST_PROGRAMS := $(COMMON_TEST_OBJS:.o=) @@ -19,10 +15,10 @@ ALL_C_SOURCES += $(COMMON_TEST_SRC) ALL_TEST_PROGRAMS += $(COMMON_TEST_PROGRAMS) # Sphinx test wants to decode TLVs. -common/test/run-sphinx: wire/onion$(EXP)_wiregen.o wire/towire.o wire/fromwire.o -common/test/run-blindedpath_enctlv common/test/run-blindedpath_onion: common/base32.o common/wireaddr.o wire/onion$(EXP)_wiregen.o wire/peer$(EXP)_wiregen.o wire/towire.o wire/fromwire.o wire/tlvstream.o -common/test/run-route_blinding_test: wire/onion$(EXP)_wiregen.o wire/peer$(EXP)_wiregen.o wire/towire.o wire/fromwire.o wire/tlvstream.o common/coin_mvt.o -common/test/run-route_blinding_override_test: common/base32.o common/wireaddr.o wire/onion$(EXP)_wiregen.o wire/peer$(EXP)_wiregen.o wire/towire.o wire/fromwire.o wire/tlvstream.o common/coin_mvt.o +common/test/run-sphinx: wire/onion_wiregen.o wire/towire.o wire/fromwire.o +common/test/run-blindedpath_enctlv common/test/run-blindedpath_onion: common/base32.o common/wireaddr.o wire/onion_wiregen.o wire/peer_wiregen.o wire/towire.o wire/fromwire.o wire/tlvstream.o +common/test/run-route_blinding_test: wire/onion_wiregen.o wire/peer_wiregen.o wire/towire.o wire/fromwire.o wire/tlvstream.o common/coin_mvt.o +common/test/run-route_blinding_override_test: common/base32.o common/wireaddr.o wire/onion_wiregen.o wire/peer_wiregen.o wire/towire.o wire/fromwire.o wire/tlvstream.o common/coin_mvt.o common/test/run-param \ common/test/run-json: \ @@ -38,27 +34,27 @@ common/test/run-json: \ common/type_to_string.o \ common/wireaddr.o \ wire/fromwire.o \ - wire/onion$(EXP)_wiregen.o \ - wire/peer$(EXP)_wiregen.o \ + wire/onion_wiregen.o \ + wire/peer_wiregen.o \ wire/towire.o common/test/run-route common/test/run-route-specific: \ common/amount.o \ common/dijkstra.o \ - common/fp16.o \ + common/fp16.o \ common/gossmap.o \ common/node_id.o \ common/pseudorand.o \ common/route.o \ wire/fromwire.o \ - wire/peer$(EXP)_wiregen.o \ + wire/peer_wiregen.o \ wire/towire.o common/test/run-gossmap_local: \ common/base32.o \ common/wireaddr.o \ wire/fromwire.o \ - wire/peer$(EXP)_wiregen.o \ + wire/peer_wiregen.o \ wire/tlvstream.o \ wire/towire.o @@ -66,7 +62,7 @@ common/test/run-gossmap_canned: \ common/base32.o \ common/wireaddr.o \ wire/fromwire.o \ - wire/peer$(EXP)_wiregen.o \ + wire/peer_wiregen.o \ wire/tlvstream.o \ wire/towire.o @@ -80,10 +76,10 @@ common/test/run-bolt12_merkle: \ common/node_id.o \ common/type_to_string.o \ common/wireaddr.o \ - wire/bolt12$(EXP)_wiregen.o \ + wire/bolt12_wiregen.o \ wire/fromwire.o \ wire/tlvstream.o \ - wire/peer$(EXP)_wiregen.o \ + wire/peer_wiregen.o \ wire/towire.o common/test/run-bolt12_merkle-json: \ diff --git a/common/test/run-base64.c b/common/test/run-base64.c index 97571a5529ae..b3117201ee50 100644 --- a/common/test/run-base64.c +++ b/common/test/run-base64.c @@ -24,12 +24,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-bigsize.c b/common/test/run-bigsize.c index 46590bdb7a91..ef5deec69ad7 100644 --- a/common/test/run-bigsize.c +++ b/common/test/run-bigsize.c @@ -26,12 +26,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-blindedpath_enctlv.c b/common/test/run-blindedpath_enctlv.c index fd88d7cbb1e9..02b669017db7 100644 --- a/common/test/run-blindedpath_enctlv.c +++ b/common/test/run-blindedpath_enctlv.c @@ -26,12 +26,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-blindedpath_onion.c b/common/test/run-blindedpath_onion.c index 5aa521b25945..a25492d828fc 100644 --- a/common/test/run-blindedpath_onion.c +++ b/common/test/run-blindedpath_onion.c @@ -36,12 +36,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-bolt11.c b/common/test/run-bolt11.c index d4b2f6aa48c9..301e8d99d89b 100644 --- a/common/test/run-bolt11.c +++ b/common/test/run-bolt11.c @@ -527,9 +527,9 @@ int main(int argc, char *argv[]) * * `x`: expiry time * * `qy`: `data_length` (`q` = 0, `y` = 2; 0 * 32 + 4 == 4) * * `jw5q`: 604800 seconds (`j` = 18, `w` = 14, `5` = 20, `q` = 0; 18 * 32^3 + 14 * 32^2 + 20 * 32 + 0 == 604800) - * * `c`: `min_final_cltv_expiry` + * * `c`: `min_final_cltv_expiry_delta` * * `qp`: `data_length` (`q` = 0, `p` = 1; 0 * 32 + 1 == 1) - * * `2`: min_final_cltv_expiry = 10 + * * `2`: min_final_cltv_expiry_delta = 10 * * `r`: tagged field: route information * * `zj`: `data_length` (`z` = 2, `j` = 18; 2 * 32 + 18 == 82) * * `q0gxwkzc8w6323m55m4jyxcjwmy7stt9hwkwe2qxmy8zpsgg7jcuwz87fcqqeuqqqyqqqqlgqqqqn3qq9q`: diff --git a/common/test/run-bolt12_decode.c b/common/test/run-bolt12_decode.c index 9043b876e453..6ddf6656dc46 100644 --- a/common/test/run-bolt12_decode.c +++ b/common/test/run-bolt12_decode.c @@ -24,12 +24,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-bolt12_merkle-json.c b/common/test/run-bolt12_merkle-json.c index d1eaf16d9011..95fcc507aa4e 100644 --- a/common/test/run-bolt12_merkle-json.c +++ b/common/test/run-bolt12_merkle-json.c @@ -4,15 +4,10 @@ #include "../bolt12_merkle.c" #include "../json_parse.c" #include "../json_parse_simple.c" +#include "../../wire/bolt12_wiregen.c" #include "../../wire/fromwire.c" +#include "../../wire/peer_wiregen.c" #include "../../wire/tlvstream.c" -#if EXPERIMENTAL_FEATURES - #include "../../wire/peer_exp_wiregen.c" - #include "../../wire/bolt12_exp_wiregen.c" -#else - #include "../../wire/peer_wiregen.c" - #include "../../wire/bolt12_wiregen.c" -#endif #include #include #include diff --git a/common/test/run-bolt12_period.c b/common/test/run-bolt12_period.c index 8b44328bda10..d6a44638d9db 100644 --- a/common/test/run-bolt12_period.c +++ b/common/test/run-bolt12_period.c @@ -22,12 +22,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-channel_type.c b/common/test/run-channel_type.c new file mode 100644 index 000000000000..09aa8bcf46df --- /dev/null +++ b/common/test/run-channel_type.c @@ -0,0 +1,136 @@ +#include "config.h" +#include "../channel_type.c" +#include "../features.c" +#include +#include +#include + +/* AUTOGENERATED MOCKS START */ +/* Generated stub for amount_asset_is_main */ +bool amount_asset_is_main(struct amount_asset *asset UNNEEDED) +{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); } +/* Generated stub for amount_asset_to_sat */ +struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED) +{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); } +/* Generated stub for amount_sat */ +struct amount_sat amount_sat(u64 satoshis UNNEEDED) +{ fprintf(stderr, "amount_sat called!\n"); abort(); } +/* Generated stub for amount_sat_add */ + bool amount_sat_add(struct amount_sat *val UNNEEDED, + struct amount_sat a UNNEEDED, + struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } +/* Generated stub for amount_sat_eq */ +bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } +/* Generated stub for amount_sat_greater_eq */ +bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } +/* Generated stub for amount_sat_sub */ + bool amount_sat_sub(struct amount_sat *val UNNEEDED, + struct amount_sat a UNNEEDED, + struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_sub called!\n"); abort(); } +/* Generated stub for amount_sat_to_asset */ +struct amount_asset amount_sat_to_asset(struct amount_sat *sat UNNEEDED, const u8 *asset UNNEEDED) +{ fprintf(stderr, "amount_sat_to_asset called!\n"); abort(); } +/* Generated stub for amount_tx_fee */ +struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED) +{ fprintf(stderr, "amount_tx_fee called!\n"); abort(); } +/* Generated stub for fromwire */ +const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED) +{ fprintf(stderr, "fromwire called!\n"); abort(); } +/* Generated stub for fromwire_bool */ +bool fromwire_bool(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_bool called!\n"); abort(); } +/* Generated stub for fromwire_fail */ +void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_fail called!\n"); abort(); } +/* Generated stub for fromwire_secp256k1_ecdsa_signature */ +void fromwire_secp256k1_ecdsa_signature(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, + secp256k1_ecdsa_signature *signature UNNEEDED) +{ fprintf(stderr, "fromwire_secp256k1_ecdsa_signature called!\n"); abort(); } +/* Generated stub for fromwire_sha256 */ +void fromwire_sha256(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sha256 *sha256 UNNEEDED) +{ fprintf(stderr, "fromwire_sha256 called!\n"); abort(); } +/* Generated stub for fromwire_tal_arrn */ +u8 *fromwire_tal_arrn(const tal_t *ctx UNNEEDED, + const u8 **cursor UNNEEDED, size_t *max UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "fromwire_tal_arrn called!\n"); abort(); } +/* Generated stub for fromwire_u16 */ +u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u16 called!\n"); abort(); } +/* Generated stub for fromwire_u32 */ +u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u32 called!\n"); abort(); } +/* Generated stub for fromwire_u64 */ +u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u64 called!\n"); abort(); } +/* Generated stub for fromwire_u8 */ +u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); } +/* Generated stub for fromwire_u8_array */ +void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } +/* Generated stub for towire */ +void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) +{ fprintf(stderr, "towire called!\n"); abort(); } +/* Generated stub for towire_bool */ +void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED) +{ fprintf(stderr, "towire_bool called!\n"); abort(); } +/* Generated stub for towire_secp256k1_ecdsa_signature */ +void towire_secp256k1_ecdsa_signature(u8 **pptr UNNEEDED, + const secp256k1_ecdsa_signature *signature UNNEEDED) +{ fprintf(stderr, "towire_secp256k1_ecdsa_signature called!\n"); abort(); } +/* Generated stub for towire_sha256 */ +void towire_sha256(u8 **pptr UNNEEDED, const struct sha256 *sha256 UNNEEDED) +{ fprintf(stderr, "towire_sha256 called!\n"); abort(); } +/* Generated stub for towire_u16 */ +void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED) +{ fprintf(stderr, "towire_u16 called!\n"); abort(); } +/* Generated stub for towire_u32 */ +void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED) +{ fprintf(stderr, "towire_u32 called!\n"); abort(); } +/* Generated stub for towire_u64 */ +void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED) +{ fprintf(stderr, "towire_u64 called!\n"); abort(); } +/* Generated stub for towire_u8 */ +void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED) +{ fprintf(stderr, "towire_u8 called!\n"); abort(); } +/* Generated stub for towire_u8_array */ +void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "towire_u8_array called!\n"); abort(); } +/* AUTOGENERATED MOCKS END */ + +static void assert_names_eq(const char **names, const char *expected) +{ + char **expected_names = tal_strsplit(tmpctx, expected, " ", STR_EMPTY_OK); + + assert(tal_count(expected_names) == tal_count(names) + 1); + for (size_t i = 0; i < tal_count(names); i++) + assert(streq(expected_names[i], names[i])); +} + +int main(int argc, char *argv[]) +{ + struct channel_type t; + + common_setup(argv[0]); + + assert_names_eq(channel_type_name(tmpctx, channel_type_none(tmpctx)), ""); + assert_names_eq(channel_type_name(tmpctx, channel_type_static_remotekey(tmpctx)), + "static_remotekey/even"); + assert_names_eq(channel_type_name(tmpctx, channel_type_anchor_outputs(tmpctx)), + "static_remotekey/even anchor_outputs/even"); + + t.features = tal_arr(tmpctx, u8, 0); + set_feature_bit(&t.features, 1000); + assert_names_eq(channel_type_name(tmpctx, &t), "unknown_1000/even"); + common_shutdown(); +} diff --git a/common/test/run-cryptomsg.c b/common/test/run-cryptomsg.c index 39e18f9df6e1..0229fbe7230f 100644 --- a/common/test/run-cryptomsg.c +++ b/common/test/run-cryptomsg.c @@ -20,12 +20,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-derive_basepoints.c b/common/test/run-derive_basepoints.c index e53b89754eac..89ef438cb73a 100644 --- a/common/test/run-derive_basepoints.c +++ b/common/test/run-derive_basepoints.c @@ -26,12 +26,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-features.c b/common/test/run-features.c index 3e7dbd6db9c3..69ec5e3c8cd7 100644 --- a/common/test/run-features.c +++ b/common/test/run-features.c @@ -19,12 +19,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-gossmap-fp16.c b/common/test/run-gossmap-fp16.c index b7b5ff1ca05a..3ef15580735e 100644 --- a/common/test/run-gossmap-fp16.c +++ b/common/test/run-gossmap-fp16.c @@ -20,12 +20,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-ip_port_parsing.c b/common/test/run-ip_port_parsing.c index 37487f8ebc52..4685f50c84de 100644 --- a/common/test/run-ip_port_parsing.c +++ b/common/test/run-ip_port_parsing.c @@ -21,12 +21,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, @@ -190,37 +196,36 @@ int main(int argc, char *argv[]) assert(!separate_address_and_port(tmpctx, "[::1]:http", &ip, &port)); // localhost hostnames for backward compat - assert(parse_wireaddr("localhost", &addr, 200, false, NULL)); + assert(parse_wireaddr(tmpctx, "localhost", 200, false, &addr) == NULL); assert(addr.port == 200); // string should win the port battle - assert(parse_wireaddr("[::1]:9735", &addr, 500, false, NULL)); + assert(parse_wireaddr(tmpctx, "[::1]:9735", 500, false, &addr) == NULL); assert(addr.port == 9735); ip = fmt_wireaddr(tmpctx, &addr); assert(streq(ip, "[::1]:9735")); // should use argument if we have no port in string - assert(parse_wireaddr("2001:db8:85a3::8a2e:370:7334", &addr, 9777, false, NULL)); + assert(parse_wireaddr(tmpctx, "2001:db8:85a3::8a2e:370:7334", 9777, false, &addr) == NULL); assert(addr.port == 9777); ip = fmt_wireaddr(tmpctx, &addr); assert(streq(ip, "[2001:db8:85a3::8a2e:370:7334]:9777")); - assert(parse_wireaddr("[::ffff:127.0.0.1]:49150", &addr, 1, false, NULL)); + assert(parse_wireaddr(tmpctx, "[::ffff:127.0.0.1]:49150", 1, false, &addr) == NULL); assert(addr.port == 49150); - assert(parse_wireaddr("4ruvswpqec5i2gogopxl4vm5bruzknbvbylov2awbo4rxiq4cimdldad.onion:49150", &addr, 1, false, NULL)); + assert(parse_wireaddr(tmpctx, "4ruvswpqec5i2gogopxl4vm5bruzknbvbylov2awbo4rxiq4cimdldad.onion:49150", 1, false, &addr) == NULL); assert(addr.port == 49150); - assert(parse_wireaddr("4ruvswpqec5i2gogopxl4vm5bruzknbvbylov2awbo4rxiq4cimdldad.onion", &addr, 1, false, NULL)); + assert(parse_wireaddr(tmpctx, "4ruvswpqec5i2gogopxl4vm5bruzknbvbylov2awbo4rxiq4cimdldad.onion", 1, false, &addr) == NULL); assert(addr.port == 1); /* We don't accept torv2 any more */ - assert(!parse_wireaddr("odpzvneidqdf5hdq.onion:49150", &addr, 1, false, NULL)); - assert(!parse_wireaddr("odpzvneidqdf5hdq.onion", &addr, 1, false, NULL)); + assert(parse_wireaddr(tmpctx, "odpzvneidqdf5hdq.onion:49150", 1, false, &addr) != NULL); + assert(parse_wireaddr(tmpctx, "odpzvneidqdf5hdq.onion", 1, false, &addr) != NULL); - assert(!parse_wireaddr_internal("odpzvneidqdf5hdq.onion", &addr_int, 1, - false, false, false, NULL)); + assert(parse_wireaddr_internal(tmpctx, "odpzvneidqdf5hdq.onion", 1, false, &addr_int) != NULL); assert(wireaddr_from_hostname(tmpctx, "odpzvneidqdf5hdq.onion", 1, NULL, NULL, NULL) == NULL); assert(wireaddr_from_hostname(tmpctx, "aaa.onion", 1, NULL, NULL, NULL) == NULL); diff --git a/common/test/run-json.c b/common/test/run-json.c index a9dc6daa9f5f..c0c292e93ed6 100644 --- a/common/test/run-json.c +++ b/common/test/run-json.c @@ -10,8 +10,6 @@ #include /* AUTOGENERATED MOCKS START */ -/* Generated stub for deprecated_apis */ -bool deprecated_apis; /* Generated stub for fromwire_tlv */ bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, const struct tlv_record_type *types UNNEEDED, size_t num_types UNNEEDED, diff --git a/common/test/run-json_filter.c b/common/test/run-json_filter.c index 5ac68b4fb9ba..594eb00f7ef7 100644 --- a/common/test/run-json_filter.c +++ b/common/test/run-json_filter.c @@ -149,10 +149,6 @@ void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED) /* Generated stub for towire_u8_array */ void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "towire_u8_array called!\n"); abort(); } -/* Generated stub for type_to_string_ */ -const char *type_to_string_(const tal_t *ctx UNNEEDED, const char *typename UNNEEDED, - union printable_types u UNNEEDED) -{ fprintf(stderr, "type_to_string_ called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ bool deprecated_apis; @@ -230,7 +226,7 @@ int main(int argc, char *argv[]) json_object_start(js, NULL); json_add_u32(js, "index", i+j); - json_add_amount_msat_only(js, "amount_msat", amount_msat(12)); + json_add_amount_msat(js, "amount_msat", amount_msat(12)); if (j == 0) json_add_string(js, "type", "sometype"); json_add_string(js, "scriptPubKey", "00000000"); diff --git a/common/test/run-json_remove.c b/common/test/run-json_remove.c index 99ae0122a938..3b25bd141f71 100644 --- a/common/test/run-json_remove.c +++ b/common/test/run-json_remove.c @@ -21,12 +21,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-json_scan.c b/common/test/run-json_scan.c index 7dfdc8247931..4b8838b8fc04 100644 --- a/common/test/run-json_scan.c +++ b/common/test/run-json_scan.c @@ -20,12 +20,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, @@ -140,6 +146,24 @@ int main(int argc, char *argv[]) assert(!json_scan(tmpctx, buf, toks, "{2:two,1:one,3:{three:{deeper:17}},arr:[1:2]}")); assert(!json_scan(tmpctx, buf, toks, "{2:two,1:one,3:{three:{deeper:17}},arr:[1:2,2:[0:3,1:4]]}")); + /* Optional fields which are present are fine. */ + assert(!json_scan(tmpctx, buf, toks, "{1?:one}")); + assert(!json_scan(tmpctx, buf, toks, "{1?:one,2?:two}")); + assert(!json_scan(tmpctx, buf, toks, "{2?:two,1?:one}")); + assert(!json_scan(tmpctx, buf, toks, "{2?:two,1?:one,3?:{three?:{deeper?:17}}}")); + assert(!json_scan(tmpctx, buf, toks, "{2?:two,1?:one,3?:{three?:{deeper?:17}},arr?:[0:{1?:arrone}]}")); + assert(!json_scan(tmpctx, buf, toks, "{2?:two,1?:one,3?:{three?:{deeper?:17}},arr?:[1:2]}")); + assert(!json_scan(tmpctx, buf, toks, "{2?:two,1?:one,3?:{three?:{deeper?:17}},arr?:[1:2,2:[0:3,1:4]]}")); + + /* Optional field which are missing are fine too */ + assert(!json_scan(tmpctx, buf, toks, "{5?:one}")); + assert(!json_scan(tmpctx, buf, toks, "{1:one,5?:two}")); + assert(!json_scan(tmpctx, buf, toks, "{2:two,5?:one}")); + assert(!json_scan(tmpctx, buf, toks, "{2:two,1:one,5?:{three:{deeper:17}}}")); + assert(!json_scan(tmpctx, buf, toks, "{2:two,1:one,3:{five?:{deeper:17}},arr:[0:{1:arrone}]}")); + assert(!json_scan(tmpctx, buf, toks, "{2:two,1:one,3:{three:{notdeeper?:17}},arr:[1:2]}")); + assert(!json_scan(tmpctx, buf, toks, "{2:two,1:one,3:{three:{deeper:17}},notarr?:[1:2,2:[0:3,1:4]]}")); + /* These do not match */ err = json_scan(tmpctx, buf, toks, "{2:one}"); assert(streq(err, "Parsing '{2:one': \"two\" does not match expected one")); diff --git a/common/test/run-json_stream-filter.c b/common/test/run-json_stream-filter.c index 16f6ea60919c..4a4e7dcc3f4d 100644 --- a/common/test/run-json_stream-filter.c +++ b/common/test/run-json_stream-filter.c @@ -26,12 +26,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, @@ -55,11 +61,6 @@ struct command_result *command_fail(struct command *cmd UNNEEDED, enum jsonrpc_e /* Generated stub for command_filter_ptr */ struct json_filter **command_filter_ptr(struct command *cmd UNNEEDED) { fprintf(stderr, "command_filter_ptr called!\n"); abort(); } -/* Generated stub for deprecated_apis */ -bool deprecated_apis; -/* Generated stub for fmt_amount_msat */ -const char *fmt_amount_msat(const tal_t *ctx UNNEEDED, struct amount_msat msat UNNEEDED) -{ fprintf(stderr, "fmt_amount_msat called!\n"); abort(); } /* Generated stub for fmt_amount_sat */ const char *fmt_amount_sat(const tal_t *ctx UNNEEDED, struct amount_sat sat UNNEEDED) { fprintf(stderr, "fmt_amount_sat called!\n"); abort(); } @@ -135,10 +136,6 @@ void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED) /* Generated stub for towire_u8_array */ void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED) { fprintf(stderr, "towire_u8_array called!\n"); abort(); } -/* Generated stub for type_to_string_ */ -const char *type_to_string_(const tal_t *ctx UNNEEDED, const char *typename UNNEEDED, - union printable_types u UNNEEDED) -{ fprintf(stderr, "type_to_string_ called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ int main(int argc, char *argv[]) diff --git a/common/test/run-key_derive.c b/common/test/run-key_derive.c index 25f246b27b64..eb8a51ce9350 100644 --- a/common/test/run-key_derive.c +++ b/common/test/run-key_derive.c @@ -24,12 +24,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-onion-message-test.c b/common/test/run-onion-message-test.c index c3ef156b8786..dc6ae3aa1b43 100644 --- a/common/test/run-onion-message-test.c +++ b/common/test/run-onion-message-test.c @@ -16,13 +16,8 @@ static void maybe_print(const char *fmt, ...); #include "../onion_message_parse.c" #include "../sphinx.c" #include "../type_to_string.c" -#if EXPERIMENTAL_FEATURES - #include "../../wire/onion_exp_wiregen.c" - #include "../../wire/peer_exp_wiregen.c" -#else - #include "../../wire/onion_wiregen.c" - #include "../../wire/peer_wiregen.c" -#endif +#include "../../wire/onion_wiregen.c" +#include "../../wire/peer_wiregen.c" #include #include #include diff --git a/common/test/run-onion-test-vector.c b/common/test/run-onion-test-vector.c index 14a1be1b4e76..d1583ae0a109 100644 --- a/common/test/run-onion-test-vector.c +++ b/common/test/run-onion-test-vector.c @@ -8,11 +8,7 @@ #include "../type_to_string.c" #include "../../wire/towire.c" #include "../../wire/fromwire.c" -#if EXPERIMENTAL_FEATURES -#include "../../wire/onion_exp_wiregen.c" -#else #include "../../wire/onion_wiregen.c" -#endif #include #include #include @@ -42,12 +38,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-param.c b/common/test/run-param.c index 6609247db72e..26efb52bd704 100644 --- a/common/test/run-param.c +++ b/common/test/run-param.c @@ -1,4 +1,5 @@ #include "config.h" +#include "../bech32.c" #include "../json_filter.c" #include "../json_parse.c" #include "../json_parse_simple.c" @@ -47,15 +48,6 @@ bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *record UNNEEDED, struct tlv_field **fields UNNEEDED, const u64 *extra_types UNNEEDED, size_t *err_off UNNEEDED, u64 *err_type UNNEEDED) { fprintf(stderr, "fromwire_tlv called!\n"); abort(); } -/* Generated stub for segwit_addr_decode */ -int segwit_addr_decode( - int* ver UNNEEDED, - uint8_t* prog UNNEEDED, - size_t* prog_len UNNEEDED, - const char* hrp UNNEEDED, - const char* addr -) -{ fprintf(stderr, "segwit_addr_decode called!\n"); abort(); } /* Generated stub for towire_tlv */ void towire_tlv(u8 **pptr UNNEEDED, const struct tlv_record_type *types UNNEEDED, size_t num_types UNNEEDED, @@ -465,6 +457,43 @@ static void deprecated_rename(void) NULL)); } +static void invalid_bech32m(void) +{ + int wit_version; + uint8_t data_out[500]; + size_t data_out_len; + + /* Taken from BIP-350 */ + + /* Correct */ + assert(segwit_addr_decode(&wit_version, data_out, &data_out_len, "bc", "BC1SW50QGDZ25J")); + assert(wit_version == 16); + assert(data_out_len == 2); + + /* Correct encoding, but expecting the wrong hrp*/ + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "tb", "BC1SW50QGDZ25J")); + + /* BIP350-valid, but fake HRP so was put in "invalid" section of BIP */ + assert(segwit_addr_decode(&wit_version, data_out, &data_out_len, "tc", "tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut")); + + /* Incorrect for various reasons (including wrong checksum between bech32 <->bech32m */ + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "bc", "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd")); + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "tb", "tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf")); + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "bc", "BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL")); + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "bc", "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh")); + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "tb", "tb1q0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq24jc47")); + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "bc", "bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4")); + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "bc", "BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R")); + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "bc", "bc1pw5dgrnzv")); + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "bc", "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav")); + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "bc", "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P")); + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "tb", "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq")); + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "bc", "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v07qwwzcrf")); + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "tb", "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vpggkg4j")); + assert(!segwit_addr_decode(&wit_version, data_out, &data_out_len, "bc", "bc1gmk9yu")); + +} + static void sendpay_nulltok(void) { struct json *j = json_parse(cmd, "[ 'A', '123']"); @@ -641,6 +670,7 @@ int main(int argc, char *argv[]) param_tests(); usage(); deprecated_rename(); + invalid_bech32m(); printf("run-params ok\n"); common_shutdown(); diff --git a/common/test/run-psbt_diff.c b/common/test/run-psbt_diff.c index 4c8ff0587841..37f4fdf495dc 100644 --- a/common/test/run-psbt_diff.c +++ b/common/test/run-psbt_diff.c @@ -132,6 +132,19 @@ static void check_psbt_comparison(void) struct wally_psbt *newpsbt = psbt_from_b64(tmpctx, "cHNidP8BAO4CAAAAAzN5VhNaE8Vcck3HxVgzwzZ222MTllIAnbHt0n14wqK3AwAAAAABAAAAA6eMOG9Offcfn4WU8H2d0Z6kxU7rcAqvyvtranQVGTwAAAAAAP3///90da/+7PPocKC7hy/NS8LJl91lxs8w0QDITv4yiUOK2wAAAAAA/f///wOMnh4AAAAAACIAIHbV3spzDYJViRvskhH+rV1dx9dvac3CR5/iDdsa1rOBSP4OAAAAAAAWABRrnRZ3l/w3gUj80T2t5objcD9W0O7mfAAAAAAAFgAUtmotjMoZeRMsAbICfElGqwiW3UocpwoAAAEA/bsBAgAAAAABAXPfLv55YUFV5bYj2nW0Qg21s+wun9ml6OSboVUZk2wLAAAAAABatvuABEoBAAAAAAAAIgAgcvZQbEPQgaQZheQRE2h0qKIYGEvEnR8AMgqGtqkMQ0JKAQAAAAAAACIAIPKe3p1VfFQC7ANr0L8T5jqBNZiRsy1otltPruOm62IUYcYCAAAAAAAiACCvU6YsJg1wnAODdsViE6KHEB7x8larBFmohA/vXE5ynYAsAwAAAAAAIgAgH/GZYEVN/fM86vqoSYtZ1PxX4cQVPG9HVTOA6qA/UkkEAEcwRAIgI5QU3lRHdW78aZwx4QptrEtqcx7bOcVBU+6j636qYG0CIHJnhPaHlHVjUI88gFWlFM957z/5JCSYWxJacc4w5C4rAUcwRAIgGc5N3cKTLBY4gZrZDZQa+mxGGDlKWRNkcwu70AOrO2oCIH1KSDAF8EhRXCVPAXJ15naYm34QdL3cP/ZGvFO0HYqYAUdSIQIxs+uJrVTubrGY2Jfk4utUK+VWAvMEyP78BtPi4yRXFyECa/fDQc/qrr4ySj2F8lKL/QTmVYx8pmYpd8Sz1NSqbMtSroDGayABASuALAMAAAAAACIAIB/xmWBFTf3zPOr6qEmLWdT8V+HEFTxvR1UzgOqgP1JJIgIDpG3E4i4cEZ7J8ZlaNfLkz1WD15BDXHpHcPkE3lrLi/lHMEQCIC4j5ihiNgV2oU9YlBLykbhO46/j8Z8eAsmp2HtP7YlpAiAKzgD7NY/OT6JP4dit5sjOnuYtzh0nm5DXO05SFloTmAEBBSUhA6RtxOIuHBGeyfGZWjXy5M9Vg9eQQ1x6R3D5BN5ay4v5rVGyIgYDpG3E4i4cEZ7J8ZlaNfLkz1WD15BDXHpHcPkE3lrLi/kI7QmAqwAAAAAM/AlsaWdodG5pbmcBCAU2hruIvIHrDPwJbGlnaHRuaW5nAgIAAQABAP0qAQEAAAAAAQH/0h9RflGgWKtkgrf56Lvb0rUobrhIOhTwcM+NmIkNKQAAAAAA/////wEuWx4AAAAAABYAFKHoOpmce16DZrQEZH7V+JP+/y6sA0gwRQIhAI+LLQh/G/oNRqePyb0R6yhfSEc/yP0V6Cti/1kkK/PwAiBdvSa2uLgDW2XbwXvAVzBxFVZrLNxybntS2lyz+euiywEgWV6uBVDCzxkOUZ98rnVFC79uPiakDUAnOQrSkX5JPUxqggEgh2OpFG0bRi0KpOvy3VBKHBhCgHtCD9daiCECMy6tBttEFqwwYKNj2B8rTGlArAak70ptIeVDA2r6LydndQNhogqxdSEC7jd/4xMMFEl0hPMVqO8Q45Ji78odoDYvqCttkPvZt6dorAAAAAAM/AlsaWdodG5pbmcBCH87vQhiysC4AAEA/Z0BAgAAAAABAvB6IVCYPv0ng28Boi5DWjT8Iu+7VnivjfxNpPrG73OrAQAAAAD9////fA9s+2Srlzm17DlKwhRh+6gPKnM8629vAxtVZCnVIrIAAAAAAP3///8DWP2IAAAAAAAWABTLOlJDpOxjeEEODHpxxWqyUCXBOpq2LQAAAAAAFgAU99rC3PzJ7JF47Zkz6pjOAFPSWtX4jB4AAAAAACIAIMhDUyNE62r0XElEok1XhBe39KGewKnw2wdQKSoUfYjKAkcwRAIgd9pEPhXZypnSOkAyKtXC/CdNamQ/qkXXxDYUnK7VjyACIGJORtWT1YVHfVJ3mMkOAPub/mb+ZWZjyWRP/cdJSOgoASEDp6bb50UoFqPN0UrAPzGb+B2kN/WjZ6h8gYpgCvWP/rMCRzBEAiAizM/eUhu2VLPbj490jkVL8zQoHkhD8ifUGdJ6pncoMQIgPI7IRfhxNrO3OfD5IEDkf1YpZTS/PrJzXsWiuzZ79T4BIQLuiWdS530flKFu+ZEnDssecpFTobBG2q0Er08sG9CGK1ieCgABAR9Y/YgAAAAAABYAFMs6UkOk7GN4QQ4MenHFarJQJcE6IgIDgqd2l8O+iYomobEnbUm/SkF77ModebdszzhKrQdoO81HMEQCIGMYEyX9E2lKN9ZGErPLT7rLUT6jiMavmf9KvVGyQhKzAiBl3tkmpLT3aBA/bHiWBp30kIH/MZEUVlJ2FjK8Qxf03AEiBgOCp3aXw76JiiahsSdtSb9KQXvsyh15t2zPOEqtB2g7zQjLOlJDAAAAAAz8CWxpZ2h0bmluZwEIyr1nYR+yWpMM/AlsaWdodG5pbmcCAgABAAz8CWxpZ2h0bmluZwEIPmp7W2cbgzQADPwJbGlnaHRuaW5nAQhfGBujAwg9RgAM/AlsaWdodG5pbmcBCLlmPrAtodZRAA==", strlen("cHNidP8BAO4CAAAAAzN5VhNaE8Vcck3HxVgzwzZ222MTllIAnbHt0n14wqK3AwAAAAABAAAAA6eMOG9Offcfn4WU8H2d0Z6kxU7rcAqvyvtranQVGTwAAAAAAP3///90da/+7PPocKC7hy/NS8LJl91lxs8w0QDITv4yiUOK2wAAAAAA/f///wOMnh4AAAAAACIAIHbV3spzDYJViRvskhH+rV1dx9dvac3CR5/iDdsa1rOBSP4OAAAAAAAWABRrnRZ3l/w3gUj80T2t5objcD9W0O7mfAAAAAAAFgAUtmotjMoZeRMsAbICfElGqwiW3UocpwoAAAEA/bsBAgAAAAABAXPfLv55YUFV5bYj2nW0Qg21s+wun9ml6OSboVUZk2wLAAAAAABatvuABEoBAAAAAAAAIgAgcvZQbEPQgaQZheQRE2h0qKIYGEvEnR8AMgqGtqkMQ0JKAQAAAAAAACIAIPKe3p1VfFQC7ANr0L8T5jqBNZiRsy1otltPruOm62IUYcYCAAAAAAAiACCvU6YsJg1wnAODdsViE6KHEB7x8larBFmohA/vXE5ynYAsAwAAAAAAIgAgH/GZYEVN/fM86vqoSYtZ1PxX4cQVPG9HVTOA6qA/UkkEAEcwRAIgI5QU3lRHdW78aZwx4QptrEtqcx7bOcVBU+6j636qYG0CIHJnhPaHlHVjUI88gFWlFM957z/5JCSYWxJacc4w5C4rAUcwRAIgGc5N3cKTLBY4gZrZDZQa+mxGGDlKWRNkcwu70AOrO2oCIH1KSDAF8EhRXCVPAXJ15naYm34QdL3cP/ZGvFO0HYqYAUdSIQIxs+uJrVTubrGY2Jfk4utUK+VWAvMEyP78BtPi4yRXFyECa/fDQc/qrr4ySj2F8lKL/QTmVYx8pmYpd8Sz1NSqbMtSroDGayABASuALAMAAAAAACIAIB/xmWBFTf3zPOr6qEmLWdT8V+HEFTxvR1UzgOqgP1JJIgIDpG3E4i4cEZ7J8ZlaNfLkz1WD15BDXHpHcPkE3lrLi/lHMEQCIC4j5ihiNgV2oU9YlBLykbhO46/j8Z8eAsmp2HtP7YlpAiAKzgD7NY/OT6JP4dit5sjOnuYtzh0nm5DXO05SFloTmAEBBSUhA6RtxOIuHBGeyfGZWjXy5M9Vg9eQQ1x6R3D5BN5ay4v5rVGyIgYDpG3E4i4cEZ7J8ZlaNfLkz1WD15BDXHpHcPkE3lrLi/kI7QmAqwAAAAAM/AlsaWdodG5pbmcBCAU2hruIvIHrDPwJbGlnaHRuaW5nAgIAAQABAP0qAQEAAAAAAQH/0h9RflGgWKtkgrf56Lvb0rUobrhIOhTwcM+NmIkNKQAAAAAA/////wEuWx4AAAAAABYAFKHoOpmce16DZrQEZH7V+JP+/y6sA0gwRQIhAI+LLQh/G/oNRqePyb0R6yhfSEc/yP0V6Cti/1kkK/PwAiBdvSa2uLgDW2XbwXvAVzBxFVZrLNxybntS2lyz+euiywEgWV6uBVDCzxkOUZ98rnVFC79uPiakDUAnOQrSkX5JPUxqggEgh2OpFG0bRi0KpOvy3VBKHBhCgHtCD9daiCECMy6tBttEFqwwYKNj2B8rTGlArAak70ptIeVDA2r6LydndQNhogqxdSEC7jd/4xMMFEl0hPMVqO8Q45Ji78odoDYvqCttkPvZt6dorAAAAAAM/AlsaWdodG5pbmcBCH87vQhiysC4AAEA/Z0BAgAAAAABAvB6IVCYPv0ng28Boi5DWjT8Iu+7VnivjfxNpPrG73OrAQAAAAD9////fA9s+2Srlzm17DlKwhRh+6gPKnM8629vAxtVZCnVIrIAAAAAAP3///8DWP2IAAAAAAAWABTLOlJDpOxjeEEODHpxxWqyUCXBOpq2LQAAAAAAFgAU99rC3PzJ7JF47Zkz6pjOAFPSWtX4jB4AAAAAACIAIMhDUyNE62r0XElEok1XhBe39KGewKnw2wdQKSoUfYjKAkcwRAIgd9pEPhXZypnSOkAyKtXC/CdNamQ/qkXXxDYUnK7VjyACIGJORtWT1YVHfVJ3mMkOAPub/mb+ZWZjyWRP/cdJSOgoASEDp6bb50UoFqPN0UrAPzGb+B2kN/WjZ6h8gYpgCvWP/rMCRzBEAiAizM/eUhu2VLPbj490jkVL8zQoHkhD8ifUGdJ6pncoMQIgPI7IRfhxNrO3OfD5IEDkf1YpZTS/PrJzXsWiuzZ79T4BIQLuiWdS530flKFu+ZEnDssecpFTobBG2q0Er08sG9CGK1ieCgABAR9Y/YgAAAAAABYAFMs6UkOk7GN4QQ4MenHFarJQJcE6IgIDgqd2l8O+iYomobEnbUm/SkF77ModebdszzhKrQdoO81HMEQCIGMYEyX9E2lKN9ZGErPLT7rLUT6jiMavmf9KvVGyQhKzAiBl3tkmpLT3aBA/bHiWBp30kIH/MZEUVlJ2FjK8Qxf03AEiBgOCp3aXw76JiiahsSdtSb9KQXvsyh15t2zPOEqtB2g7zQjLOlJDAAAAAAz8CWxpZ2h0bmluZwEIyr1nYR+yWpMM/AlsaWdodG5pbmcCAgABAAz8CWxpZ2h0bmluZwEIPmp7W2cbgzQADPwJbGlnaHRuaW5nAQhfGBujAwg9RgAM/AlsaWdodG5pbmcBCLlmPrAtodZRAA==")); + /* Round-trip versioning of both PSBTs as belt and suspender check */ + tal_wally_start(); + wally_psbt_set_version(oldpsbt, 0 /* flags */, 2); + wally_psbt_set_version(oldpsbt, 0 /* flags */, 0); + wally_psbt_set_version(oldpsbt, 0 /* flags */, 2); + tal_wally_end(oldpsbt); + + tal_wally_start(); + wally_psbt_set_version(newpsbt, 0 /* flags */, 2); + wally_psbt_set_version(newpsbt, 0 /* flags */, 0); + wally_psbt_set_version(newpsbt, 0 /* flags */, 2); + tal_wally_end(newpsbt); + assert(!psbt_contribs_changed(oldpsbt, newpsbt)); } diff --git a/common/test/run-route_blinding_onion_test.c b/common/test/run-route_blinding_onion_test.c index df9452c3f01a..29a52c3e2218 100644 --- a/common/test/run-route_blinding_onion_test.c +++ b/common/test/run-route_blinding_onion_test.c @@ -14,11 +14,7 @@ #include "../onion_encode.c" #include "../sphinx.c" #include "../type_to_string.c" -#if EXPERIMENTAL_FEATURES - #include "../../wire/onion_exp_wiregen.c" -#else - #include "../../wire/onion_wiregen.c" -#endif +#include "../../wire/onion_wiregen.c" #include #include #include diff --git a/common/test/run-softref.c b/common/test/run-softref.c index 5f5642d143ab..e4294219b4c4 100644 --- a/common/test/run-softref.c +++ b/common/test/run-softref.c @@ -21,12 +21,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-sphinx-xor_cipher_stream.c b/common/test/run-sphinx-xor_cipher_stream.c index 7875d5ed8d3c..b103fad71bcd 100644 --- a/common/test/run-sphinx-xor_cipher_stream.c +++ b/common/test/run-sphinx-xor_cipher_stream.c @@ -18,12 +18,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-sphinx.c b/common/test/run-sphinx.c index 47de12e0558a..a682867c2072 100644 --- a/common/test/run-sphinx.c +++ b/common/test/run-sphinx.c @@ -32,12 +32,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-tlv_span.c b/common/test/run-tlv_span.c index 0fc9d03c804b..5502dc6d4a5f 100644 --- a/common/test/run-tlv_span.c +++ b/common/test/run-tlv_span.c @@ -20,12 +20,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-wireaddr.c b/common/test/run-wireaddr.c index 8712563b009a..d5f72b251c09 100644 --- a/common/test/run-wireaddr.c +++ b/common/test/run-wireaddr.c @@ -32,12 +32,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, @@ -122,120 +128,163 @@ void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNE int main(int argc, char *argv[]) { - const char *err; struct wireaddr_internal addr, *expect = tal(NULL, struct wireaddr_internal); common_setup(argv[0]); /* Simple IPv4 address. */ - assert(parse_wireaddr_internal("127.0.0.1", &addr, DEFAULT_PORT, false, false, false, &err)); + assert(parse_wireaddr_internal(tmpctx, "127.0.0.1", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_WIREADDR; - assert(parse_wireaddr("127.0.0.1:9735", &expect->u.wireaddr, 0, NULL, &err)); + expect->u.wireaddr.is_websocket = false; + assert(parse_wireaddr(tmpctx, "127.0.0.1:9735", 0, NULL, &expect->u.wireaddr.wireaddr) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* IPv4 address with port. */ - assert(parse_wireaddr_internal("127.0.0.1:1", &addr, DEFAULT_PORT, false, false, false, &err)); + assert(parse_wireaddr_internal(tmpctx, "127.0.0.1:1", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_WIREADDR; - assert(parse_wireaddr("127.0.0.1:1", &expect->u.wireaddr, 0, NULL, &err)); + expect->u.wireaddr.is_websocket = false; + assert(parse_wireaddr(tmpctx, "127.0.0.1:1", 0, NULL, &expect->u.wireaddr.wireaddr) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* Simple IPv6 address. */ - assert(parse_wireaddr_internal("::1", &addr, DEFAULT_PORT, false, false, false, &err)); + assert(parse_wireaddr_internal(tmpctx, "::1", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_WIREADDR; - assert(parse_wireaddr("::1", &expect->u.wireaddr, DEFAULT_PORT, NULL, &err)); + expect->u.wireaddr.is_websocket = false; + assert(parse_wireaddr(tmpctx, "::1", DEFAULT_PORT, NULL, &expect->u.wireaddr.wireaddr) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* IPv6 address with port. */ - assert(parse_wireaddr_internal("[::1]:1", &addr, DEFAULT_PORT, false, false, false, &err)); + assert(parse_wireaddr_internal(tmpctx, "[::1]:1", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_WIREADDR; - assert(parse_wireaddr("::1", &expect->u.wireaddr, 1, NULL, &err)); + expect->u.wireaddr.is_websocket = false; + assert(parse_wireaddr(tmpctx, "::1", 1, NULL, &expect->u.wireaddr.wireaddr) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* autotor address */ - assert(parse_wireaddr_internal("autotor:127.0.0.1", &addr, DEFAULT_PORT, false, false, false, &err)); + assert(parse_wireaddr_internal(tmpctx, "autotor:127.0.0.1", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_AUTOTOR; expect->u.torservice.port = DEFAULT_PORT; - assert(parse_wireaddr("127.0.0.1", &expect->u.torservice.address, 9051, NULL, &err)); + assert(parse_wireaddr(tmpctx, "127.0.0.1", 9051, NULL, &expect->u.torservice.address) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* autotor address with port */ - assert(parse_wireaddr_internal("autotor:127.0.0.1:9055", &addr, DEFAULT_PORT, false, false, false, &err)); + assert(parse_wireaddr_internal(tmpctx, "autotor:127.0.0.1:9055", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_AUTOTOR; expect->u.torservice.port = DEFAULT_PORT; - assert(parse_wireaddr("127.0.0.1", &expect->u.torservice.address, 9055, NULL, &err)); + assert(parse_wireaddr(tmpctx, "127.0.0.1", 9055, NULL, &expect->u.torservice.address) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* autotor address with torport */ - assert(parse_wireaddr_internal("autotor:127.0.0.1/torport=9055", &addr, DEFAULT_PORT, false, false, false, &err)); + assert(parse_wireaddr_internal(tmpctx, "autotor:127.0.0.1/torport=9055", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_AUTOTOR; expect->u.torservice.port = 9055; - assert(parse_wireaddr("127.0.0.1", &expect->u.torservice.address, 9051, NULL, &err)); + assert(parse_wireaddr(tmpctx, "127.0.0.1", 9051, NULL, &expect->u.torservice.address) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* autotor address with port and torport */ - assert(parse_wireaddr_internal("autotor:127.0.0.1:9055/torport=10055", &addr, DEFAULT_PORT, false, false, false, &err)); + assert(parse_wireaddr_internal(tmpctx, "autotor:127.0.0.1:9055/torport=10055", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_AUTOTOR; expect->u.torservice.port = 10055; - assert(parse_wireaddr("127.0.0.1", &expect->u.torservice.address, 9055, NULL, &err)); + assert(parse_wireaddr(tmpctx, "127.0.0.1", 9055, NULL, &expect->u.torservice.address) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* statictor address */ - assert(parse_wireaddr_internal("statictor:127.0.0.1", &addr, DEFAULT_PORT, false, false, false, &err)); + assert(parse_wireaddr_internal(tmpctx, "statictor:127.0.0.1", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_STATICTOR; expect->u.torservice.port = DEFAULT_PORT; memset(expect->u.torservice.blob, 0, sizeof(expect->u.torservice.blob)); strcpy((char *)expect->u.torservice.blob, STATIC_TOR_MAGIC_STRING); - assert(parse_wireaddr("127.0.0.1", &expect->u.torservice.address, 9051, NULL, &err)); + assert(parse_wireaddr(tmpctx, "127.0.0.1", 9051, NULL, &expect->u.torservice.address) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* statictor address with port */ - assert(parse_wireaddr_internal("statictor:127.0.0.1:9055", &addr, DEFAULT_PORT, false, false, false, &err)); + assert(parse_wireaddr_internal(tmpctx, "statictor:127.0.0.1:9055", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_STATICTOR; expect->u.torservice.port = DEFAULT_PORT; - assert(parse_wireaddr("127.0.0.1", &expect->u.torservice.address, 9055, NULL, &err)); + assert(parse_wireaddr(tmpctx, "127.0.0.1", 9055, NULL, &expect->u.torservice.address) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* statictor address with torport */ - assert(parse_wireaddr_internal("statictor:127.0.0.1/torport=9055", &addr, DEFAULT_PORT, false, false, false, &err)); + assert(parse_wireaddr_internal(tmpctx, "statictor:127.0.0.1/torport=9055", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_STATICTOR; expect->u.torservice.port = 9055; - assert(parse_wireaddr("127.0.0.1", &expect->u.torservice.address, 9051, NULL, &err)); + assert(parse_wireaddr(tmpctx, "127.0.0.1", 9051, NULL, &expect->u.torservice.address) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* statictor address with port and torport */ - assert(parse_wireaddr_internal("statictor:127.0.0.1:9055/torport=10055", &addr, DEFAULT_PORT, false, false, false, &err)); + assert(parse_wireaddr_internal(tmpctx, "statictor:127.0.0.1:9055/torport=10055", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_STATICTOR; expect->u.torservice.port = 10055; - assert(parse_wireaddr("127.0.0.1", &expect->u.torservice.address, 9055, NULL, &err)); + assert(parse_wireaddr(tmpctx, "127.0.0.1", 9055, NULL, &expect->u.torservice.address) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* statictor address with port and torport and torblob */ - assert(parse_wireaddr_internal("statictor:127.0.0.1:9055/torport=10055/torblob=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", &addr, DEFAULT_PORT, false, false, false, &err)); + assert(parse_wireaddr_internal(tmpctx, "statictor:127.0.0.1:9055/torport=10055/torblob=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_STATICTOR; expect->u.torservice.port = 10055; /* This is actually nul terminated */ memset(expect->u.torservice.blob, 'x', sizeof(expect->u.torservice.blob)-1); - assert(parse_wireaddr("127.0.0.1", &expect->u.torservice.address, 9055, NULL, &err)); + assert(parse_wireaddr(tmpctx, "127.0.0.1", 9055, NULL, &expect->u.torservice.address) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* local socket path */ - assert(parse_wireaddr_internal("/tmp/foo.sock", &addr, DEFAULT_PORT, false, false, false, &err)); + assert(parse_wireaddr_internal(tmpctx, "/tmp/foo.sock", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_SOCKNAME; strcpy(expect->u.sockname, "/tmp/foo.sock"); assert(wireaddr_internal_eq(&addr, expect)); + /* Websocket (only for IP addresses) */ + assert(parse_wireaddr_internal(tmpctx, "ws:/tmp/foo.sock", DEFAULT_PORT, false, &addr) != NULL); + + assert(parse_wireaddr_internal(tmpctx, "ws:127.0.0.1", DEFAULT_PORT, false, &addr) == NULL); + expect->itype = ADDR_INTERNAL_WIREADDR; + expect->u.wireaddr.is_websocket = true; + assert(parse_wireaddr(tmpctx, "127.0.0.1:9735", 0, NULL, &expect->u.wireaddr.wireaddr) == NULL); + assert(wireaddr_internal_eq(&addr, expect)); + + /* Websocket: IPv4 address with port. */ + assert(parse_wireaddr_internal(tmpctx, "ws:127.0.0.1:1", DEFAULT_PORT, false, &addr) == NULL); + expect->itype = ADDR_INTERNAL_WIREADDR; + expect->u.wireaddr.is_websocket = true; + assert(parse_wireaddr(tmpctx, "127.0.0.1:1", 0, NULL, &expect->u.wireaddr.wireaddr) == NULL); + assert(wireaddr_internal_eq(&addr, expect)); + + /* Websocket: Simple IPv6 address. */ + assert(parse_wireaddr_internal(tmpctx, "ws:::1", DEFAULT_PORT, false, &addr) == NULL); + expect->itype = ADDR_INTERNAL_WIREADDR; + expect->u.wireaddr.is_websocket = true; + assert(parse_wireaddr(tmpctx, "::1", DEFAULT_PORT, NULL, &expect->u.wireaddr.wireaddr) == NULL); + assert(wireaddr_internal_eq(&addr, expect)); + + /* Websocket: IPv6 address with port. */ + assert(parse_wireaddr_internal(tmpctx, "ws:[::1]:1", DEFAULT_PORT, false, &addr) == NULL); + expect->itype = ADDR_INTERNAL_WIREADDR; + expect->u.wireaddr.is_websocket = true; + assert(parse_wireaddr(tmpctx, "::1", 1, NULL, &expect->u.wireaddr.wireaddr) == NULL); + assert(wireaddr_internal_eq(&addr, expect)); + + /* Websocket: IPv4 & v6 address. */ + assert(parse_wireaddr_internal(tmpctx, "ws:", DEFAULT_PORT, false, &addr) == NULL); + expect->itype = ADDR_INTERNAL_ALLPROTO; + expect->u.allproto.is_websocket = true; + expect->u.allproto.port = DEFAULT_PORT; + assert(wireaddr_internal_eq(&addr, expect)); + + /* Websocket: IPv4 & v6 address with port */ + assert(parse_wireaddr_internal(tmpctx, "ws::1", DEFAULT_PORT, false, &addr) == NULL); + expect->itype = ADDR_INTERNAL_ALLPROTO; + expect->u.allproto.is_websocket = true; + expect->u.allproto.port = 1; + assert(wireaddr_internal_eq(&addr, expect)); + /* Unresolved */ - assert(!parse_wireaddr_internal("ozlabs.org", &addr, DEFAULT_PORT, false, false, false, &err)); - assert(streq(err, "Needed DNS, but lookups suppressed")); - assert(parse_wireaddr_internal("ozlabs.org", &addr, DEFAULT_PORT, false, false, true, &err)); + assert(parse_wireaddr_internal(tmpctx, "ozlabs.org", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_FORPROXY; strcpy(expect->u.unresolved.name, "ozlabs.org"); expect->u.unresolved.port = DEFAULT_PORT; assert(wireaddr_internal_eq(&addr, expect)); /* Unresolved with port */ - assert(!parse_wireaddr_internal("ozlabs.org:1234", &addr, DEFAULT_PORT, false, false, false, &err)); - assert(streq(err, "Needed DNS, but lookups suppressed")); - assert(parse_wireaddr_internal("ozlabs.org:1234", &addr, DEFAULT_PORT, false, false, true, &err)); + assert(parse_wireaddr_internal(tmpctx, "ozlabs.org:1234", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_FORPROXY; strcpy(expect->u.unresolved.name, "ozlabs.org"); expect->u.unresolved.port = 1234; diff --git a/common/tx_roles.c b/common/tx_roles.c new file mode 100644 index 000000000000..541deb7b0696 --- /dev/null +++ b/common/tx_roles.c @@ -0,0 +1,18 @@ +#include "config.h" +#include +#include + +void towire_tx_role(u8 **pptr, const enum tx_role tx_role) +{ + towire_u8(pptr, tx_role); +} + +enum tx_role fromwire_tx_role(const u8 **cursor, size_t *max) +{ + u8 tx_role = fromwire_u8(cursor, max); + if (tx_role >= NUM_TX_ROLES) { + tx_role = TX_INITIATOR; + fromwire_fail(cursor, max); + } + return tx_role; +} diff --git a/common/tx_roles.h b/common/tx_roles.h index 5a65dbc1035e..9b7b5bbb9ad3 100644 --- a/common/tx_roles.h +++ b/common/tx_roles.h @@ -2,6 +2,8 @@ #define LIGHTNING_COMMON_TX_ROLES_H #include "config.h" +#include +#include #define NUM_TX_ROLES (TX_ACCEPTER + 1) enum tx_role { @@ -9,4 +11,7 @@ enum tx_role { TX_ACCEPTER, }; + +void towire_tx_role(u8 **pptr, const enum tx_role tx_role); +enum tx_role fromwire_tx_role(const u8 **cursor, size_t *max); #endif /* LIGHTNING_COMMON_TX_ROLES_H */ diff --git a/common/utils.h b/common/utils.h index dcfa111cbc9e..abf3ca6848e0 100644 --- a/common/utils.h +++ b/common/utils.h @@ -80,11 +80,22 @@ void clear_softref_(const tal_t *outer, size_t outersize, void **ptr); * Remove an element from an array * * This will shift the elements past the removed element, changing - * their position in memory, so only use this for arrays of pointers. + * their position in memory, so only use this for simple arrays. */ #define tal_arr_remove(p, n) tal_arr_remove_((p), sizeof(**p), (n)) void tal_arr_remove_(void *p, size_t elemsize, size_t n); +/** + * Insert an element in an array + */ +#define tal_arr_insert(p, n, v) \ + do { \ + size_t n_ = tal_count(*(p)); \ + tal_resize((p), n_+1); \ + memmove(*(p) + n + 1, *(p) + n, (n_ - n) * sizeof(**(p))); \ + (*(p))[n] = (v); \ + } while(0) + /* Check for valid UTF-8 */ bool utf8_check(const void *buf, size_t buflen); @@ -112,10 +123,10 @@ void tal_wally_end(const tal_t *parent); /* ... or this if you want to reparent onto something which is * allocated by libwally here. Fixes up this from_wally obj to have a * proper tal_name, too! */ -#define tal_wally_end_onto(parent, from_wally, type) \ - tal_wally_end_onto_((parent), \ - (from_wally) + 0*sizeof((from_wally) == (type *)0), \ - stringify(type)) +#define tal_wally_end_onto(parent, from_wally, type) \ + tal_wally_end_onto_( \ + (parent), (from_wally), \ + &stringify(type)[0 * sizeof((from_wally) == (type *)0)]) void tal_wally_end_onto_(const tal_t *parent, tal_t *from_wally, const char *from_wally_name); @@ -142,13 +153,6 @@ STRUCTEQ_DEF(ripemd160, 0, u); #define IFDEV(dev, nondev) (nondev) #endif -#if EXPERIMENTAL_FEATURES -/* Make sure that nondev is evaluated, and valid, but is a constant */ -#define IFEXPERIMENTAL(exp, nonexp) (0 ? (nonexp) : (exp)) -#else -#define IFEXPERIMENTAL(exp, nonexp) (nonexp) -#endif - /* Context which all wally allocations use (see common/setup.c) */ extern const tal_t *wally_tal_ctx; diff --git a/common/version.c b/common/version.c index 4fc20b6667e0..0840968fdb75 100644 --- a/common/version.c +++ b/common/version.c @@ -1,5 +1,6 @@ #include "config.h" #include +#include #include #include #include @@ -13,7 +14,7 @@ const char *version(void) return VERSION; } -char *version_and_exit(const void *unused UNUSED) +static char *version_and_exit(const void *unused UNUSED) { printf("%s\n", VERSION); if (BUILD_FEATURES[0]) { @@ -22,6 +23,13 @@ char *version_and_exit(const void *unused UNUSED) exit(0); } +void opt_register_version(void) +{ + clnopt_noarg("--version|-V", OPT_EARLY|OPT_EXITS, + version_and_exit, NULL, + "Print version and exit"); +} + static bool cmp_release_version(const char *version) { if (version[0] != 'v') return false; diff --git a/common/version.h b/common/version.h index 90b7c824d12b..aebc002ed24a 100644 --- a/common/version.h +++ b/common/version.h @@ -3,15 +3,14 @@ #include "config.h" #include -char *version_and_exit(const void *unused); +/* Add --version|-V option */ +void opt_register_version(void); + const char *version(void); /* check if the current version is a release version. * * Released versions are of form v[year].[month]?(.patch)* */ bool is_released_version(void); -#define opt_register_version() \ - opt_register_early_noarg("--version|-V", version_and_exit, NULL, \ - "Print version and exit") #endif /* LIGHTNING_COMMON_VERSION_H */ diff --git a/common/wire_error.c b/common/wire_error.c index 189c573a852e..457dc72b738d 100644 --- a/common/wire_error.c +++ b/common/wire_error.c @@ -93,6 +93,8 @@ char *sanitize_error(const tal_t *ctx, const u8 *errmsg, warning = false; else if (fromwire_warning(ctx, errmsg, channel_id, &data)) warning = true; + else if (fromwire_tx_abort(ctx, errmsg, channel_id, &data)) + warning = false; else return tal_fmt(ctx, "Invalid ERROR message '%s'", tal_hex(ctx, errmsg)); diff --git a/common/wireaddr.c b/common/wireaddr.c index 1c8be2fa88fa..174c5c22ca47 100644 --- a/common/wireaddr.c +++ b/common/wireaddr.c @@ -50,9 +50,6 @@ bool fromwire_wireaddr(const u8 **cursor, size_t *max, struct wireaddr *addr) memset(&addr->addr, 0, sizeof(addr->addr)); addr->addr[addr->addrlen] = 0; break; - case ADDR_TYPE_WEBSOCKET: - addr->addrlen = 0; - break; default: return false; } @@ -101,10 +98,12 @@ void towire_wireaddr_internal(u8 **pptr, const struct wireaddr_internal *addr) towire_u16(pptr, addr->u.torservice.port); return; case ADDR_INTERNAL_ALLPROTO: - towire_u16(pptr, addr->u.port); + towire_bool(pptr, addr->u.allproto.is_websocket); + towire_u16(pptr, addr->u.allproto.port); return; case ADDR_INTERNAL_WIREADDR: - towire_wireaddr(pptr, &addr->u.wireaddr); + towire_bool(pptr, addr->u.wireaddr.is_websocket); + towire_wireaddr(pptr, &addr->u.wireaddr.wireaddr); return; case ADDR_INTERNAL_FORPROXY: towire_u8_array(pptr, (const u8 *)addr->u.unresolved.name, @@ -128,7 +127,8 @@ bool fromwire_wireaddr_internal(const u8 **cursor, size_t *max, fromwire_fail(cursor, max); return *cursor != NULL; case ADDR_INTERNAL_ALLPROTO: - addr->u.port = fromwire_u16(cursor, max); + addr->u.allproto.is_websocket = fromwire_bool(cursor, max); + addr->u.allproto.port = fromwire_u16(cursor, max); return *cursor != NULL; case ADDR_INTERNAL_AUTOTOR: fromwire_wireaddr(cursor, max, &addr->u.torservice.address); @@ -141,7 +141,8 @@ bool fromwire_wireaddr_internal(const u8 **cursor, size_t *max, addr->u.torservice.port = fromwire_u16(cursor, max); return *cursor != NULL; case ADDR_INTERNAL_WIREADDR: - return fromwire_wireaddr(cursor, max, &addr->u.wireaddr); + addr->u.wireaddr.is_websocket = fromwire_bool(cursor, max); + return fromwire_wireaddr(cursor, max, &addr->u.wireaddr.wireaddr); case ADDR_INTERNAL_FORPROXY: fromwire_u8_array(cursor, max, (u8 *)addr->u.unresolved.name, sizeof(addr->u.unresolved.name)); @@ -178,14 +179,6 @@ void wireaddr_from_ipv6(struct wireaddr *addr, memcpy(&addr->addr, ip6, addr->addrlen); } -void wireaddr_from_websocket(struct wireaddr *addr, const u16 port) -{ - addr->type = ADDR_TYPE_WEBSOCKET; - addr->addrlen = 0; - addr->port = port; - memset(addr->addr, 0, sizeof(addr->addr)); -} - bool wireaddr_to_ipv4(const struct wireaddr *addr, struct sockaddr_in *s4) { if (addr->type != ADDR_TYPE_IPV4) @@ -210,14 +203,6 @@ bool wireaddr_to_ipv6(const struct wireaddr *addr, struct sockaddr_in6 *s6) return true; } -bool wireaddr_to_websocket(const struct wireaddr *addr, u16 *port) -{ - if (addr->type != ADDR_TYPE_WEBSOCKET) - return false; - *port = addr->port; - return true; -} - bool wireaddr_is_wildcard(const struct wireaddr *addr) { switch (addr->type) { @@ -227,7 +212,6 @@ bool wireaddr_is_wildcard(const struct wireaddr *addr) case ADDR_TYPE_TOR_V2_REMOVED: case ADDR_TYPE_TOR_V3: case ADDR_TYPE_DNS: - case ADDR_TYPE_WEBSOCKET: return false; } abort(); @@ -240,9 +224,13 @@ char *fmt_wireaddr_internal(const tal_t *ctx, case ADDR_INTERNAL_SOCKNAME: return tal_fmt(ctx, "%s", a->u.sockname); case ADDR_INTERNAL_ALLPROTO: - return tal_fmt(ctx, ":%u", a->u.port); + return tal_fmt(ctx, "%s:%u", a->u.allproto.is_websocket ? "(ws)": "", + a->u.allproto.port); case ADDR_INTERNAL_WIREADDR: - return fmt_wireaddr(ctx, &a->u.wireaddr); + if (a->u.wireaddr.is_websocket) + return tal_fmt(ctx, "(ws)%s", + fmt_wireaddr(tmpctx, &a->u.wireaddr.wireaddr)); + return fmt_wireaddr(ctx, &a->u.wireaddr.wireaddr); case ADDR_INTERNAL_FORPROXY: return tal_fmt(ctx, "%s:%u", a->u.unresolved.name, a->u.unresolved.port); @@ -277,8 +265,6 @@ char *fmt_wireaddr_without_port(const tal_t * ctx, const struct wireaddr *a) b32_encode(tmpctx, a->addr, a->addrlen)); case ADDR_TYPE_DNS: return tal_fmt(ctx, "%s", a->addr); - case ADDR_TYPE_WEBSOCKET: - return tal_strdup(ctx, "websocket"); } hex = tal_hexstr(ctx, a->addr, a->addrlen); @@ -516,53 +502,73 @@ wireaddr_from_hostname(const tal_t *ctx, return tal_free(addrs); } -bool parse_wireaddr(const char *arg, struct wireaddr *addr, u16 defport, - bool *no_dns, const char **err_msg) +const char *parse_wireaddr(const tal_t *ctx, + const char *arg, + u16 defport, + bool *no_dns, + struct wireaddr *addr) { struct in6_addr v6; struct in_addr v4; u16 port; char *ip; - bool res; + const char *err_msg; + struct wireaddr *addresses; + bool is_dns_waddr; - res = false; port = defport; - if (err_msg) - *err_msg = NULL; - if (!separate_address_and_port(tmpctx, arg, &ip, &port)) - goto finish; + if (strstarts(arg, "dns:")) { + is_dns_waddr = true; + arg += 4; + } else + is_dns_waddr = false; - if (streq(ip, "localhost")) - ip = "127.0.0.1"; - else if (streq(ip, "ip6-localhost")) - ip = "::1"; + if (!separate_address_and_port(tmpctx, arg, &ip, &port)) + return tal_strdup(ctx, "Error parsing hostname"); + + if (!is_dns_waddr) { + /* We resolved these even without DNS */ + if (streq(ip, "localhost")) + ip = "127.0.0.1"; + else if (streq(ip, "ip6-localhost")) + ip = "::1"; + } memset(&addr->addr, 0, sizeof(addr->addr)); if (inet_pton(AF_INET, ip, &v4) == 1) { + if (is_dns_waddr) + return tal_strdup(ctx, "dns: must be followed by a name"); wireaddr_from_ipv4(addr, &v4, port); - res = true; + return NULL; } else if (inet_pton(AF_INET6, ip, &v6) == 1) { + if (is_dns_waddr) + return tal_strdup(ctx, "dns: must be followed by a name"); wireaddr_from_ipv6(addr, &v6, port); - res = true; + return NULL; } - /* Resolve with getaddrinfo */ - if (!res) { - struct wireaddr *addresses = wireaddr_from_hostname(NULL, ip, port, - no_dns, NULL, err_msg); - if (addresses) { - *addr = addresses[0]; - tal_free(addresses); - res = true; - } + if (is_dns_waddr) { + addr->type = ADDR_TYPE_DNS; + if (strlen(ip) > DNS_ADDRLEN) + return "DNS address too long"; + + addr->addrlen = strlen(ip); + memcpy(addr->addr, ip, addr->addrlen); + addr->port = port; + return NULL; } -finish: - if (!res && err_msg && !*err_msg) - *err_msg = "Error parsing hostname"; - return res; + /* Resolve with getaddrinfo */ + addresses = wireaddr_from_hostname(NULL, ip, port, no_dns, NULL, &err_msg); + if (!addresses) + return tal_strdup(ctx, err_msg); + + /* FIXME: Allow return of multiple addresses? */ + *addr = addresses[0]; + tal_free(addresses); + return NULL; } bool wireaddr_internal_eq(const struct wireaddr_internal *a, @@ -575,7 +581,8 @@ bool wireaddr_internal_eq(const struct wireaddr_internal *a, case ADDR_INTERNAL_SOCKNAME: return streq(a->u.sockname, b->u.sockname); case ADDR_INTERNAL_ALLPROTO: - return a->u.port == b->u.port; + return a->u.allproto.is_websocket == b->u.allproto.is_websocket + && a->u.allproto.port == b->u.allproto.port; case ADDR_INTERNAL_STATICTOR: if (!memeq(a->u.torservice.blob, sizeof(a->u.torservice.blob), b->u.torservice.blob, sizeof(b->u.torservice.blob))) @@ -591,35 +598,36 @@ bool wireaddr_internal_eq(const struct wireaddr_internal *a, return false; return a->u.unresolved.port == b->u.unresolved.port; case ADDR_INTERNAL_WIREADDR: - return wireaddr_eq(&a->u.wireaddr, &b->u.wireaddr); + return a->u.wireaddr.is_websocket == b->u.wireaddr.is_websocket + && wireaddr_eq(&a->u.wireaddr.wireaddr, &b->u.wireaddr.wireaddr); } abort(); } -bool parse_wireaddr_internal(const char *arg, struct wireaddr_internal *addr, - u16 port, bool wildcard_ok, bool dns_ok, - bool unresolved_ok, - const char **err_msg) +const char *parse_wireaddr_internal(const tal_t *ctx, + const char *arg, + u16 default_port, + bool dns_lookup_ok, + struct wireaddr_internal *addr) { u16 splitport; - char *ip = NULL; + char *ip; char *service_addr; - bool needed_dns = false; + const char *err; + bool needed_dns, is_websocket; /* Addresses starting with '/' are local socket paths */ if (arg[0] == '/') { addr->itype = ADDR_INTERNAL_SOCKNAME; /* Check if the path is too long */ - if (strlen(arg) >= sizeof(addr->u.sockname)) { - if (err_msg) - *err_msg = "Socket name too long"; - return false; - } + if (strlen(arg) >= sizeof(addr->u.sockname)) + return "Socket name too long"; + /* Zero it out for passing across the wire */ memset(addr->u.sockname, 0, sizeof(addr->u.sockname)); strcpy(addr->u.sockname, arg); - return true; + return NULL; } /* 'autotor:' is a special prefix meaning talk to Tor to create @@ -635,22 +643,17 @@ bool parse_wireaddr_internal(const char *arg, struct wireaddr_internal *addr, char *endp = NULL; addr->u.torservice.port = strtol(parts[i]+strlen("torport="), &endp, 10); if (addr->u.torservice.port <= 0 || *endp != '\0') { - if (err_msg) - *err_msg = "Bad :torport: number"; - return false; + return "Bad :torport: number"; } } else { - if (err_msg) - *err_msg = tal_fmt(tmpctx, "unknown tor arg %s", parts[i]); - return false; + return tal_fmt(ctx, "unknown tor arg %s", parts[i]); } } service_addr = tal_fmt(tmpctx, "%s", parts[0] + strlen("autotor:")); - - return parse_wireaddr(service_addr, - &addr->u.torservice.address, 9051, - dns_ok ? NULL : &needed_dns, err_msg); + return parse_wireaddr(ctx, service_addr, 9051, + dns_lookup_ok ? NULL : &needed_dns, + &addr->u.torservice.address); } /* 'statictor:' is a special prefix meaning talk to Tor to create @@ -668,23 +671,17 @@ bool parse_wireaddr_internal(const char *arg, struct wireaddr_internal *addr, char *endp = NULL; addr->u.torservice.port = strtol(parts[i]+strlen("torport="), &endp, 10); if (addr->u.torservice.port <= 0 || *endp != '\0') { - if (err_msg) - *err_msg = "Bad :torport: number"; - return false; + return "Bad :torport: number"; } } else if (strstarts(parts[i], "torblob=")) { const char *blobdata = parts[i] + strlen("torblob="); if (strlen(blobdata) > TOR_V3_BLOBLEN) { - if (err_msg) - *err_msg = "torblob too long"; - return false; + return "torblob too long"; } strcpy(addr->u.torservice.blob, blobdata); use_magic_blob = false; } else { - if (err_msg) - *err_msg = tal_fmt(tmpctx, "unknown tor arg %s", parts[i]); - return false; + return tal_fmt(ctx, "unknown tor arg %s", parts[i]); } } @@ -695,49 +692,60 @@ bool parse_wireaddr_internal(const char *arg, struct wireaddr_internal *addr, service_addr = tal_fmt(tmpctx, "%s", parts[0] + strlen("statictor:")); - return parse_wireaddr(service_addr, - &addr->u.torservice.address, 9051, - dns_ok ? NULL : &needed_dns, err_msg); + return parse_wireaddr(ctx, service_addr, 9051, + dns_lookup_ok ? NULL : &needed_dns, + &addr->u.torservice.address); } - splitport = port; - if (!separate_address_and_port(tmpctx, arg, &ip, &splitport)) { - if (err_msg) { - *err_msg = tal_fmt(tmpctx, "Error parsing hostname %s %s", (char *)arg, ip); - } - return false; + /* Do this before we get to separate_address_and_port! */ + if (strstarts(arg, "ws:")) { + arg += 3; + is_websocket = true; + } else { + is_websocket = false; } + /* This can fail, but that may be OK! */ + splitport = default_port; + if (!separate_address_and_port(tmpctx, arg, &ip, &splitport)) + ip = NULL; + /* An empty string means IPv4 and IPv6 (which under Linux by default * means just IPv6, and IPv4 gets autobound). */ - if (wildcard_ok && is_wildcardaddr(ip)) { + if (ip && streq(ip, "")) { addr->itype = ADDR_INTERNAL_ALLPROTO; - addr->u.port = splitport; - return true; + addr->u.allproto.is_websocket = is_websocket; + addr->u.allproto.port = splitport; + return NULL; } - addr->itype = ADDR_INTERNAL_WIREADDR; - if (parse_wireaddr(arg, &addr->u.wireaddr, port, - dns_ok ? NULL : &needed_dns, err_msg)) { - if (addr->u.wireaddr.type == ADDR_TYPE_TOR_V2_REMOVED) { - if (err_msg) - *err_msg = "v2 Tor onion services not supported"; - return false; - } - - return true; + needed_dns = false; + err = parse_wireaddr(ctx, arg, default_port, + dns_lookup_ok ? NULL : &needed_dns, + &addr->u.wireaddr.wireaddr); + if (!err) { + addr->itype = ADDR_INTERNAL_WIREADDR; + addr->u.wireaddr.is_websocket = is_websocket; + return NULL; } - if (!needed_dns || !unresolved_ok) - return false; + /* Did we fail because we needed DNS lookup? If not, we just failed. */ + if (!needed_dns) + return err; - /* We can't do DNS, so keep unresolved. */ - if (!wireaddr_from_unresolved(addr, ip, splitport)) { - if (err_msg) - *err_msg = "Name too long"; - return false; - } - return true; + /* Invalid port, like foo:xxx or foo:0 */ + if (!ip) + return "Malformed port"; + + if (is_websocket) + return "Could not resolve websocket address"; + + /* Keep unresolved. */ + tal_free(err); + if (!wireaddr_from_unresolved(addr, ip, splitport)) + return "Name too long"; + + return NULL; } bool wireaddr_from_unresolved(struct wireaddr_internal *addr, @@ -794,7 +802,7 @@ struct addrinfo *wireaddr_internal_to_addrinfo(const tal_t *ctx, case ADDR_INTERNAL_FORPROXY: break; case ADDR_INTERNAL_WIREADDR: - return wireaddr_to_addrinfo(ctx, &wireaddr->u.wireaddr); + return wireaddr_to_addrinfo(ctx, &wireaddr->u.wireaddr.wireaddr); } abort(); } @@ -826,7 +834,6 @@ struct addrinfo *wireaddr_to_addrinfo(const tal_t *ctx, case ADDR_TYPE_TOR_V2_REMOVED: case ADDR_TYPE_TOR_V3: case ADDR_TYPE_DNS: - case ADDR_TYPE_WEBSOCKET: break; } abort(); @@ -875,14 +882,13 @@ bool all_tor_addresses(const struct wireaddr_internal *wireaddr) case ADDR_INTERNAL_STATICTOR: continue; case ADDR_INTERNAL_WIREADDR: - switch (wireaddr[i].u.wireaddr.type) { + switch (wireaddr[i].u.wireaddr.wireaddr.type) { case ADDR_TYPE_IPV4: case ADDR_TYPE_IPV6: case ADDR_TYPE_DNS: return false; case ADDR_TYPE_TOR_V2_REMOVED: case ADDR_TYPE_TOR_V3: - case ADDR_TYPE_WEBSOCKET: continue; } } diff --git a/common/wireaddr.h b/common/wireaddr.h index bdae7788fb30..7a34f70c442f 100644 --- a/common/wireaddr.h +++ b/common/wireaddr.h @@ -30,10 +30,6 @@ struct sockaddr_un; * * `5`: DNS hostname; data = `[byte:len][len*byte:hostname][u16:port]` (length up to 258) */ -/* BOLT-websockets #7: - * * `6`: WebSocket port; data = `[2:port]` (length 2) - */ - #define TOR_V2_ADDRLEN 10 #define TOR_V3_ADDRLEN 35 #define DNS_ADDRLEN 255 @@ -47,7 +43,6 @@ enum wire_addr_type { ADDR_TYPE_TOR_V2_REMOVED = 3, ADDR_TYPE_TOR_V3 = 4, ADDR_TYPE_DNS = 5, - ADDR_TYPE_WEBSOCKET = 6 }; struct wireaddr { @@ -75,10 +70,25 @@ enum addr_listen_announce fromwire_addr_listen_announce(const u8 **cursor, size_t *max); void towire_addr_listen_announce(u8 **pptr, enum addr_listen_announce ala); -/* If no_dns is non-NULL, we will set it to true and return false if - * we wanted to do a DNS lookup. */ -bool parse_wireaddr(const char *arg, struct wireaddr *addr, u16 port, - bool *no_dns, const char **err_msg); +/** + * parse_wireaddr - parse a string into the various defaults we have. + * @ctx: context to allocate returned error string + * @arg: the string + * @defport: the port to use if none specified in string + * @no_dns: if non-NULL, don't do DNS lookups. + * @addr: the addr to write, set if non-NULL return. + * + * If it returns NULL, check addr->itype to see if it's suitable for + * you! Otherwise, it returns a string allocated off @ctx. If you + * handed @no_dns, it will be set to true if the failure was due to + * the fact we wanted to do an DNS lookup, and false for other + * failures. + */ +const char *parse_wireaddr(const tal_t *ctx, + const char *arg, + u16 defport, + bool *no_dns, + struct wireaddr *addr); char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a); char *fmt_wireaddr_without_port(const tal_t *ctx, const struct wireaddr *a); @@ -98,10 +108,8 @@ void wireaddr_from_ipv4(struct wireaddr *addr, void wireaddr_from_ipv6(struct wireaddr *addr, const struct in6_addr *ip6, const u16 port); -void wireaddr_from_websocket(struct wireaddr *addr, const u16 port); bool wireaddr_to_ipv4(const struct wireaddr *addr, struct sockaddr_in *s4); bool wireaddr_to_ipv6(const struct wireaddr *addr, struct sockaddr_in6 *s6); -bool wireaddr_to_websocket(const struct wireaddr *addr, u16 *port); bool wireaddr_is_wildcard(const struct wireaddr *addr); @@ -119,9 +127,15 @@ struct wireaddr_internal { enum wireaddr_internal_type itype; union { /* ADDR_INTERNAL_WIREADDR */ - struct wireaddr wireaddr; + struct waddr { + struct wireaddr wireaddr; + bool is_websocket; + } wireaddr; /* ADDR_INTERNAL_ALLPROTO */ - u16 port; + struct allproto { + u16 port; + bool is_websocket; + } allproto; /* ADDR_INTERNAL_AUTOTOR * ADDR_INTERNAL_STATICTOR */ struct torservice { @@ -156,10 +170,21 @@ bool is_wildcardaddr(const char *arg); bool is_dnsaddr(const char *arg); -bool parse_wireaddr_internal(const char *arg, struct wireaddr_internal *addr, - u16 port, bool wildcard_ok, bool dns_ok, - bool unresolved_ok, - const char **err_msg); +/** + * parse_wireaddr_internal - parse a string into the various defaults we have. + * @ctx: context to allocate returned error string + * @arg: the string + * @default_port: the port to use if none specified in string + * @dns_lookup_ok: true if it's OK to do DNS name lookups. + * @addr: the addr to write, set if non-NULL return. + * + * If it returns NULL, you want to check addr->itype to see if it's + * suitable for you! */ +const char *parse_wireaddr_internal(const tal_t *ctx, + const char *arg, + u16 default_port, + bool dns_lookup_ok, + struct wireaddr_internal *addr); void towire_wireaddr_internal(u8 **pptr, const struct wireaddr_internal *addr); diff --git a/configure b/configure index a943baedfc87..52a4a4e86e19 100755 --- a/configure +++ b/configure @@ -142,17 +142,35 @@ set_defaults() CC=${CC:-cc} CDEBUGFLAGS=${CDEBUGFLAGS--std=gnu11 -g -fstack-protector-strong} DEVELOPER=${DEVELOPER:-0} - EXPERIMENTAL_FEATURES=${EXPERIMENTAL_FEATURES:-0} COMPAT=${COMPAT:-1} STATIC=${STATIC:-0} ASAN=${ASAN:-0} UBSAN=${UBSAN:-0} + FUZZING=${FUZZING:-0} + FUZZFLAGS="" + CSANFLAGS="" + if [ "$ASAN" != 0 ]; then + CSANFLAGS="$CSANFLAGS -fsanitize=address" + if [ "$DEVELOPER" != 0 ]; then + CSANFLAGS="$CSANFLAGS -fno-sanitize-recover=address" + fi + fi + if [ "$UBSAN" != 0 ]; then + CSANFLAGS="$CSANFLAGS -fsanitize=undefined" + if [ "$DEVELOPER" != 0 ]; then + CSANFLAGS="$CSANFLAGS -fno-sanitize-recover=undefined" + fi + fi + if [ "$FUZZING" != 0 ]; then + FUZZFLAGS="-fsanitize=fuzzer-no-link" + CSANFLAGS="$CSANFLAGS $FUZZFLAGS" + fi + echo CSANFLAGS = $CSANFLAGS PYTEST=${PYTEST-$(default_pytest)} COPTFLAGS=${COPTFLAGS-$(default_coptflags "$DEVELOPER")} CONFIGURATOR_CC=${CONFIGURATOR_CC-$CC} VALGRIND=${VALGRIND:-$(default_valgrind_setting)} TEST_NETWORK=${TEST_NETWORK:-regtest} - FUZZING=${FUZZING:-0} RUST=${RUST:-$(default_rust_setting)} } @@ -179,14 +197,12 @@ usage() echo " Prefix for make install" usage_with_default "--enable/disable-developer" "$DEVELOPER" "enable" "disable" echo " Developer mode, good for testing" - usage_with_default "--enable/disable-experimental-features" "$EXPERIMENTAL_FEATURES" "enable" "disable" - echo " Enable experimental features" usage_with_default "--enable/disable-compat" "$COMPAT" "enable" "disable" echo " Compatibility mode, good to disable to see if your software breaks" usage_with_default "--enable/disable-valgrind" "(autodetect)" echo " Run tests with Valgrind" usage_with_default "--enable/disable-static" "$STATIC" "enable" "disable" - echo " Static link sqlite3, gmp and zlib libraries" + echo " Static link sqlite3 and zlib libraries" usage_with_default "--enable/disable-address-sanitizer" "$ASAN" "enable" "disable" echo " Compile with address-sanitizer" usage_with_default "--enable/disable-ub-sanitizer" "$UBSAN" "enable" "disable" @@ -241,8 +257,6 @@ for opt in "$@"; do --prefix=*) PREFIX="${opt#--prefix=}";; --enable-developer) DEVELOPER=1;; --disable-developer) DEVELOPER=0;; - --enable-experimental-features) EXPERIMENTAL_FEATURES=1;; - --disable-experimental-features) EXPERIMENTAL_FEATURES=0;; --enable-compat) COMPAT=1;; --disable-compat) COMPAT=0;; --enable-valgrind) VALGRIND=1;; @@ -309,7 +323,7 @@ fi # Clean up on exit. trap "rm -f $CONFIG_VAR_FILE.$$" 0 -$CONFIGURATOR --extra-tests --autotools-style --var-file=$CONFIG_VAR_FILE.$$ --header-file=$CONFIG_HEADER.$$ --configurator-cc="$CONFIGURATOR_CC" --wrapper="$CONFIGURATOR_WRAPPER" "$CC" ${CWARNFLAGS-$BASE_WARNFLAGS} $CDEBUGFLAGS $COPTFLAGS -I$CPATH -L$LIBRARY_PATH $SQLITE3_CFLAGS $POSTGRES_INCLUDE < #include #include #include #include #include +#include #include #include #include @@ -31,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -47,6 +48,7 @@ #include #include #include +#include #include /*~ We are passed two file descriptors when exec'ed from `lightningd`: the @@ -231,6 +233,7 @@ static struct peer *new_peer(struct daemon *daemon, const struct node_id *id, const struct crypto_state *cs, const u8 *their_features, + enum is_websocket is_websocket, struct io_conn *conn STEALS, int *fd_for_subd) { @@ -247,6 +250,7 @@ static struct peer *new_peer(struct daemon *daemon, peer->draining = false; peer->peer_outq = msg_queue_new(peer, false); peer->last_recv_time = time_now(); + peer->is_websocket = is_websocket; #if DEVELOPER peer->dev_writes_enabled = NULL; @@ -272,6 +276,7 @@ struct io_plan *peer_connected(struct io_conn *conn, const struct wireaddr *remote_addr, struct crypto_state *cs, const u8 *their_features TAKES, + enum is_websocket is_websocket, bool incoming) { u8 *msg; @@ -305,8 +310,8 @@ struct io_plan *peer_connected(struct io_conn *conn, status_peer_unusual(id, "Unsupported feature %u", unsup); msg = towire_warningfmt(NULL, NULL, "Unsupported feature %u", unsup); - msg = cryptomsg_encrypt_msg(tmpctx, cs, take(msg)); - return io_write(conn, msg, tal_count(msg), io_close_cb, NULL); + msg = cryptomsg_encrypt_msg(NULL, cs, take(msg)); + return io_write_wire(conn, take(msg), io_close_cb, NULL); } if (!feature_check_depends(their_features, &depender, &missing)) { @@ -315,8 +320,8 @@ struct io_plan *peer_connected(struct io_conn *conn, msg = towire_warningfmt(NULL, NULL, "Feature %zu requires feature %zu", depender, missing); - msg = cryptomsg_encrypt_msg(tmpctx, cs, take(msg)); - return io_write(conn, msg, tal_count(msg), io_close_cb, NULL); + msg = cryptomsg_encrypt_msg(NULL, cs, take(msg)); + return io_write_wire(conn, take(msg), io_close_cb, NULL); } /* We've successfully connected. */ @@ -332,7 +337,7 @@ struct io_plan *peer_connected(struct io_conn *conn, conn, find_connecting(daemon, id)->conn); /* This contains the per-peer state info; gossipd fills in pps->gs */ - peer = new_peer(daemon, id, cs, their_features, conn, &subd_fd); + peer = new_peer(daemon, id, cs, their_features, is_websocket, conn, &subd_fd); /* Only takes over conn if it succeeds. */ if (!peer) return io_close(conn); @@ -370,13 +375,14 @@ static struct io_plan *handshake_in_success(struct io_conn *conn, const struct wireaddr_internal *addr, struct crypto_state *cs, struct oneshot *timeout, + enum is_websocket is_websocket, struct daemon *daemon) { struct node_id id; node_id_from_pubkey(&id, id_key); status_peer_debug(&id, "Connect IN"); return peer_exchange_initmsg(conn, daemon, daemon->our_features, - cs, &id, addr, timeout, true); + cs, &id, addr, timeout, is_websocket, true); } /*~ If the timer goes off, we simply free everything, which hangs up. */ @@ -404,12 +410,12 @@ static bool get_remote_address(struct io_conn *conn, if (s.ss_family == AF_INET6) { struct sockaddr_in6 *s6 = (void *)&s; addr->itype = ADDR_INTERNAL_WIREADDR; - wireaddr_from_ipv6(&addr->u.wireaddr, + wireaddr_from_ipv6(&addr->u.wireaddr.wireaddr, &s6->sin6_addr, ntohs(s6->sin6_port)); } else if (s.ss_family == AF_INET) { struct sockaddr_in *s4 = (void *)&s; addr->itype = ADDR_INTERNAL_WIREADDR; - wireaddr_from_ipv4(&addr->u.wireaddr, + wireaddr_from_ipv4(&addr->u.wireaddr.wireaddr, &s4->sin_addr, ntohs(s4->sin_port)); } else if (s.ss_family == AF_UNIX) { struct sockaddr_un *sun = (void *)&s; @@ -428,6 +434,7 @@ static bool get_remote_address(struct io_conn *conn, struct conn_in { struct wireaddr_internal addr; struct daemon *daemon; + enum is_websocket is_websocket; }; /*~ Once we've got a connection in, we set it up here (whether it's via the @@ -450,6 +457,7 @@ static struct io_plan *conn_in(struct io_conn *conn, * leaked */ return responder_handshake(notleak(conn), &daemon->mykey, &conn_in_arg->addr, timeout, + conn_in_arg->is_websocket, handshake_in_success, daemon); } @@ -460,10 +468,12 @@ static struct io_plan *connection_in(struct io_conn *conn, { struct conn_in conn_in_arg; + conn_in_arg.addr.u.wireaddr.is_websocket = false; if (!get_remote_address(conn, &conn_in_arg.addr)) return io_close(conn); conn_in_arg.daemon = daemon; + conn_in_arg.is_websocket = false; return conn_in(conn, &conn_in_arg); } @@ -478,6 +488,7 @@ static struct io_plan *websocket_connection_in(struct io_conn *conn, int err; struct conn_in conn_in_arg; + conn_in_arg.addr.u.wireaddr.is_websocket = true; if (!get_remote_address(conn, &conn_in_arg.addr)) return io_close(conn); @@ -544,6 +555,7 @@ static struct io_plan *websocket_connection_in(struct io_conn *conn, /* New connection actually talks to proxy process. */ conn_in_arg.daemon = daemon; + conn_in_arg.is_websocket = true; io_new_conn(tal_parent(conn), childmsg[0], conn_in, &conn_in_arg); /* Abandon original (doesn't close since child has dup'd fd) */ @@ -567,6 +579,7 @@ static struct io_plan *handshake_out_success(struct io_conn *conn, const struct wireaddr_internal *addr, struct crypto_state *cs, struct oneshot *timeout, + enum is_websocket is_websocket, struct connecting *connect) { struct node_id id; @@ -576,7 +589,7 @@ static struct io_plan *handshake_out_success(struct io_conn *conn, status_peer_debug(&id, "Connect OUT"); return peer_exchange_initmsg(conn, connect->daemon, connect->daemon->our_features, - cs, &id, addr, timeout, false); + cs, &id, addr, timeout, is_websocket, false); } struct io_plan *connection_out(struct io_conn *conn, struct connecting *connect) @@ -601,7 +614,7 @@ struct io_plan *connection_out(struct io_conn *conn, struct connecting *connect) connect->connstate = "Cryptographic handshake"; return initiator_handshake(conn, &connect->daemon->mykey, &outkey, &connect->addrs[connect->addrnum], - timeout, handshake_out_success, connect); + timeout, NORMAL_SOCKET, handshake_out_success, connect); } /*~ When we've exhausted all addresses without success, we come here. @@ -713,10 +726,10 @@ static struct io_plan *conn_init(struct io_conn *conn, break; case ADDR_INTERNAL_WIREADDR: /* DNS should have been resolved before */ - assert(addr->u.wireaddr.type != ADDR_TYPE_DNS); + assert(addr->u.wireaddr.wireaddr.type != ADDR_TYPE_DNS); /* If it was a Tor address, we wouldn't be here. */ - assert(!is_toraddr((char*)addr->u.wireaddr.addr)); - ai = wireaddr_to_addrinfo(tmpctx, &addr->u.wireaddr); + assert(!is_toraddr((char*)addr->u.wireaddr.wireaddr.addr)); + ai = wireaddr_to_addrinfo(tmpctx, &addr->u.wireaddr.wireaddr); break; } assert(ai); @@ -740,8 +753,8 @@ static struct io_plan *conn_proxy_init(struct io_conn *conn, port = addr->u.unresolved.port; break; case ADDR_INTERNAL_WIREADDR: - host = fmt_wireaddr_without_port(tmpctx, &addr->u.wireaddr); - port = addr->u.wireaddr.port; + host = fmt_wireaddr_without_port(tmpctx, &addr->u.wireaddr.wireaddr); + port = addr->u.wireaddr.wireaddr.port; break; case ADDR_INTERNAL_SOCKNAME: case ADDR_INTERNAL_ALLPROTO: @@ -807,7 +820,7 @@ static void try_connect_one_addr(struct connecting *connect) use_proxy = true; break; case ADDR_INTERNAL_WIREADDR: - switch (addr->u.wireaddr.type) { + switch (addr->u.wireaddr.wireaddr.type) { case ADDR_TYPE_TOR_V2_REMOVED: af = -1; break; @@ -837,9 +850,9 @@ static void try_connect_one_addr(struct connecting *connect) hints.ai_family = AF_UNSPEC; hints.ai_protocol = 0; hints.ai_flags = AI_ADDRCONFIG; - gai_err = getaddrinfo((char *)addr->u.wireaddr.addr, + gai_err = getaddrinfo((char *)addr->u.wireaddr.wireaddr.addr, tal_fmt(tmpctx, "%d", - addr->u.wireaddr.port), + addr->u.wireaddr.wireaddr.port), &hints, &ais); if (gai_err != 0) { tal_append_fmt(&connect->errors, @@ -853,16 +866,17 @@ static void try_connect_one_addr(struct connecting *connect) /* create new addrhints on-the-fly per result ... */ for (aii = ais; aii; aii = aii->ai_next) { addrhint.itype = ADDR_INTERNAL_WIREADDR; + addrhint.u.wireaddr.is_websocket = false; if (aii->ai_family == AF_INET) { sa4 = (struct sockaddr_in *) aii->ai_addr; - wireaddr_from_ipv4(&addrhint.u.wireaddr, + wireaddr_from_ipv4(&addrhint.u.wireaddr.wireaddr, &sa4->sin_addr, - addr->u.wireaddr.port); + addr->u.wireaddr.wireaddr.port); } else if (aii->ai_family == AF_INET6) { sa6 = (struct sockaddr_in6 *) aii->ai_addr; - wireaddr_from_ipv6(&addrhint.u.wireaddr, + wireaddr_from_ipv6(&addrhint.u.wireaddr.wireaddr, &sa6->sin6_addr, - addr->u.wireaddr.port); + addr->u.wireaddr.wireaddr.port); } else { /* skip unsupported ai_family */ continue; @@ -873,9 +887,6 @@ static void try_connect_one_addr(struct connecting *connect) } freeaddrinfo(ais); goto next; - case ADDR_TYPE_WEBSOCKET: - af = -1; - break; } } @@ -930,15 +941,6 @@ static void try_connect_one_addr(struct connecting *connect) try_connect_one_addr(connect); } -/*~ Sometimes it's nice to have an explicit enum instead of a bool to make - * arguments clearer: it kind of hacks around C's lack of naming formal - * arguments in callers (e.g. in Python we'd simply call func(websocket=False)). - */ -enum is_websocket { - NORMAL_SOCKET, - WEBSOCKET, -}; - /*~ connectd is responsible for incoming connections, but it's the process of * setting up the listening ports which gives us information we need for startup * (such as our own address). So we perform setup in two phases: first we bind @@ -1039,15 +1041,15 @@ static struct listen_fd *make_listen_fd(const tal_t *ctx, static struct listen_fd *handle_wireaddr_listen(const tal_t *ctx, const struct wireaddr_internal *wi, bool listen_mayfail, - enum is_websocket is_websocket, char **errstr) { struct sockaddr_in addr; struct sockaddr_in6 addr6; const struct wireaddr *wireaddr; + bool is_websocket = wi->u.wireaddr.is_websocket; assert(wi->itype == ADDR_INTERNAL_WIREADDR); - wireaddr = &wi->u.wireaddr; + wireaddr = &wi->u.wireaddr.wireaddr; /* Note the use of a switch() over enum here, even though it must be * IPv4 or IPv6 here; that will catch future changes. */ @@ -1062,7 +1064,6 @@ static struct listen_fd *handle_wireaddr_listen(const tal_t *ctx, return make_listen_fd(ctx, wi, AF_INET6, &addr6, sizeof(addr6), listen_mayfail, is_websocket, errstr); /* Handle specially by callers. */ - case ADDR_TYPE_WEBSOCKET: case ADDR_TYPE_TOR_V2_REMOVED: case ADDR_TYPE_TOR_V3: case ADDR_TYPE_DNS: @@ -1100,10 +1101,12 @@ find_local_address(const struct listen_fd **listen_fds) for (size_t i = 0; i < tal_count(listen_fds); i++) { if (listen_fds[i]->wi.itype != ADDR_INTERNAL_WIREADDR) continue; - if (listen_fds[i]->wi.u.wireaddr.type != ADDR_TYPE_IPV4 - && listen_fds[i]->wi.u.wireaddr.type != ADDR_TYPE_IPV6) + if (listen_fds[i]->wi.u.wireaddr.is_websocket) continue; - return &listen_fds[i]->wi.u.wireaddr; + if (listen_fds[i]->wi.u.wireaddr.wireaddr.type != ADDR_TYPE_IPV4 + && listen_fds[i]->wi.u.wireaddr.wireaddr.type != ADDR_TYPE_IPV6) + continue; + return &listen_fds[i]->wi.u.wireaddr.wireaddr; } return NULL; } @@ -1166,7 +1169,7 @@ setup_listeners(const tal_t *ctx, /* You can only announce wiretypes, not internal formats! */ assert(proposed_wireaddr[i].itype == ADDR_INTERNAL_WIREADDR); - add_announceable(announceable, &wa.u.wireaddr); + add_announceable(announceable, &wa.u.wireaddr.wireaddr); } /* Now look for listening addresses. */ @@ -1206,42 +1209,41 @@ setup_listeners(const tal_t *ctx, bool ipv6_ok; wa.itype = ADDR_INTERNAL_WIREADDR; - wa.u.wireaddr.port = wa.u.port; + wa.u.wireaddr.wireaddr.port = wa.u.allproto.port; + wa.u.wireaddr.is_websocket = wa.u.allproto.is_websocket; /* First, create wildcard IPv6 address. */ - wa.u.wireaddr.type = ADDR_TYPE_IPV6; - wa.u.wireaddr.addrlen = 16; - memset(wa.u.wireaddr.addr, 0, - sizeof(wa.u.wireaddr.addr)); + wa.u.wireaddr.wireaddr.type = ADDR_TYPE_IPV6; + wa.u.wireaddr.wireaddr.addrlen = 16; + memset(wa.u.wireaddr.wireaddr.addr, 0, + sizeof(wa.u.wireaddr.wireaddr.addr)); /* This may fail due to no IPv6 support. */ - lfd = handle_wireaddr_listen(ctx, &wa, false, - NORMAL_SOCKET, errstr); + lfd = handle_wireaddr_listen(ctx, &wa, false, errstr); if (lfd) { tal_arr_expand(&listen_fds, tal_steal(listen_fds, lfd)); if (announce - && public_address(daemon, &wa.u.wireaddr)) + && public_address(daemon, &wa.u.wireaddr.wireaddr)) add_announceable(announceable, - &wa.u.wireaddr); + &wa.u.wireaddr.wireaddr); } ipv6_ok = (lfd != NULL); /* Now, create wildcard IPv4 address. */ - wa.u.wireaddr.type = ADDR_TYPE_IPV4; - wa.u.wireaddr.addrlen = 4; - memset(wa.u.wireaddr.addr, 0, - sizeof(wa.u.wireaddr.addr)); + wa.u.wireaddr.wireaddr.type = ADDR_TYPE_IPV4; + wa.u.wireaddr.wireaddr.addrlen = 4; + memset(wa.u.wireaddr.wireaddr.addr, 0, + sizeof(wa.u.wireaddr.wireaddr.addr)); /* This listen *may* fail, as long as IPv6 succeeds! */ - lfd = handle_wireaddr_listen(ctx, &wa, ipv6_ok, - NORMAL_SOCKET, errstr); + lfd = handle_wireaddr_listen(ctx, &wa, ipv6_ok, errstr); if (lfd) { tal_arr_expand(&listen_fds, tal_steal(listen_fds, lfd)); if (announce - && public_address(daemon, &wa.u.wireaddr)) + && public_address(daemon, &wa.u.wireaddr.wireaddr)) add_announceable(announceable, - &wa.u.wireaddr); + &wa.u.wireaddr.wireaddr); } else if (!ipv6_ok) { /* Both failed, return now, errstr set. */ return NULL; @@ -1250,13 +1252,12 @@ setup_listeners(const tal_t *ctx, } /* This is a vanilla wireaddr as per BOLT #7 */ case ADDR_INTERNAL_WIREADDR: - lfd = handle_wireaddr_listen(ctx, &wa, false, - NORMAL_SOCKET, errstr); + lfd = handle_wireaddr_listen(ctx, &wa, false, errstr); if (!lfd) return NULL; tal_arr_expand(&listen_fds, tal_steal(listen_fds, lfd)); - if (announce && public_address(daemon, &wa.u.wireaddr)) - add_announceable(announceable, &wa.u.wireaddr); + if (announce && public_address(daemon, &wa.u.wireaddr.wireaddr)) + add_announceable(announceable, &wa.u.wireaddr.wireaddr); continue; case ADDR_INTERNAL_FORPROXY: break; @@ -1283,8 +1284,6 @@ setup_listeners(const tal_t *ctx, /* Only consider bindings added before this! */ size_t num_nonws_listens = tal_count(listen_fds); - /* If not overriden below, this is the default. */ - *errstr = "Cannot listen on websocket: not listening on any IPv4/6 addresses"; for (size_t i = 0; i < num_nonws_listens; i++) { /* Ignore UNIX sockets */ if (listen_fds[i]->wi.itype != ADDR_INTERNAL_WIREADDR) @@ -1292,51 +1291,26 @@ setup_listeners(const tal_t *ctx, /* Override with websocket port */ addr = listen_fds[i]->wi; - addr.u.wireaddr.port = daemon->websocket_port; + addr.u.wireaddr.is_websocket = true; + addr.u.wireaddr.wireaddr.port = daemon->websocket_port; /* We set mayfail on all but the first websocket; * it's quite common to have multple overlapping * addresses. */ - lfd = handle_wireaddr_listen(ctx, &addr, - announced_some, - WEBSOCKET, errstr); + lfd = handle_wireaddr_listen(ctx, &addr, announced_some, + errstr); if (!lfd) continue; - if (!announced_some) { - /* BOLT-websocket #7: - * - MUST NOT add a `type 6` address unless - * there is also at least one address of - * different type. - */ - if (tal_count(*announceable) != 0) { - /* See https://github.com/lightningnetwork/lnd/issues/6432: - * if we add websocket to the node_announcement, it doesn't propagate. - * So we do not do this for now in general! */ - if (daemon->announce_websocket) { - wireaddr_from_websocket(&addr.u.wireaddr, - daemon->websocket_port); - add_announceable(announceable, - &addr.u.wireaddr); - } - } else { - status_unusual("Bound to websocket %s," - " but we cannot announce" - " the websocket as we don't" - " announce anything else!", - type_to_string(tmpctx, - struct wireaddr_internal, - &addr)); - } - announced_some = true; - } - + announced_some = true; tal_arr_expand(&listen_fds, tal_steal(listen_fds, lfd)); } /* If none of those was possible, it's a configuration error? */ - if (tal_count(listen_fds) == num_nonws_listens) + if (tal_count(listen_fds) == num_nonws_listens) { + *errstr = "Cannot listen on websocket: not listening on any IPv4/6 addresses"; return NULL; + } } /* FIXME: Websocket over Tor (difficult for autotor, since we need @@ -1523,8 +1497,12 @@ static void connect_init(struct daemon *daemon, const u8 *msg) tal_free(announceable); #if DEVELOPER - if (dev_disconnect) + if (dev_disconnect) { + daemon->dev_disconnect_fd = 5; dev_disconnect_init(5); + } else { + daemon->dev_disconnect_fd = -1; + } #endif } @@ -1557,8 +1535,10 @@ static void connect_activate(struct daemon *daemon, const u8 *msg) if (do_listen) { for (size_t i = 0; i < tal_count(daemon->listen_fds); i++) { if (listen(daemon->listen_fds[i]->fd, 64) != 0) { - if (daemon->listen_fds[i]->mayfail) + if (daemon->listen_fds[i]->mayfail) { + close(daemon->listen_fds[i]->fd); continue; + } errmsg = tal_fmt(tmpctx, "Failed to listen on socket %s: %s", type_to_string(tmpctx, @@ -1567,11 +1547,13 @@ static void connect_activate(struct daemon *daemon, const u8 *msg) strerror(errno)); break; } - notleak(io_new_listener(daemon, - daemon->listen_fds[i]->fd, - get_in_cb(daemon->listen_fds[i] - ->is_websocket), - daemon)); + /* Add to listeners array */ + tal_arr_expand(&daemon->listeners, + io_new_listener(daemon, + daemon->listen_fds[i]->fd, + get_in_cb(daemon->listen_fds[i] + ->is_websocket), + daemon)); } } @@ -1631,10 +1613,11 @@ static void add_seed_addrs(struct wireaddr_internal **addrs, continue; struct wireaddr_internal a; a.itype = ADDR_INTERNAL_WIREADDR; - a.u.wireaddr = new_addrs[j]; + a.u.wireaddr.is_websocket = false; + a.u.wireaddr.wireaddr = new_addrs[j]; status_peer_debug(id, "Resolved %s to %s", hostnames[i], type_to_string(tmpctx, struct wireaddr, - &a.u.wireaddr)); + &a.u.wireaddr.wireaddr)); tal_arr_expand(addrs, a); } /* Other seeds will likely have the same information. */ @@ -1644,33 +1627,27 @@ static void add_seed_addrs(struct wireaddr_internal **addrs, } } -static bool wireaddr_int_equals_wireaddr(const struct wireaddr_internal *addr_a, - const struct wireaddr *addr_b) -{ - if (!addr_a || !addr_b) - return false; - return wireaddr_eq(&addr_a->u.wireaddr, addr_b); -} - /*~ Adds just one address type. * * Ignores deprecated and the `addrhint`. */ -static void add_gossip_addrs_bytype(struct wireaddr_internal **addrs, - const struct wireaddr *normal_addrs, - const struct wireaddr_internal *addrhint, - const enum wire_addr_type type) +static void add_gossip_addrs_bytypes(struct wireaddr_internal **addrs, + const struct wireaddr *normal_addrs, + const struct wireaddr *addrhint, + u64 types) { for (size_t i = 0; i < tal_count(normal_addrs); i++) { - if (normal_addrs[i].type == ADDR_TYPE_TOR_V2_REMOVED) + if (addrhint && wireaddr_eq(addrhint, &normal_addrs[i])) continue; - if (wireaddr_int_equals_wireaddr(addrhint, &normal_addrs[i])) + /* I guess this is possible in future! */ + if (normal_addrs[i].type > 63) continue; - if (normal_addrs[i].type != type) - continue; - struct wireaddr_internal addr; - addr.itype = ADDR_INTERNAL_WIREADDR; - addr.u.wireaddr = normal_addrs[i]; - tal_arr_expand(addrs, addr); + if (((u64)1 << normal_addrs[i].type) & types) { + struct wireaddr_internal addr; + addr.itype = ADDR_INTERNAL_WIREADDR; + addr.u.wireaddr.is_websocket = false; + addr.u.wireaddr.wireaddr = normal_addrs[i]; + tal_arr_expand(addrs, addr); + } } } @@ -1684,29 +1661,38 @@ static void add_gossip_addrs_bytype(struct wireaddr_internal **addrs, * direct (faster) IPv4 and finally (less stable) TOR connections. */ static void add_gossip_addrs(struct wireaddr_internal **addrs, const struct wireaddr *normal_addrs, - const struct wireaddr_internal *addrhint) + const struct wireaddr *addrhint) { - /* Wrap each one in a wireaddr_internal and add to addrs. */ - for (size_t i = 0; i < tal_count(normal_addrs); i++) { - /* This is not supported, ignore. */ - if (normal_addrs[i].type == ADDR_TYPE_TOR_V2_REMOVED) - continue; - /* The hint was already added earlier */ - if (wireaddr_int_equals_wireaddr(addrhint, &normal_addrs[i])) - continue; - /* We add IPv4 and TOR in separate loops to prefer IPv6 */ - if (normal_addrs[i].type == ADDR_TYPE_IPV4) - continue; - if (normal_addrs[i].type == ADDR_TYPE_TOR_V3) - continue; - struct wireaddr_internal addr; - addr.itype = ADDR_INTERNAL_WIREADDR; - addr.u.wireaddr = normal_addrs[i]; - tal_arr_expand(addrs, addr); + u64 types[] = { 0, 0, 0 }; + + /* Note gratuitous use of switch() means we'll know if a new one + * appears! */ + for (size_t i = ADDR_TYPE_IPV4; i <= ADDR_TYPE_DNS; i++) { + switch ((enum wire_addr_type)i) { + /* First priority */ + case ADDR_TYPE_IPV6: + case ADDR_TYPE_DNS: + types[0] |= ((u64)1 << i); + break; + /* Second priority */ + case ADDR_TYPE_IPV4: + types[1] |= ((u64)1 << i); + break; + case ADDR_TYPE_TOR_V3: + /* Third priority */ + types[2] |= ((u64)1 << i); + break; + /* We can't use these to connect to! */ + case ADDR_TYPE_TOR_V2_REMOVED: + break; + } + /* Other results returned are possible, but we don't understand + * them anyway! */ } - /* Do the loop for skipped protocols in preferred order. */ - add_gossip_addrs_bytype(addrs, normal_addrs, addrhint, ADDR_TYPE_IPV4); - add_gossip_addrs_bytype(addrs, normal_addrs, addrhint, ADDR_TYPE_TOR_V3); + + /* Add in priority order */ + for (size_t i = 0; i < ARRAY_SIZE(types); i++) + add_gossip_addrs_bytypes(addrs, normal_addrs, addrhint, types[i]); } /*~ Consumes addrhint if not NULL. @@ -1748,7 +1734,12 @@ static void try_connect_peer(struct daemon *daemon, if (addrhint) tal_arr_expand(&addrs, *addrhint); - add_gossip_addrs(&addrs, gossip_addrs, addrhint); + /* Tell it to omit the existing hint (if that's a wireaddr itself) */ + add_gossip_addrs(&addrs, gossip_addrs, + addrhint + && addrhint->itype == ADDR_INTERNAL_WIREADDR + && !addrhint->u.wireaddr.is_websocket + ? &addrhint->u.wireaddr.wireaddr : NULL); if (tal_count(addrs) == 0) { /* Don't resolve via DNS seed if we're supposed to use proxy. */ @@ -1837,6 +1828,20 @@ static void peer_discard(struct daemon *daemon, const u8 *msg) tal_free(peer); } +static void start_shutdown(struct daemon *daemon, const u8 *msg) +{ + if (!fromwire_connectd_start_shutdown(msg)) + master_badmsg(WIRE_CONNECTD_START_SHUTDOWN, msg); + + daemon->shutting_down = true; + + /* No more incoming connections! */ + daemon->listeners = tal_free(daemon->listeners); + + daemon_conn_send(daemon->master, + take(towire_connectd_start_shutdown_reply(NULL))); +} + /* lightningd tells us to send a msg and disconnect. */ static void peer_final_msg(struct io_conn *conn, struct daemon *daemon, const u8 *msg) @@ -1880,6 +1885,141 @@ static void dev_suppress_gossip(struct daemon *daemon, const u8 *msg) { daemon->dev_suppress_gossip = true; } + +static const char *addr2name(const tal_t *ctx, + const struct sockaddr_storage *sa, + socklen_t addrlen) +{ + const struct sockaddr_in *in = (struct sockaddr_in *)sa; + const struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa; + const struct sockaddr_un *un = (struct sockaddr_un *)sa; + char addr[1000]; + + switch (sa->ss_family) { + case AF_UNIX: + if (addrlen == sizeof(un->sun_family)) + return tal_fmt(ctx, "unix socket "); + else + return tal_fmt(ctx, "unix socket %s", un->sun_path); + case AF_INET: + if (!inet_ntop(sa->ss_family, &in->sin_addr, addr, sizeof(addr))) + return tal_fmt(ctx, "IPv4 socket "); + else + return tal_fmt(ctx, "IPv4 socket %s:%u", + addr, ntohs(in->sin_port)); + case AF_INET6: + if (!inet_ntop(sa->ss_family, &in6->sin6_addr, addr, sizeof(addr))) + return tal_fmt(ctx, "IPv6 socket "); + else + return tal_fmt(ctx, "IPv6 socket %s:%u", + addr, ntohs(in6->sin6_port)); + default: + return tal_fmt(ctx, "unknown family %u (**BROKEN**)", + (unsigned)sa->ss_family); + } +} + +static void describe_fd(int fd) +{ + struct sockaddr_storage sa; + socklen_t addrlen = sizeof(sa); + + if (getsockname(fd, (void *)&sa, &addrlen) != 0) { + status_broken("dev_report_fds: %i cannot get sockname (%s)", + fd, strerror(errno)); + return; + } + status_info("dev_report_fds: %i name %s", fd, addr2name(tmpctx, &sa, addrlen)); + + if (getpeername(fd, (void *)&sa, &addrlen) != 0) + return; + status_info("dev_report_fds: %i peer %s", fd, addr2name(tmpctx, &sa, addrlen)); +} + +static const char *io_plan_status_str(enum io_plan_status status) +{ + switch (status) { + case IO_UNSET: return "IO_UNSET"; + case IO_POLLING_NOTSTARTED: return "IO_POLLING_NOTSTARTED"; + case IO_POLLING_STARTED: return "IO_POLLING_STARTED"; + case IO_WAITING: return "IO_WAITING"; + case IO_ALWAYS: return "IO_ALWAYS"; + } + return "INVALID-STATUS"; +} + +/* Stupid and slow, but machines are fast! */ +static const tal_t *find_tal_ptr(const tal_t *root, const tal_t *p) +{ + if (root == p) + return root; + + for (tal_t *t = tal_first(root); t; t = tal_next(t)) { + const tal_t *ret = find_tal_ptr(t, p); + if (ret) + return ret; + } + return NULL; +} + +/* Looks up ptr in hash tree, to try to find name */ +static const char *try_tal_name(const tal_t *ctx, const void *p) +{ + const tal_t *t = find_tal_ptr(NULL, p); + if (t) + return tal_name(t); + return tal_fmt(ctx, "%p", p); +} + +static void dev_report_fds(struct daemon *daemon, const u8 *msg) +{ + for (int fd = 3; fd < 4096; fd++) { + bool listener; + const struct io_conn *c; + const struct io_listener *l; + if (!isatty(fd) && errno == EBADF) + continue; + if (fd == HSM_FD) { + status_info("dev_report_fds: %i -> hsm fd", fd); + continue; + } + if (fd == GOSSIPCTL_FD) { + status_info("dev_report_fds: %i -> gossipd fd", fd); + continue; + } +#if DEVELOPER + if (fd == daemon->dev_disconnect_fd) { + status_info("dev_report_fds: %i -> dev_disconnect_fd", fd); + continue; + } +#endif + if (fd == daemon->gossip_store_fd) { + status_info("dev_report_fds: %i -> gossip_store", fd); + continue; + } + c = io_have_fd(fd, &listener); + if (!c) { + status_broken("dev_report_fds: %i open but unowned?", fd); + continue; + } else if (listener) { + l = (void *)c; + status_info("dev_report_fds: %i -> listener (%s)", fd, + backtrace_symname(tmpctx, l->init)); + } else { + status_info("dev_report_fds: %i -> IN=%s:%s+%s(%s), OUT=%s:%s+%s(%s)", + fd, + io_plan_status_str(c->plan[IO_IN].status), + backtrace_symname(tmpctx, c->plan[IO_IN].io), + backtrace_symname(tmpctx, c->plan[IO_IN].next), + try_tal_name(tmpctx, c->plan[IO_IN].next_arg), + io_plan_status_str(c->plan[IO_OUT].status), + backtrace_symname(tmpctx, c->plan[IO_OUT].io), + backtrace_symname(tmpctx, c->plan[IO_OUT].next), + try_tal_name(tmpctx, c->plan[IO_OUT].next_arg)); + } + describe_fd(fd); + } +} #endif /* DEVELOPER */ static struct io_plan *recv_peer_connect_subd(struct io_conn *conn, @@ -1937,6 +2077,10 @@ static struct io_plan *recv_req(struct io_conn *conn, return daemon_conn_read_with_fd(conn, daemon->master, recv_peer_connect_subd, daemon); + case WIRE_CONNECTD_START_SHUTDOWN: + start_shutdown(daemon, msg); + goto out; + case WIRE_CONNECTD_DEV_MEMLEAK: #if DEVELOPER dev_connect_memleak(daemon, msg); @@ -1946,6 +2090,11 @@ static struct io_plan *recv_req(struct io_conn *conn, #if DEVELOPER dev_suppress_gossip(daemon, msg); goto out; +#endif + case WIRE_CONNECTD_DEV_REPORT_FDS: +#if DEVELOPER + dev_report_fds(daemon, msg); + goto out; #endif /* We send these, we don't receive them */ case WIRE_CONNECTD_INIT_REPLY: @@ -1958,6 +2107,7 @@ static struct io_plan *recv_req(struct io_conn *conn, case WIRE_CONNECTD_GOT_ONIONMSG_TO_US: case WIRE_CONNECTD_CUSTOMMSG_IN: case WIRE_CONNECTD_PEER_DISCONNECT_DONE: + case WIRE_CONNECTD_START_SHUTDOWN_REPLY: break; } @@ -2024,11 +2174,13 @@ int main(int argc, char *argv[]) daemon = tal(NULL, struct daemon); daemon->connection_counter = 1; daemon->peers = tal(daemon, struct peer_htable); + daemon->listeners = tal_arr(daemon, struct io_listener *, 0); peer_htable_init(daemon->peers); memleak_add_helper(daemon, memleak_daemon_cb); list_head_init(&daemon->connecting); timers_init(&daemon->timers, time_mono()); daemon->gossip_store_fd = -1; + daemon->shutting_down = false; /* stdin == control */ daemon->master = daemon_conn_new(daemon, STDIN_FILENO, recv_req, NULL, diff --git a/connectd/connectd.h b/connectd/connectd.h index 8a35a02b85bb..8605155fc72b 100644 --- a/connectd/connectd.h +++ b/connectd/connectd.h @@ -10,6 +10,7 @@ #include #include #include +#include struct io_conn; struct connecting; @@ -45,6 +46,9 @@ struct peer { /* Main daemon */ struct daemon *daemon; + /* Are we connected via a websocket? */ + enum is_websocket is_websocket; + /* The pubkey of the node */ struct node_id id; /* Counters and keys for symmetric crypto */ @@ -145,6 +149,9 @@ struct daemon { /* Connection to gossip daemon. */ struct daemon_conn *gossipd; + /* Any listening sockets we have. */ + struct io_listener **listeners; + /* Allow localhost to be considered "public": DEVELOPER-only option, * but for simplicity we don't #if DEVELOPER-wrap it here. */ bool dev_allow_localhost; @@ -184,6 +191,9 @@ struct daemon { /* We only announce websocket addresses if !deprecated_apis */ bool announce_websocket; + /* Shutting down, don't send new stuff */ + bool shutting_down; + #if DEVELOPER /* Hack to speed up gossip timer */ bool dev_fast_gossip; @@ -191,6 +201,8 @@ struct daemon { bool dev_no_ping_timer; /* Hack to no longer send gossip */ bool dev_suppress_gossip; + /* dev_disconnect file */ + int dev_disconnect_fd; #endif }; @@ -208,6 +220,7 @@ struct io_plan *peer_connected(struct io_conn *conn, const struct wireaddr *remote_addr, struct crypto_state *cs, const u8 *their_features TAKES, + enum is_websocket is_websocket, bool incoming); /* Removes peer from hash table, tells gossipd and lightningd. */ diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv index d8b77d0a4295..d42d5f506a6d 100644 --- a/connectd/connectd_wire.csv +++ b/connectd/connectd_wire.csv @@ -105,6 +105,9 @@ msgtype,connectd_dev_memleak,2033 msgtype,connectd_dev_memleak_reply,2133 msgdata,connectd_dev_memleak_reply,leak,bool, +# master -> connectd: dump status of your fds. +msgtype,connectd_dev_report_fds,2034 + # Ping/pong test. Waits for a reply if it expects one. msgtype,connectd_ping,2030 msgdata,connectd_ping,id,node_id, @@ -144,6 +147,12 @@ msgdata,connectd_custommsg_out,id,node_id, msgdata,connectd_custommsg_out,msg_len,u16, msgdata,connectd_custommsg_out,msg,u8,msg_len +# master -> connectd: we're shutting down, no new connections. +msgtype,connectd_start_shutdown,2031 + +# connect - >master: acknowledged. +msgtype,connectd_start_shutdown_reply,2131 + # master -> connect: stop sending gossip. msgtype,connectd_dev_suppress_gossip,2032 diff --git a/connectd/gossip_rcvd_filter.c b/connectd/gossip_rcvd_filter.c index a0e9b6b53522..93a58fe3cd1f 100644 --- a/connectd/gossip_rcvd_filter.c +++ b/connectd/gossip_rcvd_filter.c @@ -84,13 +84,14 @@ static bool is_msg_gossip_broadcast(const u8 *cursor) case WIRE_TX_REMOVE_OUTPUT: case WIRE_TX_COMPLETE: case WIRE_TX_SIGNATURES: + case WIRE_TX_INIT_RBF: + case WIRE_TX_ACK_RBF: + case WIRE_TX_ABORT: + case WIRE_PEER_STORAGE: + case WIRE_YOUR_PEER_STORAGE: case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: - case WIRE_INIT_RBF: - case WIRE_ACK_RBF: -#if EXPERIMENTAL_FEATURES case WIRE_STFU: -#endif break; } return false; diff --git a/connectd/gossip_store.c b/connectd/gossip_store.c index 02af672eded1..e387f55d97da 100644 --- a/connectd/gossip_store.c +++ b/connectd/gossip_store.c @@ -71,8 +71,9 @@ static bool public_msg_type(enum peer_wire type) case WIRE_CHANNEL_READY: case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: - case WIRE_INIT_RBF: - case WIRE_ACK_RBF: + case WIRE_TX_INIT_RBF: + case WIRE_TX_ACK_RBF: + case WIRE_TX_ABORT: case WIRE_SHUTDOWN: case WIRE_CLOSING_SIGNED: case WIRE_UPDATE_ADD_HTLC: @@ -91,9 +92,9 @@ static bool public_msg_type(enum peer_wire type) case WIRE_REPLY_CHANNEL_RANGE: case WIRE_GOSSIP_TIMESTAMP_FILTER: case WIRE_ONION_MESSAGE: -#if EXPERIMENTAL_FEATURES + case WIRE_PEER_STORAGE: + case WIRE_YOUR_PEER_STORAGE: case WIRE_STFU: -#endif return false; case WIRE_CHANNEL_ANNOUNCEMENT: case WIRE_NODE_ANNOUNCEMENT: @@ -108,7 +109,6 @@ static bool public_msg_type(enum peer_wire type) u8 *gossip_store_next(const tal_t *ctx, int *gossip_store_fd, u32 timestamp_min, u32 timestamp_max, - bool push_only, bool with_spam, size_t *off, size_t *end) { @@ -119,7 +119,7 @@ u8 *gossip_store_next(const tal_t *ctx, struct gossip_hdr hdr; u16 msglen, flags; u32 checksum, timestamp; - bool push, ratelimited; + bool ratelimited; int type, r; r = pread(*gossip_store_fd, &hdr, sizeof(hdr), *off); @@ -128,7 +128,6 @@ u8 *gossip_store_next(const tal_t *ctx, msglen = be16_to_cpu(hdr.len); flags = be16_to_cpu(hdr.flags); - push = (flags & GOSSIP_STORE_PUSH_BIT); ratelimited = (flags & GOSSIP_STORE_RATELIMIT_BIT); /* Skip any deleted entries. */ @@ -139,8 +138,7 @@ u8 *gossip_store_next(const tal_t *ctx, /* Skip any timestamp filtered */ timestamp = be32_to_cpu(hdr.timestamp); - if (!push && - !timestamp_filter(timestamp_min, timestamp_max, + if (!timestamp_filter(timestamp_min, timestamp_max, timestamp)) { *off += r + msglen; continue; @@ -171,8 +169,6 @@ u8 *gossip_store_next(const tal_t *ctx, /* Ignore gossipd internal messages. */ } else if (!public_msg_type(type)) { msg = tal_free(msg); - } else if (!push && push_only) { - msg = tal_free(msg); } else if (!with_spam && ratelimited) { msg = tal_free(msg); } diff --git a/connectd/gossip_store.h b/connectd/gossip_store.h index 21a0eb7549d2..12cd1d6c19eb 100644 --- a/connectd/gossip_store.h +++ b/connectd/gossip_store.h @@ -13,7 +13,6 @@ u8 *gossip_store_next(const tal_t *ctx, int *gossip_store_fd, u32 timestamp_min, u32 timestamp_max, - bool push_only, bool with_spam, size_t *off, size_t *end); diff --git a/connectd/handshake.c b/connectd/handshake.c index 1097f6f3d033..79f6f763da02 100644 --- a/connectd/handshake.c +++ b/connectd/handshake.c @@ -176,12 +176,16 @@ struct handshake { /* Timeout timer if we take too long. */ struct oneshot *timeout; + /* Are we connected via a websocket? */ + enum is_websocket is_websocket; + /* Function to call once handshake complete. */ struct io_plan *(*cb)(struct io_conn *conn, const struct pubkey *their_id, const struct wireaddr_internal *wireaddr, struct crypto_state *cs, struct oneshot *timeout, + enum is_websocket is_websocket, void *cbarg); void *cbarg; }; @@ -353,11 +357,13 @@ static struct io_plan *handshake_succeeded(struct io_conn *conn, const struct wireaddr_internal *addr, struct crypto_state *cs, struct oneshot *timeout, + enum is_websocket is_websocket, void *cbarg); void *cbarg; struct pubkey their_id; struct wireaddr_internal addr; struct oneshot *timeout; + enum is_websocket is_websocket; /* BOLT #8: * @@ -384,9 +390,10 @@ static struct io_plan *handshake_succeeded(struct io_conn *conn, their_id = h->their_id; addr = h->addr; timeout = h->timeout; + is_websocket = h->is_websocket; tal_free(h); - return cb(conn, &their_id, &addr, &cs, timeout, cbarg); + return cb(conn, &their_id, &addr, &cs, timeout, is_websocket, cbarg); } static struct handshake *new_handshake(const tal_t *ctx, @@ -964,11 +971,13 @@ struct io_plan *responder_handshake_(struct io_conn *conn, const struct pubkey *my_id, const struct wireaddr_internal *addr, struct oneshot *timeout, + enum is_websocket is_websocket, struct io_plan *(*cb)(struct io_conn *, const struct pubkey *, const struct wireaddr_internal *, struct crypto_state *, struct oneshot *, + enum is_websocket, void *cbarg), void *cbarg) { @@ -980,6 +989,7 @@ struct io_plan *responder_handshake_(struct io_conn *conn, h->cbarg = cbarg; h->cb = cb; h->timeout = timeout; + h->is_websocket = is_websocket; return act_one_responder(conn, h); } @@ -989,11 +999,13 @@ struct io_plan *initiator_handshake_(struct io_conn *conn, const struct pubkey *their_id, const struct wireaddr_internal *addr, struct oneshot *timeout, + enum is_websocket is_websocket, struct io_plan *(*cb)(struct io_conn *, const struct pubkey *, const struct wireaddr_internal *, struct crypto_state *, struct oneshot *timeout, + enum is_websocket is_websocket, void *cbarg), void *cbarg) { @@ -1005,6 +1017,7 @@ struct io_plan *initiator_handshake_(struct io_conn *conn, h->addr = *addr; h->cbarg = cbarg; h->cb = cb; + h->is_websocket = is_websocket; h->timeout = timeout; return act_one_initiator(conn, h); diff --git a/connectd/handshake.h b/connectd/handshake.h index facb7f203250..ec52fb3caf9c 100644 --- a/connectd/handshake.h +++ b/connectd/handshake.h @@ -8,15 +8,25 @@ struct wireaddr_internal; struct pubkey; struct oneshot; -#define initiator_handshake(conn, my_id, their_id, addr, timeout, cb, cbarg) \ - initiator_handshake_((conn), (my_id), (their_id), (addr), (timeout), \ +/*~ Sometimes it's nice to have an explicit enum instead of a bool to make + * arguments clearer: it kind of hacks around C's lack of naming formal + * arguments in callers (e.g. in Python we'd simply call func(websocket=False)). + */ +enum is_websocket { + NORMAL_SOCKET, + WEBSOCKET, +}; + +#define initiator_handshake(conn, my_id, their_id, addr, timeout, is_ws, cb, cbarg) \ + initiator_handshake_((conn), (my_id), (their_id), (addr), (timeout), (is_ws), \ typesafe_cb_preargs(struct io_plan *, void *, \ (cb), (cbarg), \ struct io_conn *, \ const struct pubkey *, \ const struct wireaddr_internal *, \ struct crypto_state *, \ - struct oneshot *), \ + struct oneshot *, \ + enum is_websocket), \ (cbarg)) @@ -25,35 +35,40 @@ struct io_plan *initiator_handshake_(struct io_conn *conn, const struct pubkey *their_id, const struct wireaddr_internal *addr, struct oneshot *timeout, + enum is_websocket is_websocket, struct io_plan *(*cb)(struct io_conn *, const struct pubkey *, const struct wireaddr_internal *, struct crypto_state *, struct oneshot *timeout, + enum is_websocket, void *cbarg), void *cbarg); -#define responder_handshake(conn, my_id, addr, timeout, cb, cbarg) \ - responder_handshake_((conn), (my_id), (addr), (timeout), \ +#define responder_handshake(conn, my_id, addr, timeout, is_ws, cb, cbarg) \ + responder_handshake_((conn), (my_id), (addr), (timeout), (is_ws), \ typesafe_cb_preargs(struct io_plan *, void *, \ (cb), (cbarg), \ struct io_conn *, \ const struct pubkey *, \ const struct wireaddr_internal *, \ struct crypto_state *, \ - struct oneshot *), \ + struct oneshot *, \ + enum is_websocket), \ (cbarg)) struct io_plan *responder_handshake_(struct io_conn *conn, const struct pubkey *my_id, const struct wireaddr_internal *addr, struct oneshot *timeout, + enum is_websocket is_websocket, struct io_plan *(*cb)(struct io_conn *, const struct pubkey *, const struct wireaddr_internal *, struct crypto_state *, struct oneshot *, + enum is_websocket, void *cbarg), void *cbarg); #endif /* LIGHTNING_CONNECTD_HANDSHAKE_H */ diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 90fc34a2439c..a79ddf53109d 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -315,11 +315,15 @@ static void set_urgent_flag(struct peer *peer, bool urgent) int val; int opt; const char *optname; - static bool complained = false; if (urgent == peer->urgent) return; + /* FIXME: We can't do this on websockets, but we could signal our + * websocket proxy via some magic message to do so! */ + if (peer->is_websocket != NORMAL_SOCKET) + return; + #ifdef TCP_CORK opt = TCP_CORK; optname = "TCP_CORK"; @@ -332,14 +336,12 @@ static void set_urgent_flag(struct peer *peer, bool urgent) val = urgent; if (setsockopt(io_conn_fd(peer->to_peer), - IPPROTO_TCP, opt, &val, sizeof(val)) != 0) { - /* This actually happens in testing, where we blackhole the fd */ - if (!complained) { - status_unusual("setsockopt %s=1: %s", - optname, - strerror(errno)); - complained = true; - } + IPPROTO_TCP, opt, &val, sizeof(val)) != 0 + /* This actually happens in testing, where we blackhole the fd */ + && IFDEV(peer->daemon->dev_disconnect_fd == -1, true)) { + status_broken("setsockopt %s=1 fd=%u: %s", + optname, io_conn_fd(peer->to_peer), + strerror(errno)); } peer->urgent = urgent; } @@ -355,6 +357,7 @@ static bool is_urgent(enum peer_wire type) case WIRE_TX_REMOVE_INPUT: case WIRE_TX_REMOVE_OUTPUT: case WIRE_TX_COMPLETE: + case WIRE_TX_ABORT: case WIRE_TX_SIGNATURES: case WIRE_OPEN_CHANNEL: case WIRE_ACCEPT_CHANNEL: @@ -363,8 +366,8 @@ static bool is_urgent(enum peer_wire type) case WIRE_CHANNEL_READY: case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: - case WIRE_INIT_RBF: - case WIRE_ACK_RBF: + case WIRE_TX_INIT_RBF: + case WIRE_TX_ACK_RBF: case WIRE_SHUTDOWN: case WIRE_CLOSING_SIGNED: case WIRE_UPDATE_ADD_HTLC: @@ -384,9 +387,9 @@ static bool is_urgent(enum peer_wire type) case WIRE_REPLY_CHANNEL_RANGE: case WIRE_GOSSIP_TIMESTAMP_FILTER: case WIRE_ONION_MESSAGE: -#if EXPERIMENTAL_FEATURES + case WIRE_PEER_STORAGE: + case WIRE_YOUR_PEER_STORAGE: case WIRE_STFU: -#endif return false; /* These are time-sensitive, and so send without delay. */ @@ -500,23 +503,6 @@ static u8 *maybe_from_gossip_store(const tal_t *ctx, struct peer *peer) if (IFDEV(peer->daemon->dev_suppress_gossip, false)) return NULL; - /* BOLT #7: - * - if the `gossip_queries` feature is negotiated: - * - MUST NOT relay any gossip messages it did not generate itself, - * unless explicitly requested. - */ - - /* So, even if they didn't send us a timestamp_filter message, - * we *still* send our own gossip. */ - if (!peer->gs.gossip_timer) { - return gossip_store_next(ctx, &peer->daemon->gossip_store_fd, - 0, 0xFFFFFFFF, - true, - false, - &peer->gs.off, - &peer->daemon->gossip_store_end); - } - /* Not streaming right now? */ if (!peer->gs.active) return NULL; @@ -529,7 +515,6 @@ static u8 *maybe_from_gossip_store(const tal_t *ctx, struct peer *peer) peer->gs.timestamp_min, peer->gs.timestamp_max, false, - false, &peer->gs.off, &peer->daemon->gossip_store_end); /* Don't send back gossip they sent to us! */ @@ -693,18 +678,27 @@ static void handle_gossip_timestamp_filter_in(struct peer *peer, const u8 *msg) if (peer->gs.timestamp_max < peer->gs.timestamp_min) peer->gs.timestamp_max = UINT32_MAX; - /* Optimization: they don't want anything. LND and us (at least), - * both set first_timestamp to 0xFFFFFFFF to indicate that. */ - if (peer->gs.timestamp_min == UINT32_MAX) + /* BOLT-gossip-filter-simplify #7: + * The receiver: + *... + * - if `first_timestamp` is 0: + * - SHOULD send all known gossip messages. + * - otherwise, if `first_timestamp` is 0xFFFFFFFF: + * - SHOULD NOT send any gossip messages (except its own). + * - otherwise: + * - SHOULD send gossip messages it receives from now own. + */ + /* For us, this means we only sweep the gossip store for messages + * if the first_timestamp is 0 */ + if (first_timestamp == 0) + peer->gs.off = 1; + else if (first_timestamp == 0xFFFFFFFF) peer->gs.off = peer->daemon->gossip_store_end; else { - /* Second optimation: it's common to ask for "recent" gossip, - * so we don't have to start at beginning of store. */ + /* We are actually a bit nicer than the spec, and we include + * "recent" gossip here. */ update_recent_timestamp(peer->daemon); - if (peer->gs.timestamp_min >= peer->daemon->gossip_recent_time) - peer->gs.off = peer->daemon->gossip_store_recent_off; - else - peer->gs.off = 1; + peer->gs.off = peer->daemon->gossip_store_recent_off; } /* BOLT #7: @@ -720,7 +714,7 @@ static bool handle_custommsg(struct daemon *daemon, const u8 *msg) { enum peer_wire type = fromwire_peektype(msg); - if (type % 2 == 1 && !peer_wire_is_defined(type)) { + if (type % 2 == 1 && !peer_wire_is_internal(type)) { /* The message is not part of the messages we know how to * handle. Assuming this is a custommsg, we just forward it to the * master. */ @@ -1132,6 +1126,14 @@ static struct io_plan *read_body_from_peer_done(struct io_conn *peer_conn, subd = find_subd(peer, &channel_id); if (!subd) { enum peer_wire t = fromwire_peektype(decrypted); + + /* Simplest to close on them at this point. */ + if (peer->daemon->shutting_down) { + status_peer_debug(&peer->id, + "Shutting down: hanging up for %s", + peer_wire_name(t)); + return io_close(peer_conn); + } status_peer_debug(&peer->id, "Activating for message %s", peer_wire_name(t)); subd = new_subd(peer, &channel_id); diff --git a/connectd/netaddress.c b/connectd/netaddress.c index 5f9fb57fd3fa..bcd389353b3e 100644 --- a/connectd/netaddress.c +++ b/connectd/netaddress.c @@ -259,7 +259,6 @@ bool guess_address(struct wireaddr *addr) case ADDR_TYPE_TOR_V2_REMOVED: case ADDR_TYPE_TOR_V3: case ADDR_TYPE_DNS: - case ADDR_TYPE_WEBSOCKET: status_broken("Cannot guess address type %u", addr->type); break; } diff --git a/connectd/peer_exchange_initmsg.c b/connectd/peer_exchange_initmsg.c index fa97998382c6..55f73107bcda 100644 --- a/connectd/peer_exchange_initmsg.c +++ b/connectd/peer_exchange_initmsg.c @@ -27,6 +27,9 @@ struct early_peer { /* Buffer for reading/writing message. */ u8 *msg; + /* Are we connected via a websocket? */ + enum is_websocket is_websocket; + bool incoming; }; @@ -115,7 +118,6 @@ static struct io_plan *peer_init_received(struct io_conn *conn, case ADDR_TYPE_TOR_V2_REMOVED: case ADDR_TYPE_TOR_V3: case ADDR_TYPE_DNS: - case ADDR_TYPE_WEBSOCKET: remote_addr = tal_free(remote_addr); break; } @@ -137,6 +139,7 @@ static struct io_plan *peer_init_received(struct io_conn *conn, remote_addr, &peer->cs, take(features), + peer->is_websocket, peer->incoming); } @@ -192,6 +195,7 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, const struct node_id *id, const struct wireaddr_internal *addr, struct oneshot *timeout, + enum is_websocket is_websocket, bool incoming) { /* If conn is closed, forget peer */ @@ -204,6 +208,7 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, peer->addr = *addr; peer->cs = *cs; peer->incoming = incoming; + peer->is_websocket = is_websocket; /* Attach timer to early peer, so it gets freed with it. */ notleak(tal_steal(peer, timeout)); @@ -231,19 +236,20 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, * incoming connection, if the node is the receiver and the connection was done * via IP. */ - if (incoming && addr->itype == ADDR_INTERNAL_WIREADDR && - address_routable(&addr->u.wireaddr, true)) { - switch (addr->u.wireaddr.type) { + if (incoming + && addr->itype == ADDR_INTERNAL_WIREADDR + && !addr->u.wireaddr.is_websocket + && address_routable(&addr->u.wireaddr.wireaddr, true)) { + switch (addr->u.wireaddr.wireaddr.type) { case ADDR_TYPE_IPV4: case ADDR_TYPE_IPV6: tlvs->remote_addr = tal_arr(tlvs, u8, 0); - towire_wireaddr(&tlvs->remote_addr, &addr->u.wireaddr); + towire_wireaddr(&tlvs->remote_addr, &addr->u.wireaddr.wireaddr); break; /* Only report IP addresses back for now */ case ADDR_TYPE_TOR_V2_REMOVED: case ADDR_TYPE_TOR_V3: case ADDR_TYPE_DNS: - case ADDR_TYPE_WEBSOCKET: break; } } diff --git a/connectd/peer_exchange_initmsg.h b/connectd/peer_exchange_initmsg.h index eb654aaa73c0..702e1350470c 100644 --- a/connectd/peer_exchange_initmsg.h +++ b/connectd/peer_exchange_initmsg.h @@ -18,6 +18,7 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, const struct node_id *id, const struct wireaddr_internal *addr, struct oneshot *timeout, + enum is_websocket is_websocket, bool incoming); #endif /* LIGHTNING_CONNECTD_PEER_EXCHANGE_INITMSG_H */ diff --git a/connectd/test/run-gossip_rcvd_filter.c b/connectd/test/run-gossip_rcvd_filter.c index 17810ac3c101..bf080c0e6a81 100644 --- a/connectd/test/run-gossip_rcvd_filter.c +++ b/connectd/test/run-gossip_rcvd_filter.c @@ -20,12 +20,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/connectd/test/run-initiator-success.c b/connectd/test/run-initiator-success.c index 73e35875f5ce..f6d46d0639cb 100644 --- a/connectd/test/run-initiator-success.c +++ b/connectd/test/run-initiator-success.c @@ -28,12 +28,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, @@ -279,6 +285,7 @@ static struct io_plan *success(struct io_conn *conn UNUSED, const struct wireaddr_internal *addr UNUSED, struct crypto_state *cs, struct oneshot *timeout UNUSED, + enum is_websocket is_websocket UNUSED, void *unused UNUSED) { assert(pubkey_eq(them, &rs_pub)); @@ -320,8 +327,8 @@ int main(int argc, char *argv[]) e_pub = pubkey("036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7"); dummy.itype = ADDR_INTERNAL_WIREADDR; - dummy.u.wireaddr.addrlen = 0; - initiator_handshake((void *)tmpctx, &ls_pub, &rs_pub, &dummy, NULL, success, NULL); + dummy.u.wireaddr.wireaddr.addrlen = 0; + initiator_handshake((void *)tmpctx, &ls_pub, &rs_pub, &dummy, NULL, NORMAL_SOCKET, success, NULL); /* Should not exit! */ abort(); } diff --git a/connectd/test/run-netaddress.c b/connectd/test/run-netaddress.c index f92ea8aa7582..74f06c3d0c96 100644 --- a/connectd/test/run-netaddress.c +++ b/connectd/test/run-netaddress.c @@ -27,12 +27,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, @@ -162,16 +168,19 @@ int main(int argc, char *argv[]) common_setup(argv[0]); // start with IPv4 - parse_wireaddr("0.0.0.0", &wa, DEFAULT_PORT, NULL, &err); + err = parse_wireaddr(tmpctx, "0.0.0.0", DEFAULT_PORT, NULL, &wa); + assert(!err); assert(!IsValid(&wa)); assert(IsIPv4(&wa)); assert(!IsIPv6(&wa)); - parse_wireaddr("255.255.255.255", &wa, DEFAULT_PORT, NULL, &err); + err = parse_wireaddr(tmpctx, "255.255.255.255", DEFAULT_PORT, NULL, &wa); + assert(!err); assert(!IsValid(&wa)); assert(IsIPv4(&wa)); assert(!IsIPv6(&wa)); - parse_wireaddr("127.0.0.1", &wa, DEFAULT_PORT, NULL, &err); + err = parse_wireaddr(tmpctx, "127.0.0.1", DEFAULT_PORT, NULL, &wa); + assert(!err); assert(IsValid(&wa)); assert(IsIPv4(&wa)); assert(!IsIPv6(&wa)); @@ -179,7 +188,8 @@ int main(int argc, char *argv[]) assert(address_routable(&wa, true)); assert(!address_routable(&wa, false)); - parse_wireaddr("0.1.2.3", &wa, DEFAULT_PORT, NULL, &err); + err = parse_wireaddr(tmpctx, "0.1.2.3", DEFAULT_PORT, NULL, &wa); + assert(!err); assert(IsValid(&wa)); assert(IsIPv4(&wa)); assert(!IsIPv6(&wa)); @@ -187,7 +197,8 @@ int main(int argc, char *argv[]) assert(address_routable(&wa, true)); assert(!address_routable(&wa, false)); - parse_wireaddr("10.0.21.42", &wa, DEFAULT_PORT, NULL, &err); + err = parse_wireaddr(tmpctx, "10.0.21.42", DEFAULT_PORT, NULL, &wa); + assert(!err); assert(IsValid(&wa)); assert(IsIPv4(&wa)); assert(!IsIPv6(&wa)); @@ -196,7 +207,8 @@ int main(int argc, char *argv[]) assert(!address_routable(&wa, true)); assert(!address_routable(&wa, false)); - parse_wireaddr("192.168.123.4", &wa, DEFAULT_PORT, NULL, &err); + err = parse_wireaddr(tmpctx, "192.168.123.4", DEFAULT_PORT, NULL, &wa); + assert(!err); assert(IsValid(&wa)); assert(IsIPv4(&wa)); assert(!IsIPv6(&wa)); @@ -205,7 +217,8 @@ int main(int argc, char *argv[]) assert(!address_routable(&wa, true)); assert(!address_routable(&wa, false)); - parse_wireaddr("1.2.3.4", &wa, DEFAULT_PORT, NULL, &err); + err = parse_wireaddr(tmpctx, "1.2.3.4", DEFAULT_PORT, NULL, &wa); + assert(!err); assert(IsValid(&wa)); assert(IsIPv4(&wa)); assert(!IsIPv6(&wa)); @@ -214,7 +227,8 @@ int main(int argc, char *argv[]) assert(address_routable(&wa, false)); // now IPv6 stuff - parse_wireaddr("2142:DEAD:beef::1", &wa, DEFAULT_PORT, NULL, &err); + err = parse_wireaddr(tmpctx, "2142:DEAD:beef::1", DEFAULT_PORT, NULL, &wa); + assert(!err); assert(IsValid(&wa)); assert(!IsIPv4(&wa)); assert(IsIPv6(&wa)); @@ -222,12 +236,14 @@ int main(int argc, char *argv[]) assert(address_routable(&wa, true)); assert(address_routable(&wa, false)); - parse_wireaddr("0::0", &wa, DEFAULT_PORT, NULL, &err); + err = parse_wireaddr(tmpctx, "0::0", DEFAULT_PORT, NULL, &wa); + assert(!err); assert(!IsValid(&wa)); assert(!IsIPv4(&wa)); assert(IsIPv6(&wa)); - parse_wireaddr("2001:db8::1", &wa, DEFAULT_PORT, NULL, &err); + err = parse_wireaddr(tmpctx, "2001:db8::1", DEFAULT_PORT, NULL, &wa); + assert(!err); assert(!IsValid(&wa)); assert(!IsIPv4(&wa)); assert(IsIPv6(&wa)); diff --git a/connectd/test/run-responder-success.c b/connectd/test/run-responder-success.c index b5de1da5a9e7..0b0d8c002e8f 100644 --- a/connectd/test/run-responder-success.c +++ b/connectd/test/run-responder-success.c @@ -28,12 +28,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, @@ -278,6 +284,7 @@ static struct io_plan *success(struct io_conn *conn UNUSED, const struct wireaddr_internal *addr UNUSED, struct crypto_state *cs, struct oneshot *timeout UNUSED, + enum is_websocket is_websocket UNUSED, void *unused UNUSED) { assert(secret_eq_str(&cs->sk, expect_sk)); @@ -314,8 +321,8 @@ int main(int argc, char *argv[]) e_pub = pubkey("02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27"); dummy.itype = ADDR_INTERNAL_WIREADDR; - dummy.u.wireaddr.addrlen = 0; - responder_handshake((void *)tmpctx, &ls_pub, &dummy, NULL, success, NULL); + dummy.u.wireaddr.wireaddr.addrlen = 0; + responder_handshake((void *)tmpctx, &ls_pub, &dummy, NULL, NORMAL_SOCKET, success, NULL); /* Should not exit! */ abort(); } diff --git a/connectd/test/run-websocket.c b/connectd/test/run-websocket.c index db4ff47eb805..93d4f9caade1 100644 --- a/connectd/test/run-websocket.c +++ b/connectd/test/run-websocket.c @@ -63,12 +63,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_eq */ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_eq called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/connectd/tor_autoservice.c b/connectd/tor_autoservice.c index 33b6b970f6ab..4b08f9235f82 100644 --- a/connectd/tor_autoservice.c +++ b/connectd/tor_autoservice.c @@ -1,5 +1,4 @@ #include "config.h" -#include #include #include #include @@ -114,7 +113,7 @@ static struct wireaddr *make_onion(const tal_t *ctx, port, fmt_wireaddr(tmpctx, local))); while ((line = tor_response_line(rbuf)) != NULL) { - const char *name; + const char *name, *err; if (!strstarts(line, "ServiceID=")) continue; @@ -125,9 +124,10 @@ static struct wireaddr *make_onion(const tal_t *ctx, name = tal_fmt(tmpctx, "%s.onion", line); onion = tal(ctx, struct wireaddr); - if (!parse_wireaddr(name, onion, local->port, false, NULL)) + err = parse_wireaddr(tmpctx, name, local->port, NULL, onion); + if (err) status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Tor gave bad onion name '%s'", name); + "Tor gave bad onion name '%s': %s", name, err); status_info("New autotor service onion address: \"%s:%d\" bound from extern port:%d", name, local->port, port); discard_remaining_response(rbuf); return onion; @@ -151,7 +151,7 @@ static struct wireaddr *make_fixed_onion(const tal_t *ctx, blob64, port, fmt_wireaddr(tmpctx, local))); while ((line = tor_response_line_wfail(rbuf))) { - const char *name; + const char *name, *err; if (strstarts(line, "Onion address collision")) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Tor address in use"); @@ -165,9 +165,10 @@ static struct wireaddr *make_fixed_onion(const tal_t *ctx, name = tal_fmt(tmpctx, "%s.onion", line); onion = tal(ctx, struct wireaddr); - if (!parse_wireaddr(name, onion, port, false, NULL)) + err = parse_wireaddr(tmpctx, name, port, false, onion); + if (err) status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Tor gave bad onion name '%s'", name); + "Tor gave bad onion name '%s': %s", name, err); #ifdef SUPERVERBOSE status_info("Static Tor service onion address: \"%s:%d,%s\"from blob %s base64 %s ", name, port ,fmt_wireaddr(tmpctx, local), blob ,blob64); @@ -272,10 +273,12 @@ struct wireaddr *tor_autoservice(const tal_t *ctx, fd = socket(ai_tor->ai_family, SOCK_STREAM, 0); if (fd < 0) - err(1, "Creating stream socket for Tor"); + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Creating stream socket for Tor"); if (connect(fd, ai_tor->ai_addr, ai_tor->ai_addrlen) != 0) - err(1, "Connecting stream socket to Tor service"); + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Connecting stream socket to Tor service"); buffer = tal_arr(tmpctx, char, rbuf_good_size(fd)); rbuf_init(&rbuf, fd, buffer, tal_count(buffer), buf_resize); @@ -312,10 +315,12 @@ struct wireaddr *tor_fixed_service(const tal_t *ctx, fd = socket(ai_tor->ai_family, SOCK_STREAM, 0); if (fd < 0) - err(1, "Creating stream socket for Tor"); + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Creating stream socket for Tor"); if (connect(fd, ai_tor->ai_addr, ai_tor->ai_addrlen) != 0) - err(1, "Connecting stream socket to Tor service"); + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Connecting stream socket to Tor service"); buffer = tal_arr(tmpctx, char, rbuf_good_size(fd)); rbuf_init(&rbuf, fd, buffer, tal_count(buffer), buf_resize); diff --git a/connectd/websocketd.c b/connectd/websocketd.c index 9dc65bec2fcc..782530426069 100644 --- a/connectd/websocketd.c +++ b/connectd/websocketd.c @@ -109,6 +109,7 @@ static const char *get_http_hdr(const tal_t *ctx, const u8 *buf, size_t buflen, && buf[strlen(hdrname)] == ':') break; buf = end + 2; + buflen -= hdrlen + 2; } buf += strlen(hdrname) + 1; diff --git a/contrib/docker/Dockerfile.alpine b/contrib/docker/Dockerfile.alpine index 375de7faf348..ddae6b2a1c37 100644 --- a/contrib/docker/Dockerfile.alpine +++ b/contrib/docker/Dockerfile.alpine @@ -12,7 +12,6 @@ RUN apk update && \ cargo \ gettext \ git \ - gmp-dev \ libsodium \ libtool \ net-tools \ diff --git a/contrib/docker/linuxarm32v7.Dockerfile b/contrib/docker/Dockerfile.arm32v7 similarity index 59% rename from contrib/docker/linuxarm32v7.Dockerfile rename to contrib/docker/Dockerfile.arm32v7 index 8bea5cbfadc9..59ca33b00baf 100644 --- a/contrib/docker/linuxarm32v7.Dockerfile +++ b/contrib/docker/Dockerfile.arm32v7 @@ -1,22 +1,19 @@ -# This dockerfile is meant to cross compile with a x64 machine for a arm32v7 host -# It is using multi stage build: +# This dockerfile is meant to compile a core-lightning arm32v7 image +# It is using multi stage build: # * downloader: Download litecoin/bitcoin and qemu binaries needed for core-lightning -# * builder: Cross compile c-lightning dependencies, then c-lightning itself with static linking +# * builder: Compile core-lightning dependencies, then core-lightning itself with static linking # * final: Copy the binaries required at runtime # The resulting image uploaded to dockerhub will only contain what is needed for runtime. -# From the root of the repository, run "docker build -t yourimage:yourtag -f contrib/linuxarm32v7.Dockerfile ." +# From the root of the repository, run "docker build -t yourimage:yourtag ." FROM debian:bullseye-slim as downloader RUN set -ex \ - && apt-get update \ - && apt-get install -qq --no-install-recommends ca-certificates dirmngr wget \ - qemu-user-static binfmt-support +&& apt-get update \ +&& apt-get install -qq --no-install-recommends ca-certificates dirmngr wget -WORKDIR /opt - -RUN wget -qO /opt/tini "https://github.com/krallin/tini/releases/download/v0.18.0/tini-armhf" \ - && echo "01b54b934d5f5deb32aa4eb4b0f71d0e76324f4f0237cc262d59376bf2bdc269 /opt/tini" | sha256sum -c - \ - && chmod +x /opt/tini +ADD https://github.com/krallin/tini/releases/download/v0.19.0/tini-static-armel /tini +ADD https://github.com/krallin/tini/releases/download/v0.19.0/tini-static-armel.asc /tini.asc +RUN chmod +x /tini ARG BITCOIN_VERSION=22.0 ENV BITCOIN_TARBALL bitcoin-$BITCOIN_VERSION-arm-linux-gnueabihf.tar.gz @@ -47,7 +44,6 @@ RUN mkdir /opt/litecoin && cd /opt/litecoin \ FROM debian:bullseye-slim as builder ENV LIGHTNINGD_VERSION=master - RUN apt-get update -qq && \ apt-get install -qq -y --no-install-recommends \ autoconf \ @@ -62,73 +58,65 @@ RUN apt-get update -qq && \ libpq-dev \ libtool \ libffi-dev \ + protobuf-compiler \ python3 \ python3-dev \ python3-mako \ python3-pip \ python3-venv \ python3-setuptools \ - wget && \ - # arm32v7 compilers - apt-get install -qq -y --no-install-recommends \ - libc6-armhf-cross \ - gcc-arm-linux-gnueabihf \ - g++-arm-linux-gnueabihf - -ENV target_host=arm-linux-gnueabihf + wget -ENV AR=${target_host}-ar \ -AS=${target_host}-as \ -CC=${target_host}-gcc \ -CXX=${target_host}-g++ \ -LD=${target_host}-ld \ -STRIP=${target_host}-strip \ -QEMU_LD_PREFIX=/usr/${target_host} \ -HOST=${target_host} +RUN apt-get update && apt-get install -y pkg-config libssl-dev +ENV PKG_CONFIG_PATH /usr/lib/arm-linux-gnueabihf/pkgconfig RUN wget -q https://zlib.net/fossils/zlib-1.2.13.tar.gz \ -&& tar xvf zlib-1.2.13.tar.gz \ -&& cd zlib-1.2.13 \ -&& ./configure --prefix=$QEMU_LD_PREFIX \ -&& make \ -&& make install && cd .. && rm zlib-1.2.13.tar.gz && rm -rf zlib-1.2.13 + && tar xvf zlib-1.2.13.tar.gz \ + && cd zlib-1.2.13 \ + && ./configure \ + && make \ + && make install && cd .. && \ + rm zlib-1.2.13.tar.gz && \ + rm -rf zlib-1.2.13 RUN apt-get install -y --no-install-recommends unzip tclsh \ -&& wget -q https://www.sqlite.org/2019/sqlite-src-3290000.zip \ -&& unzip sqlite-src-3290000.zip \ -&& cd sqlite-src-3290000 \ -&& ./configure --enable-static --disable-readline --disable-threadsafe --disable-load-extension --host=${target_host} --prefix=$QEMU_LD_PREFIX \ -&& make \ -&& make install && cd .. && rm sqlite-src-3290000.zip && rm -rf sqlite-src-3290000 - + && wget -q https://www.sqlite.org/2019/sqlite-src-3290000.zip \ + && unzip sqlite-src-3290000.zip \ + && cd sqlite-src-3290000 \ + && ./configure --enable-static --disable-readline --disable-threadsafe --disable-load-extension \ + && make \ + && make install && cd .. && rm sqlite-src-3290000.zip && rm -rf sqlite-src-3290000 + +USER root RUN wget -q https://gmplib.org/download/gmp/gmp-6.1.2.tar.xz \ -&& tar xvf gmp-6.1.2.tar.xz \ -&& cd gmp-6.1.2 \ -&& ./configure --disable-assembly --prefix=$QEMU_LD_PREFIX --host=${target_host} \ -&& make \ -&& make install && cd .. && rm gmp-6.1.2.tar.xz && rm -rf gmp-6.1.2 + && tar xvf gmp-6.1.2.tar.xz \ + && cd gmp-6.1.2 \ + && ./configure --disable-assembly \ + && make \ + && make install && cd .. && rm gmp-6.1.2.tar.xz && rm -rf gmp-6.1.2 + +ENV RUST_PROFILE=release +ENV PATH=$PATH:/root/.cargo/bin/ +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +RUN rustup toolchain install stable --component rustfmt --allow-downgrade -COPY --from=downloader /usr/bin/qemu-arm-static /usr/bin/qemu-arm-static WORKDIR /opt/lightningd COPY . /tmp/lightning RUN git clone --recursive /tmp/lightning . && \ git checkout $(git --work-tree=/tmp/lightning --git-dir=/tmp/lightning/.git rev-parse HEAD) -ARG DEVELOPER=0 +ARG DEVELOPER=1 ENV PYTHON_VERSION=3 - -RUN curl -sSL https://install.python-poetry.org | python3 - \ -&& pip3 install -U pip \ -&& pip3 install -U wheel \ -&& /root/.local/bin/poetry install +RUN curl -sSL https://install.python-poetry.org | python3 - +RUN pip3 install -U pip +RUN pip3 install -U wheel +RUN /root/.local/bin/poetry install RUN ./configure --prefix=/tmp/lightning_install --enable-static && \ -make DEVELOPER=${DEVELOPER} && \ -/root/.local/bin/poetry run make install + make DEVELOPER=${DEVELOPER} && \ + /root/.local/bin/poetry run make install -FROM arm32v7/debian:bullseye-slim as final -COPY --from=downloader /usr/bin/qemu-arm-static /usr/bin/qemu-arm-static -COPY --from=downloader /opt/tini /usr/bin/tini +FROM debian:bullseye-slim as final RUN apt-get update && \ apt-get install -y --no-install-recommends \ @@ -150,6 +138,7 @@ VOLUME [ "/root/.lightning" ] COPY --from=builder /tmp/lightning_install/ /usr/local/ COPY --from=downloader /opt/bitcoin/bin /usr/bin COPY --from=downloader /opt/litecoin/bin /usr/bin +COPY --from=downloader "/tini" /usr/bin/tini COPY tools/docker-entrypoint.sh entrypoint.sh EXPOSE 9735 9835 diff --git a/contrib/docker/linuxarm64v8.Dockerfile b/contrib/docker/Dockerfile.arm64v8 similarity index 61% rename from contrib/docker/linuxarm64v8.Dockerfile rename to contrib/docker/Dockerfile.arm64v8 index 79f3ed8bad59..5ea8f03ec7b0 100644 --- a/contrib/docker/linuxarm64v8.Dockerfile +++ b/contrib/docker/Dockerfile.arm64v8 @@ -1,25 +1,27 @@ -# This dockerfile is meant to cross compile with a x64 machine for a arm64v8 host -# It is using multi stage build: -# * downloader: Download litecoin/bitcoin and qemu binaries needed for Core Lightning -# * builder: Cross compile Core Lightning dependencies, then Core Lightning itself with static linking +# This dockerfile is meant to compile a core-lightning arm64v8 image +# It is using multi stage build: +# * downloader: Download litecoin/bitcoin and qemu binaries needed for core-lightning +# * builder: Compile core-lightning dependencies, then core-lightning itself with static linking # * final: Copy the binaries required at runtime # The resulting image uploaded to dockerhub will only contain what is needed for runtime. -# From the root of the repository, run "docker build -t yourimage:yourtag -f contrib/linuxarm64v8.Dockerfile ." +# From the root of the repository, run "docker build -t yourimage:yourtag ." FROM debian:bullseye-slim as downloader RUN set -ex \ && apt-get update \ - && apt-get install -qq --no-install-recommends ca-certificates dirmngr wget \ - qemu-user-static binfmt-support + && apt-get install -qq --no-install-recommends ca-certificates dirmngr wget + +ADD https://github.com/krallin/tini/releases/download/v0.19.0/tini-static-arm64 /tini +RUN chmod +x /tini WORKDIR /opt -RUN wget -qO /opt/tini "https://github.com/krallin/tini/releases/download/v0.18.0/tini-arm64" \ - && echo "7c5463f55393985ee22357d976758aaaecd08defb3c5294d353732018169b019 /opt/tini" | sha256sum -c - \ +RUN wget -qO /opt/tini "https://github.com/krallin/tini/releases/download/v0.18.0/tini" \ + && echo "12d20136605531b09a2c2dac02ccee85e1b874eb322ef6baf7561cd93f93c855 /opt/tini" | sha256sum -c - \ && chmod +x /opt/tini ARG BITCOIN_VERSION=22.0 -ENV BITCOIN_TARBALL bitcoin-$BITCOIN_VERSION-aarch64-linux-gnu.tar.gz +ENV BITCOIN_TARBALL bitcoin-${BITCOIN_VERSION}-aarch64-linux-gnu.tar.gz ENV BITCOIN_URL https://bitcoincore.org/bin/bitcoin-core-$BITCOIN_VERSION/$BITCOIN_TARBALL ENV BITCOIN_ASC_URL https://bitcoincore.org/bin/bitcoin-core-$BITCOIN_VERSION/SHA256SUMS @@ -32,9 +34,8 @@ RUN mkdir /opt/bitcoin && cd /opt/bitcoin \ && tar -xzvf $BITCOIN_TARBALL $BD/bitcoin-cli --strip-components=1 \ && rm $BITCOIN_TARBALL - ENV LITECOIN_VERSION 0.16.3 -ENV LITECOIN_URL https://download.litecoin.org/litecoin-${LITECOIN_VERSION}/linux/litecoin-${LITECOIN_VERSION}-aarch64-linux-gnu.tar.gz +ENV LITECOIN_URL https://download.litecoin.org/litecoin-${LITECOIN_VERSION}/linux/litecoin-${LITECOIN_VERSION}-aarch64-linux-gnu.tar.gz ENV LITECOIN_SHA256 3284316bdf10496528b3cd730877be3a1ea34add49dfc88fe0e96eb9925c1f08 # install litecoin binaries @@ -48,7 +49,6 @@ RUN mkdir /opt/litecoin && cd /opt/litecoin \ FROM debian:bullseye-slim as builder ENV LIGHTNINGD_VERSION=master - RUN apt-get update -qq && \ apt-get install -qq -y --no-install-recommends \ autoconf \ @@ -63,71 +63,66 @@ RUN apt-get update -qq && \ libpq-dev \ libtool \ libffi-dev \ + protobuf-compiler \ python3 \ python3-dev \ python3-mako \ python3-pip \ python3-venv \ python3-setuptools \ - wget && \ - # arm64v8 compilers - apt-get install -qq -y --no-install-recommends \ - libc6-arm64-cross \ - gcc-aarch64-linux-gnu \ - g++-aarch64-linux-gnu - -ENV target_host=aarch64-linux-gnu + wget -ENV AR=${target_host}-ar \ -AS=${target_host}-as \ -CC=${target_host}-gcc \ -CXX=${target_host}-g++ \ -LD=${target_host}-ld \ -STRIP=${target_host}-strip \ -QEMU_LD_PREFIX=/usr/${target_host} \ -HOST=${target_host} +RUN apt-get update && apt-get install -y pkg-config libssl-dev +ENV PKG_CONFIG_PATH /usr/lib/arm-linux-gnueabihf/pkgconfig RUN wget -q https://zlib.net/fossils/zlib-1.2.13.tar.gz \ -&& tar xvf zlib-1.2.13.tar.gz \ -&& cd zlib-1.2.13 \ -&& ./configure --prefix=$QEMU_LD_PREFIX \ -&& make \ -&& make install && cd .. && rm zlib-1.2.13.tar.gz && rm -rf zlib-1.2.13 + && tar xvf zlib-1.2.13.tar.gz \ + && cd zlib-1.2.13 \ + && ./configure \ + && make \ + && make install && cd .. && \ + rm zlib-1.2.13.tar.gz && \ + rm -rf zlib-1.2.13 RUN apt-get install -y --no-install-recommends unzip tclsh \ -&& wget -q https://www.sqlite.org/2019/sqlite-src-3290000.zip \ -&& unzip sqlite-src-3290000.zip \ -&& cd sqlite-src-3290000 \ -&& ./configure --enable-static --disable-readline --disable-threadsafe --disable-load-extension --host=${target_host} --prefix=$QEMU_LD_PREFIX \ -&& make \ -&& make install && cd .. && rm sqlite-src-3290000.zip && rm -rf sqlite-src-3290000 - + && wget -q https://www.sqlite.org/2019/sqlite-src-3290000.zip \ + && unzip sqlite-src-3290000.zip \ + && cd sqlite-src-3290000 \ + && ./configure --enable-static --disable-readline --disable-threadsafe --disable-load-extension \ + && make \ + && make install && cd .. && rm sqlite-src-3290000.zip && rm -rf sqlite-src-3290000 + +USER root RUN wget -q https://gmplib.org/download/gmp/gmp-6.1.2.tar.xz \ -&& tar xvf gmp-6.1.2.tar.xz \ -&& cd gmp-6.1.2 \ -&& ./configure --disable-assembly --prefix=$QEMU_LD_PREFIX --host=${target_host} \ -&& make \ -&& make install && cd .. && rm gmp-6.1.2.tar.xz && rm -rf gmp-6.1.2 -COPY --from=downloader /usr/bin/qemu-aarch64-static /usr/bin/qemu-aarch64-static + && tar xvf gmp-6.1.2.tar.xz \ + && cd gmp-6.1.2 \ + && ./configure --disable-assembly \ + && make \ + && make install && cd .. && rm gmp-6.1.2.tar.xz && rm -rf gmp-6.1.2 + +ENV RUST_PROFILE=release +ENV PATH=$PATH:/root/.cargo/bin/ +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +RUN rustup toolchain install stable --component rustfmt --allow-downgrade + WORKDIR /opt/lightningd COPY . /tmp/lightning RUN git clone --recursive /tmp/lightning . && \ git checkout $(git --work-tree=/tmp/lightning --git-dir=/tmp/lightning/.git rev-parse HEAD) -ARG DEVELOPER=0 +ARG DEVELOPER=1 ENV PYTHON_VERSION=3 - -RUN curl -sSL https://install.python-poetry.org | python3 - \ -&& pip3 install -U pip \ -&& pip3 install -U wheel \ -&& /root/.local/bin/poetry install +RUN curl -sSL https://install.python-poetry.org | python3 - +RUN pip3 install -U pip +RUN pip3 install -U wheel +RUN /root/.local/bin/poetry install RUN ./configure --prefix=/tmp/lightning_install --enable-static && \ -make DEVELOPER=${DEVELOPER} && \ -/root/.local/bin/poetry run make install + make DEVELOPER=${DEVELOPER} && \ + /root/.local/bin/poetry run make install + +FROM debian:bullseye-slim as final -FROM arm64v8/debian:bullseye-slim as final -COPY --from=downloader /usr/bin/qemu-aarch64-static /usr/bin/qemu-aarch64-static COPY --from=downloader /opt/tini /usr/bin/tini RUN apt-get update && \ @@ -150,6 +145,7 @@ VOLUME [ "/root/.lightning" ] COPY --from=builder /tmp/lightning_install/ /usr/local/ COPY --from=downloader /opt/bitcoin/bin /usr/bin COPY --from=downloader /opt/litecoin/bin /usr/bin +COPY --from=downloader "/tini" /usr/bin/tini COPY tools/docker-entrypoint.sh entrypoint.sh EXPOSE 9735 9835 diff --git a/contrib/docker/Dockerfile.builder b/contrib/docker/Dockerfile.builder index 26e3be204baa..2c717a907fcb 100644 --- a/contrib/docker/Dockerfile.builder +++ b/contrib/docker/Dockerfile.builder @@ -22,7 +22,6 @@ RUN apt-get -qq update && \ libtool \ libprotobuf-c-dev \ libsqlite3-dev \ - libgmp-dev \ git \ python3 \ valgrind \ diff --git a/contrib/docker/Dockerfile.builder.fedora b/contrib/docker/Dockerfile.builder.fedora index 4a43c033e2e8..f5fe4d4207c4 100644 --- a/contrib/docker/Dockerfile.builder.fedora +++ b/contrib/docker/Dockerfile.builder.fedora @@ -9,7 +9,6 @@ RUN dnf update -y && \ 'Development Tools' && \ dnf install -y \ clang \ - gmp-devel \ libsq3-devel \ python3-devel \ python3-mako \ diff --git a/contrib/docker/Dockerfile.tester b/contrib/docker/Dockerfile.tester index 3b1e47b3e5c5..6da1aad543f7 100644 --- a/contrib/docker/Dockerfile.tester +++ b/contrib/docker/Dockerfile.tester @@ -27,7 +27,6 @@ RUN apt-get -qq update && \ git \ libc6-dev-arm64-cross \ libc6-dev-armhf-cross \ - libgmp-dev \ libpq-dev \ libprotobuf-c-dev \ libsqlite3-dev \ diff --git a/contrib/docker/scripts/build.sh b/contrib/docker/scripts/build.sh index 806e28e439e9..61368321b663 100755 --- a/contrib/docker/scripts/build.sh +++ b/contrib/docker/scripts/build.sh @@ -7,7 +7,6 @@ export CC=${COMPILER:-gcc} export COMPAT=${COMPAT:-1} export TEST_CHECK_DBSTMTS=${TEST_CHECK_DBSTMTS:-0} export DEVELOPER=${DEVELOPER:-1} -export EXPERIMENTAL_FEATURES=${EXPERIMENTAL_FEATURES:-0} export PATH=$CWD/dependencies/bin:"$HOME"/.local/bin:"$PATH" export PYTEST_OPTS="--maxfail=5 --suppress-no-test-exit-code ${PYTEST_OPTS}" export PYTEST_PAR=${PYTEST_PAR:-10} @@ -78,16 +77,6 @@ then rm sqlite-src-3260000.zip rm -rf sqlite-src-3260000 - wget -q https://gmplib.org/download/gmp/gmp-6.1.2.tar.xz - tar xf gmp-6.1.2.tar.xz - cd gmp-6.1.2 || exit 1 - ./configure --disable-assembly --prefix="$QEMU_LD_PREFIX" --host="$TARGET_HOST" - make - sudo make install - cd .. - rm gmp-6.1.2.tar.xz - rm -rf gmp-6.1.2 - ./configure CC="$TARGET_HOST-gcc" --enable-static make -j32 CC="$TARGET_HOST-gcc" > /dev/null diff --git a/contrib/docker/scripts/setup.sh b/contrib/docker/scripts/setup.sh index 18cf124f3f22..6f9cbdb76022 100755 --- a/contrib/docker/scripts/setup.sh +++ b/contrib/docker/scripts/setup.sh @@ -24,7 +24,6 @@ sudo apt-get -qq install --no-install-recommends --allow-unauthenticated -yy \ git \ libc6-dev-arm64-cross \ libc6-dev-armhf-cross \ - libgmp-dev \ libpq-dev \ libprotobuf-c-dev \ libsqlite3-dev \ diff --git a/contrib/msggen/README.md b/contrib/msggen/README.md index 2c90f9f94ee0..ea71e7a9c674 100644 --- a/contrib/msggen/README.md +++ b/contrib/msggen/README.md @@ -21,3 +21,22 @@ digraph { "Rust JSON-RPC structs" -> "cln-rpc"; } ``` + +`msggen` will load the schemas in `doc/schemas` into memory, and then +use `Patches` to enrich the model before using it to generate the +bindings for the various languages as well as the converters from one +format to another. These patches can be found in `msggen/patch.py` and +perform a variety of operations: + + - Annotate the model with additional data from external sources, such + as the `.msggen.json` file at the repository root to track details + that can be derived but should remain constant (grpc field + numbering and versioning information) + - Aggregate common types with type overrides and omit fields that we + can't map currently. + - Infer optionality based on the versions a field was added or + deprecated, and the currently supported range of versions. + +If there is a field that is currently missing in the model, that is in +the schemas it is most likely because it has been marked as omitted in +the patch. diff --git a/contrib/msggen/msggen/__main__.py b/contrib/msggen/msggen/__main__.py index 5f9fdc2b8f35..20fcbc6f66dd 100644 --- a/contrib/msggen/msggen/__main__.py +++ b/contrib/msggen/msggen/__main__.py @@ -7,6 +7,18 @@ from msggen.gen.rust import RustGenerator from msggen.gen.generator import GeneratorChain from msggen.utils import load_jsonrpc_service +import logging +from msggen.patch import VersionAnnotationPatch, OptionalPatch, OverridePatch +from msggen.checks import VersioningCheck + + +logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s [%(levelname)s] %(message)s", + handlers=[ + logging.StreamHandler() + ] +) def add_handler_gen_grpc(generator_chain: GeneratorChain, meta): @@ -52,8 +64,22 @@ def write_msggen_meta(meta): def run(rootdir: Path): schemadir = rootdir / "doc" / "schemas" - service = load_jsonrpc_service(schema_dir=schemadir) meta = load_msggen_meta() + service = load_jsonrpc_service( + schema_dir=schemadir, + ) + + p = VersionAnnotationPatch(meta=meta) + p.apply(service) + OptionalPatch().apply(service) + + # Mark some fields we can't map as omitted, and for complex types + # we manually mapped, use those types instead. + OverridePatch().apply(service) + + # Run the checks here, we should eventually split that out to a + # separate subcommand + VersioningCheck().check(service) generator_chain = GeneratorChain() add_handler_gen_grpc(generator_chain, meta) diff --git a/contrib/msggen/msggen/checks.py b/contrib/msggen/msggen/checks.py new file mode 100644 index 000000000000..1f97d87a2043 --- /dev/null +++ b/contrib/msggen/msggen/checks.py @@ -0,0 +1,36 @@ +from abc import ABC +from msggen import model + + +class Check(ABC): + """A check is a visitor that throws exceptions on inconsistencies. + + """ + def visit(self, field: model.Field) -> None: + pass + + def check(self, service: model.Service) -> None: + def recurse(f: model.Field): + # First recurse if we have further type definitions + if isinstance(f, model.ArrayField): + self.visit(f.itemtype) + recurse(f.itemtype) + elif isinstance(f, model.CompositeField): + for c in f.fields: + self.visit(c) + recurse(c) + # Now visit ourselves + self.visit(f) + for m in service.methods: + recurse(m.request) + recurse(m.response) + + +class VersioningCheck(Check): + """Check that all schemas have the `added` and `deprecated` annotations. + """ + def visit(self, f: model.Field) -> None: + if not hasattr(f, "added"): + raise ValueError(f"Field {f.path} is missing the `added` annotation") + if not hasattr(f, "deprecated"): + raise ValueError(f"Field {f.path} is missing the `deprecated` annotation") diff --git a/contrib/msggen/msggen/gen/grpc.py b/contrib/msggen/msggen/gen/grpc.py index 2dd6adcc6c74..920dfe3bad47 100644 --- a/contrib/msggen/msggen/gen/grpc.py +++ b/contrib/msggen/msggen/gen/grpc.py @@ -16,7 +16,7 @@ 'number': 'double', 'pubkey': 'bytes', 'short_channel_id': 'string', - 'signature': 'bytes', + 'signature': 'string', 'string': 'string', 'txid': 'bytes', 'u8': 'uint32', # Yep, this is the smallest integer type in grpc... @@ -33,20 +33,9 @@ } -# Manual overrides for some of the auto-generated types for paths -overrides = { - # Truncate the tree here, it's a complex structure with identitcal - # types - 'ListPeers.peers[].channels[].state_changes[]': None, - 'ListPeers.peers[].channels[].htlcs[].state': None, - 'ListPeers.peers[].channels[].opener': "ChannelSide", - 'ListPeers.peers[].channels[].closer': "ChannelSide", - 'ListPeers.peers[].channels[].features[]': "string", - 'ListFunds.channels[].state': 'ChannelState', - 'ListTransactions.transactions[].type[]': None, -} - - +# GRPC builds a stub with the methods declared in the protobuf file, +# but it also comes with its own methods, e.g., `connect` which can +# clash with the generated ones. So rename the ones we know clash. method_name_overrides = { "Connect": "ConnectPeer", } @@ -178,7 +167,7 @@ def generate_enum(self, e: EnumField, indent=0): self.write(f"""{prefix}}}\n""", False) def generate_message(self, message: CompositeField): - if overrides.get(message.path, "") is None: + if message.omit(): return self.write(f""" @@ -187,33 +176,26 @@ def generate_message(self, message: CompositeField): # Declare enums inline so they are scoped correctly in C++ for _, f in enumerate(message.fields): - if isinstance(f, EnumField) and f.path not in overrides.keys(): + if isinstance(f, EnumField) and not f.override(): self.generate_enum(f, indent=1) for i, f in self.enumerate_fields(message.typename, message.fields): - if overrides.get(f.path, "") is None: + if f.omit(): continue - opt = "optional " if not f.required else "" + opt = "optional " if f.optional else "" + if isinstance(f, ArrayField): - typename = typemap.get(f.itemtype.typename, f.itemtype.typename) - if f.path in overrides: - typename = overrides[f.path] + typename = f.override(typemap.get(f.itemtype.typename, f.itemtype.typename)) self.write(f"\trepeated {typename} {f.normalized()} = {i};\n", False) elif isinstance(f, PrimitiveField): - typename = typemap.get(f.typename, f.typename) - if f.path in overrides: - typename = overrides[f.path] + typename = f.override(typemap.get(f.typename, f.typename)) self.write(f"\t{opt}{typename} {f.normalized()} = {i};\n", False) elif isinstance(f, EnumField): - typename = f.typename - if f.path in overrides: - typename = overrides[f.path] + typename = f.override(f.typename) self.write(f"\t{opt}{typename} {f.normalized()} = {i};\n", False) elif isinstance(f, CompositeField): - typename = f.typename - if f.path in overrides: - typename = overrides[f.path] + typename = f.override(f.typename) self.write(f"\t{opt}{typename} {f.normalized()} = {i};\n", False) self.write(f"""}} @@ -253,7 +235,7 @@ def generate_array(self, prefix, field: ArrayField): def generate_composite(self, prefix, field: CompositeField): """Generates the conversions from JSON-RPC to GRPC. """ - if overrides.get(field.path, "") is None: + if field.omit(): return # First pass: generate any sub-fields before we generate the @@ -267,14 +249,14 @@ def generate_composite(self, prefix, field: CompositeField): pbname = self.to_camel_case(field.typename) # And now we can convert the current field: self.write(f"""\ - #[allow(unused_variables)] + #[allow(unused_variables,deprecated)] impl From<{prefix}::{field.typename}> for pb::{pbname} {{ fn from(c: {prefix}::{field.typename}) -> Self {{ Self {{ """) for f in field.fields: - if overrides.get(f.path, "") is None: + if f.omit(): continue name = f.normalized() @@ -286,20 +268,22 @@ def generate_composite(self, prefix, field: CompositeField): mapping = { 'hex': f'hex::decode(i).unwrap()', 'secret': f'i.to_vec()', + 'hash': f'i.to_vec()', }.get(typ, f'i.into()') - if f.required: - self.write(f"{name}: c.{name}.into_iter().map(|i| {mapping}).collect(), // Rule #3 for type {typ} \n", numindent=3) + self.write(f"// Field: {f.path}\n", numindent=3) + if not f.optional: + self.write(f"{name}: c.{name}.into_iter().map(|i| {mapping}).collect(), // Rule #3 for type {typ}\n", numindent=3) else: - self.write(f"{name}: c.{name}.map(|arr| arr.into_iter().map(|i| {mapping}).collect()).unwrap_or(vec![]), // Rule #3 \n", numindent=3) + self.write(f"{name}: c.{name}.map(|arr| arr.into_iter().map(|i| {mapping}).collect()).unwrap_or(vec![]), // Rule #3\n", numindent=3) elif isinstance(f, EnumField): - if f.required: + if not f.optional: self.write(f"{name}: c.{name} as i32,\n", numindent=3) else: self.write(f"{name}: c.{name}.map(|v| v as i32),\n", numindent=3) elif isinstance(f, PrimitiveField): - typ = f.typename + ("?" if not f.required else "") + typ = f.typename + ("?" if f.optional else "") # We may need to reduce or increase the size of some # types, or have some conversion such as # hex-decoding. Also includes the `Some()` that grpc @@ -322,16 +306,29 @@ def generate_composite(self, prefix, field: CompositeField): 'hash?': f'c.{name}.map(|v| v.to_vec())', 'secret': f'c.{name}.to_vec()', 'secret?': f'c.{name}.map(|v| v.to_vec())', + + 'msat_or_any': f'Some(c.{name}.into())', + 'msat_or_all': f'Some(c.{name}.into())', + 'msat_or_all?': f'c.{name}.map(|o|o.into())', + 'feerate?': f'c.{name}.map(|o|o.into())', + 'feerate': f'Some(c.{name}.into())', + 'outpoint?': f'c.{name}.map(|o|o.into())', + 'TlvStream?': f'c.{name}.map(|s| s.into())', + 'RoutehintList?': f'c.{name}.map(|rl| rl.into())', + + }.get( typ, f'c.{name}' # default to just assignment ) + if f.deprecated: + self.write(f"#[allow(deprecated)]\n", numindent=3) self.write(f"{name}: {rhs}, // Rule #2 for type {typ}\n", numindent=3) elif isinstance(f, CompositeField): rhs = "" - if f.required: + if not f.optional: rhs = f'Some(c.{name}.into())' else: rhs = f'c.{name}.map(|v| v.into())' @@ -377,6 +374,8 @@ def generate(self, service: Service) -> None: """) self.generate_responses(service) + self.generate_requests(service) + self.write("\n") def write(self, text: str, numindent: int = 0) -> None: raw = dedent(text) @@ -392,10 +391,13 @@ class GrpcUnconverterGenerator(GrpcConverterGenerator): def generate(self, service: Service): self.generate_requests(service) + # TODO Temporarily disabled since the use of overrides is lossy + # self.generate_responses(service) + def generate_composite(self, prefix, field: CompositeField) -> None: # First pass: generate any sub-fields before we generate the # top-level field itself. - if overrides.get(field.path, "") is None: + if field.omit(): return for f in field.fields: @@ -407,7 +409,7 @@ def generate_composite(self, prefix, field: CompositeField) -> None: pbname = self.to_camel_case(field.typename) # And now we can convert the current field: self.write(f"""\ - #[allow(unused_variables)] + #[allow(unused_variables,deprecated)] impl From for {prefix}::{field.typename} {{ fn from(c: pb::{pbname}) -> Self {{ Self {{ @@ -415,31 +417,50 @@ def generate_composite(self, prefix, field: CompositeField) -> None: for f in field.fields: name = f.normalized() + if f.omit(): + continue + if isinstance(f, ArrayField): typ = f.itemtype.typename mapping = { 'hex': f'hex::encode(s)', 'u32': f's', - 'secret': f's.try_into().unwrap()' + 'secret': f's.try_into().unwrap()', + 'hash': f'Sha256::from_slice(&s).unwrap()', }.get(typ, f's.into()') - if f.required: + + # TODO fix properly + if typ in ["ListtransactionsTransactionsType"]: + continue + if name == 'state_changes': + self.write(f" state_changes: None,") + continue + + if not f.optional: self.write(f"{name}: c.{name}.into_iter().map(|s| {mapping}).collect(), // Rule #4\n", numindent=3) else: self.write(f"{name}: Some(c.{name}.into_iter().map(|s| {mapping}).collect()), // Rule #4\n", numindent=3) elif isinstance(f, EnumField): - if f.required: + if f.path == 'ListPeers.peers[].channels[].htlcs[].state': + continue + if not f.optional: self.write(f"{name}: c.{name}.try_into().unwrap(),\n", numindent=3) else: self.write(f"{name}: c.{name}.map(|v| v.try_into().unwrap()),\n", numindent=3) pass elif isinstance(f, PrimitiveField): - typ = f.typename + ("?" if not f.required else "") + typ = f.typename + ("?" if f.optional else "") # We may need to reduce or increase the size of some # types, or have some conversion such as # hex-decoding. Also includes the `Some()` that grpc # requires for non-native types. + + if name == "scriptPubKey": + name = "script_pub_key" + rhs = { + 'u8': f'c.{name} as u8', 'u16': f'c.{name} as u16', 'u16?': f'c.{name}.map(|v| v as u16)', 'hex': f'hex::encode(&c.{name})', @@ -472,7 +493,7 @@ def generate_composite(self, prefix, field: CompositeField) -> None: self.write(f"{name}: {rhs}, // Rule #1 for type {typ}\n", numindent=3) elif isinstance(f, CompositeField): rhs = "" - if f.required: + if not f.optional: rhs = f'c.{name}.unwrap().into()' else: rhs = f'c.{name}.map(|v| v.into())' diff --git a/contrib/msggen/msggen/gen/grpc2py.py b/contrib/msggen/msggen/gen/grpc2py.py index 8bc791823fe1..503eff1629b9 100644 --- a/contrib/msggen/msggen/gen/grpc2py.py +++ b/contrib/msggen/msggen/gen/grpc2py.py @@ -69,12 +69,10 @@ def generate(self, service: Service) -> None: def hexlify(b): return b if b is None else b.hex() + def amount2msat(a): return a.msat - def amount_or_all2msat(a): - breakpoint() - def remove_default(d): # grpc is really not good at empty values, they get replaced with the type's default value... diff --git a/contrib/msggen/msggen/gen/rust.py b/contrib/msggen/msggen/gen/rust.py index a773f065cff1..88a113b920f8 100644 --- a/contrib/msggen/msggen/gen/rust.py +++ b/contrib/msggen/msggen/gen/rust.py @@ -15,21 +15,6 @@ # built-in keywords. keywords = ["in", "type"] -# Manual overrides for some of the auto-generated types for paths -# Manual overrides for some of the auto-generated types for paths -overrides = { - 'ListPeers.peers[].channels[].state_changes[].old_state': "ChannelState", - 'ListPeers.peers[].channels[].state_changes[].new_state': "ChannelState", - 'ListPeers.peers[].channels[].state_changes[].cause': "ChannelStateChangeCause", - 'ListPeers.peers[].channels[].htlcs[].state': None, - 'ListPeers.peers[].channels[].opener': "ChannelSide", - 'ListPeers.peers[].channels[].closer': "ChannelSide", - 'ListPeers.peers[].channels[].features[]': "string", - 'ListFunds.channels[].state': 'ChannelState', - 'ListTransactions.transactions[].type[]': None, - 'Invoice.exposeprivatechannels': None, -} - # A map of schema type to rust primitive types. typemap = { 'boolean': 'bool', @@ -75,6 +60,8 @@ def normalize_varname(field): def gen_field(field): + if field.omit(): + return ("", "") if isinstance(field, CompositeField): return gen_composite(field) elif isinstance(field, EnumField): @@ -90,7 +77,7 @@ def gen_field(field): def gen_enum(e): defi, decl = "", "" - if e.path in overrides and overrides[e.path] is None: + if e.omit(): return "", "" if e.description != "": @@ -128,11 +115,11 @@ def gen_enum(e): typename = e.typename - if e.path in overrides: + if e.override() is not None: decl = "" # No declaration if we have an override - typename = overrides[e.path] + typename = e.override() - if e.required: + if not e.optional: defi = f" // Path `{e.path}`\n" defi += rename_if_necessary(str(e.name), e.name.normalized()) defi += f" pub {e.name.normalized()}: {typename},\n" @@ -152,7 +139,7 @@ def gen_primitive(p): if p.deprecated: defi += " #[deprecated]\n" defi += rename_if_necessary(org, p.name.name) - if p.required: + if not p.optional: defi += f" pub {p.name}: {typename},\n" else: defi += f" #[serde(skip_serializing_if = \"Option::is_none\")]\n pub {p.name}: Option<{typename}>,\n" @@ -172,9 +159,9 @@ def gen_array(a): logger.debug(f"Generating array field {a.name} -> {name} ({a.path})") _, decl = gen_field(a.itemtype) - if a.path in overrides: + if a.override(): decl = "" # No declaration if we have an override - itemtype = overrides[a.path] + itemtype = a.override() elif isinstance(a.itemtype, PrimitiveField): itemtype = a.itemtype.typename elif isinstance(a.itemtype, CompositeField): @@ -191,7 +178,7 @@ def gen_array(a): if a.deprecated: defi += " #[deprecated]\n" defi += rename_if_necessary(alias, name) - if a.required: + if not a.optional: defi += f" pub {name}: {'Vec<'*a.dims}{itemtype}{'>'*a.dims},\n" else: defi += f" #[serde(skip_serializing_if = \"crate::is_none_or_empty\")]\n pub {name}: Option<{'Vec<'*a.dims}{itemtype}{'>'*a.dims}>,\n" @@ -216,7 +203,7 @@ def gen_composite(c) -> Tuple[str, str]: defi = "" if c.deprecated: defi += " #[deprecated]\n" - if c.required: + if not c.optional: defi += f" pub {c.name}: {c.typename},\n" else: defi += f" #[serde(skip_serializing_if = \"Option::is_none\")]\n pub {c.name}: Option<{c.typename}>,\n" diff --git a/contrib/msggen/msggen/model.py b/contrib/msggen/msggen/model.py index 8492d3831cc6..f1a7813601d4 100644 --- a/contrib/msggen/msggen/model.py +++ b/contrib/msggen/msggen/model.py @@ -19,7 +19,7 @@ def normalized(self): "type": "item_type" }.get(self.name, self.name) - name = name.replace(' ', '_').replace('-', '_').replace('[]', '') + name = name.replace(' ', '_').replace('-', '_').replace('[]', '').replace("/", "_") return name def __str__(self): @@ -27,12 +27,27 @@ def __str__(self): class Field: - def __init__(self, path, description): + def __init__( + self, + path, + description, + added=None, + deprecated=None + ): self.path = path self.description = description - self.deprecated = False + self.added = added + self.deprecated = deprecated self.required = False + # Are we going to omit this field when generating bindings? + # This usually means that the field either doesn't make sense + # to convert or that msggen cannot handle converting this + # field and its children yet. + self.omitted = False + + self.type_override: Optional[str] = None + @property def name(self): return FieldName(self.path.split(".")[-1]) @@ -46,6 +61,37 @@ def __repr__(self): def normalized(self): return self.name.normalized() + def capitalized(self): + return self.name.capitalized() + + def omit(self): + """Returns true if we should not consider this field in our model. + + This can be either because the field is redundant, or because + msggen cannot currently handle it. The field (and it's type if + it's composite) will not be materialized in the generated + bindings and converters. + + It is mainly switched on and off in the OverridePatch which is + the central location where we manage overrides and omissions. + + """ + return self.omitted + + def override(self, default: Optional[str] = None) -> Optional[str]: + """Provide a type that should be used instead of the inferred one. + + This is useful if for shared types that we don't want to + generate multiple times, and for enums that can result in + naming clashes in the grpc model (enum variantss must be + uniquely name in the top-level scope...). + + It is mainly switched on and off in the OverridePatch which is + the central location where we manage overrides and omissions. + + """ + return self.type_override if self.type_override else default + class Service: """Top level class that wraps all the RPC methods. @@ -92,8 +138,22 @@ def __init__(self, name: str, request: Field, response: Field): class CompositeField(Field): - def __init__(self, typename, fields, path, description): - Field.__init__(self, path, description) + def __init__( + self, + typename, + fields, + path, + description, + added, + deprecated + ): + Field.__init__( + self, + path, + description, + added=added, + deprecated=deprecated + ) self.typename = typename self.fields = fields @@ -130,6 +190,8 @@ def from_js(cls, js, path): field = None desc = ftype["description"] if "description" in ftype else "" fpath = f"{path}.{fname}" + added = ftype.get('added', None) + deprecated = ftype.get('deprecated', None) if fpath in overrides: field = copy(overrides[fpath]) @@ -159,7 +221,7 @@ def from_js(cls, js, path): field = ArrayField.from_js(fpath, ftype) elif ftype["type"] in PrimitiveField.types: - field = PrimitiveField(ftype["type"], fpath, desc) + field = PrimitiveField(ftype["type"], fpath, desc, added=added, deprecated=deprecated) else: logger.warning( @@ -173,7 +235,7 @@ def from_js(cls, js, path): logger.debug(field) return CompositeField( - typename, fields, path, js["description"] if "description" in js else "" + typename, fields, path, js["description"] if "description" in js else "", added=js.get('added', None), deprecated=js.get('deprecated', None) ) def __str__(self): @@ -191,12 +253,12 @@ def __str__(self): return self.variant def normalized(self): - return self.variant.replace(' ', '_').replace('-', '_').upper() + return self.variant.replace(' ', '_').replace('-', '_').replace("/", "_").upper() class EnumField(Field): - def __init__(self, typename, values, path, description): - Field.__init__(self, path, description) + def __init__(self, typename, values, path, description, added, deprecated): + Field.__init__(self, path, description, added=added, deprecated=deprecated) self.typename = typename self.values = values self.variants = [EnumVariant(v) for v in self.values] @@ -210,6 +272,8 @@ def from_js(cls, js, path): values=filter(lambda i: i is not None, js["enum"]), path=path, description=js["description"] if "description" in js else "", + added=js.get('added', None), + deprecated=js.get('deprecated', None), ) def __str__(self): @@ -224,8 +288,8 @@ class UnionField(Field): and a `oneof` in protobuf. """ - def __init__(self, path, description, variants): - Field.__init__(self, path, description) + def __init__(self, path, description, variants, added, deprecated): + Field.__init__(self, path, description, added=added, deprecated=deprecated) self.variants = variants self.typename = path2type(path) @@ -281,8 +345,8 @@ class PrimitiveField(Field): "hash", ] - def __init__(self, typename, path, description): - Field.__init__(self, path, description) + def __init__(self, typename, path, description, added, deprecated): + Field.__init__(self, path, description, added=added, deprecated=deprecated) self.typename = typename def __str__(self): @@ -290,8 +354,8 @@ def __str__(self): class ArrayField(Field): - def __init__(self, itemtype, dims, path, description): - Field.__init__(self, path, description) + def __init__(self, itemtype, dims, path, description, added, deprecated): + Field.__init__(self, path, description, added=added, deprecated=deprecated) self.itemtype = itemtype self.dims = dims self.path = path @@ -321,11 +385,13 @@ def from_js(cls, path, js): child_js["type"], path, child_js.get("description", ""), + added=child_js.get("added", None), + deprecated=child_js.get("deprecated", None), ) logger.debug(f"Array path={path} dims={dims}, type={itemtype}") return ArrayField( - itemtype, dims=dims, path=path, description=js.get("description", "") + itemtype, dims=dims, path=path, description=js.get("description", ""), added=js.get('added', None), deprecated=js.get('deprecated', None) ) @@ -339,14 +405,16 @@ def __str__(self): return f"Command[name={self.name}, fields=[{fieldnames}]]" -InvoiceLabelField = PrimitiveField("string", None, None) -DatastoreKeyField = ArrayField(itemtype=PrimitiveField("string", None, None), dims=1, path=None, description=None) -InvoiceExposeprivatechannelsField = PrimitiveField("boolean", None, None) -PayExclude = ArrayField(itemtype=PrimitiveField("string", None, None), dims=1, path=None, description=None) +InvoiceLabelField = PrimitiveField("string", None, None, added=None, deprecated=None) +DatastoreKeyField = ArrayField(itemtype=PrimitiveField("string", None, None, added=None, deprecated=None), dims=1, path=None, description=None, added=None, deprecated=None) +InvoiceExposeprivatechannelsField = PrimitiveField("boolean", None, None, added=None, deprecated=None) +PayExclude = ArrayField(itemtype=PrimitiveField("string", None, None, added=None, deprecated=None), dims=1, path=None, description=None, added=None, deprecated=None) RoutehintListField = PrimitiveField( "RoutehintList", None, - None + None, + added=None, + deprecated=None ) # TlvStreams are special, they don't have preset dict-keys, rather @@ -355,7 +423,9 @@ def __str__(self): TlvStreamField = PrimitiveField( "TlvStream", None, - None + None, + added=None, + deprecated=None ) # Override fields with manually managed types, fieldpath -> field mapping diff --git a/contrib/msggen/msggen/patch.py b/contrib/msggen/msggen/patch.py new file mode 100644 index 000000000000..deab2eb2e14b --- /dev/null +++ b/contrib/msggen/msggen/patch.py @@ -0,0 +1,185 @@ +from abc import ABC +from msggen import model + + +class Patch(ABC): + """A patch that can be applied to an in-memory model + + This effectively post-processes the in-memory model to ensure the + invariants are satisfied. + + """ + + def visit(self, field: model.Field) -> None: + """Gets called for each node in the model. + """ + pass + + def apply(self, service: model.Service) -> None: + """Apply this patch to the model by calling `visit` in + pre-order on each node in the schema tree. + + """ + def recurse(f: model.Field): + # First recurse if we have further type definitions + if isinstance(f, model.ArrayField): + self.visit(f.itemtype) + recurse(f.itemtype) + elif isinstance(f, model.CompositeField): + for c in f.fields: + self.visit(c) + recurse(c) + # Now visit ourselves + self.visit(f) + for m in service.methods: + recurse(m.request) + recurse(m.response) + + +class VersionAnnotationPatch(Patch): + """Annotates fields with the version they were added or deprecated if not specified. + + A patch is used so we don't have to annotate all fields that + existed prior to the introduction of the `added` and `deprecated` + fields, and uses the `.msggen.json` file to remember which fields + are known, and which ones are new. For existing fields we just + want a default value, while for new fields we want to error if the + author did not annotate them manually. + + """ + + def __init__(self, meta) -> None: + """Create a patch that can annotate `added` and `deprecated` + """ + self.meta = meta + + def visit(self, f: model.Field) -> None: + m = self.meta['model-field-versions'].get(f.path, {}) + + # The following lines are used to backfill fields that predate + # the introduction, so they need to use a default version to + # mark. These are stored in `.msggen.json` only, and we use + # the default value only on the first run. Code left commented + # to show how it was done + # if f.added is None and 'added' not in m: + # m['added'] = 'pre-v0.10.1' + + added = m.get('added', None) + deprecated = m.get('deprecated', None) + + assert added or f.added, f"Field {f.path} does not have an `added` annotation" + + # We do not allow the added and deprecated flags to be + # modified after the fact. + if f.added and added and f.added != m['added']: + raise ValueError(f"Field {f.path} changed `added` annotation: {f.added} != {m['added']}") + + if f.deprecated and deprecated and f.deprecated != deprecated: + raise ValueError(f"Field {f.path} changed `deprecated` annotation: {f.deprecated} != {m['deprecated']}") + + if f.added is None: + f.added = added + if f.deprecated is None: + f.deprecated = deprecated + + # Backfill the metadata using the annotation + self.meta['model-field-versions'][f.path] = { + 'added': f.added, + 'deprecated': f.deprecated, + } + + +class OptionalPatch(Patch): + """Annotates fields with `.optional` + + Optional fields are either non-required fields, or fields that + were not required in prior versions. This latter case covers the + deprecation and addition for schema evolution + """ + + versions = [ + 'pre-v0.10.1', # Dummy versions collecting all fields that predate the versioning. + 'v0.10.1', + 'v0.10.2', + 'v0.11.0', + 'v0.12.0', + 'v0.12.1', + 'v22.11', + 'v23.02', + 'v23.05', + ] + # Oldest supported versions. Bump this if you no longer want to + # support older versions, and you want to make required fields + # more stringent. + supported = 'v0.10.1' + + def visit(self, f: model.Field) -> None: + if f.added not in self.versions: + raise ValueError(f"Version {f.added} in unknown, please add it to {__file__}") + if f.deprecated and f.deprecated not in self.versions: + raise ValueError(f"Version {f.deprecated} in unknown, please add it to {__file__}") + + idx = ( + self.versions.index(self.supported), + len(self.versions) - 1, + ) + # Default to false, and then overwrite it if required. + f.optional = False + if not f.required: + f.optional = True + + if self.versions.index(f.added) > idx[0]: + f.optional = True + + if f.deprecated and self.versions.index(f.deprecated) < idx[1]: + f.optional = True + + +class OverridePatch(Patch): + """Allows omitting some fields and overriding the type of fields based on configuration. + + """ + omit = [ + 'Decode.invoice_paths[]', + 'Decode.invoice_paths[].payinfo', + 'Decode.offer_paths[].path[]', + 'Decode.offer_recurrence', + 'Decode.routes[][]', + 'Decode.unknown_invoice_request_tlvs[]', + 'Decode.unknown_invoice_tlvs[]', + 'Decode.unknown_offer_tlvs[]', + 'DecodePay.routes[][]', + 'DecodeRoutes.routes', + 'Invoice.exposeprivatechannels', + 'ListClosedChannels.closedchannels[].channel_type', + 'ListPeerChannels.channels[].channel_type', + 'ListPeerChannels.channels[].features[]', + 'ListPeerChannels.channels[].state_changes[]', + 'ListPeers.peers[].channels[].state_changes[]', + 'ListTransactions.transactions[].type[]', + ] + + # Handcoded types to use instead of generating the types from the + # schema. Useful for repeated types, and types that have + # redundancies. + overrides = { + 'ListClosedChannels.closedchannels[].closer': "ChannelSide", + 'ListClosedChannels.closedchannels[].opener': "ChannelSide", + 'ListFunds.channels[].state': 'ChannelState', + 'ListPeerChannels.channels[].closer': "ChannelSide", + 'ListPeerChannels.channels[].opener': "ChannelSide", + 'ListPeers.peers[].channels[].closer': "ChannelSide", + 'ListPeers.peers[].channels[].features[]': "string", + 'ListPeers.peers[].channels[].opener': "ChannelSide", + 'ListPeers.peers[].channels[].state_changes[].cause': "ChannelStateChangeCause", + 'ListPeers.peers[].channels[].state_changes[].old_state': "ChannelState", + 'ListPeers.peers[].channels[].state_changes[].old_state': "ChannelState", + 'ListPeers.peers[].channels[].htlcs[].state': "HtlcState", + 'ListPeerChannels.channels[].htlcs[].state': "HtlcState", + } + + def visit(self, f: model.Field) -> None: + """For now just skips the fields we can't convert. + """ + f.omitted = f.path in self.omit + f.type_override = self.overrides.get(f.path, None) diff --git a/contrib/msggen/msggen/utils/utils.py b/contrib/msggen/msggen/utils/utils.py index 4ef75d26cc2b..873168b7192a 100644 --- a/contrib/msggen/msggen/utils/utils.py +++ b/contrib/msggen/msggen/utils/utils.py @@ -64,8 +64,10 @@ def load_jsonrpc_service(schema_dir: str): "TxDiscard", "TxPrepare", "TxSend", - # "decodepay", - # "decode", + "ListPeerChannels", + "ListClosedChannels", + "DecodePay", + "Decode", # "delpay", # "disableoffer", "Disconnect", @@ -93,10 +95,11 @@ def load_jsonrpc_service(schema_dir: str): "Ping", # "plugin", # "reserveinputs", - # "sendcustommsg", + "SendCustomMsg", # "sendinvoice", # "sendonionmessage", "SetChannel", + "SignInvoice", "SignMessage", # "unreserveinputs", # "waitblockheight", @@ -105,6 +108,8 @@ def load_jsonrpc_service(schema_dir: str): "Stop", # "notifications", # No point in mapping this # "help", + "PreApproveKeysend", + "PreApproveInvoice", ] methods = [load_jsonrpc_method(name, schema_dir=schema_dir) for name in method_names] service = Service(name="Node", methods=methods) diff --git a/contrib/pyln-client/README.md b/contrib/pyln-client/README.md index 38fba5aa05cb..2e781bddbbcd 100644 --- a/contrib/pyln-client/README.md +++ b/contrib/pyln-client/README.md @@ -96,7 +96,7 @@ def init(options, configuration, plugin): @plugin.subscribe("connect") -def on_connect(plugin, id, address): +def on_connect(plugin, id, address, **kwargs): plugin.log("Received connect event for peer {}".format(id)) diff --git a/contrib/pyln-client/pyln/client/__init__.py b/contrib/pyln-client/pyln/client/__init__.py index f25ca52e88cd..ed736ba84bc2 100644 --- a/contrib/pyln-client/pyln/client/__init__.py +++ b/contrib/pyln-client/pyln/client/__init__.py @@ -1,8 +1,9 @@ from .lightning import LightningRpc, RpcError, Millisatoshi from .plugin import Plugin, monkey_patch, RpcException -from .gossmap import Gossmap, GossmapNode, GossmapChannel, GossmapNodeId +from .gossmap import Gossmap, GossmapNode, GossmapChannel, GossmapHalfchannel, GossmapNodeId, LnFeatureBits +from .gossmapstats import GossmapStats -__version__ = "22.11rc1" +__version__ = "23.05" __all__ = [ "LightningRpc", @@ -15,5 +16,8 @@ "Gossmap", "GossmapNode", "GossmapChannel", + "GossmapHalfchannel", "GossmapNodeId", + "LnFeatureBits", + "GossmapStats", ] diff --git a/contrib/pyln-client/pyln/client/clnutils.py b/contrib/pyln-client/pyln/client/clnutils.py new file mode 100644 index 000000000000..68161cadefab --- /dev/null +++ b/contrib/pyln-client/pyln/client/clnutils.py @@ -0,0 +1,23 @@ +import re + + +def cln_parse_rpcversion(string): + """ + Parse cln version string to determine RPC version. + + cln switched from 'semver' alike `major.minor.sub[rcX][-mod]` + to ubuntu style with version 22.11 `yy.mm[.patch][-mod]` + make sure we can read all of them for (the next 80 years). + """ + rpcversion = string + if rpcversion.startswith('v'): # strip leading 'v' + rpcversion = rpcversion[1:] + if rpcversion.find('-') != -1: # strip mods + rpcversion = rpcversion[:rpcversion.find('-')] + if re.search('.*(rc[\\d]*)$', rpcversion): # strip release candidates + rpcversion = rpcversion[:rpcversion.find('rc')] + if rpcversion.count('.') == 1: # imply patch version 0 if not given + rpcversion = rpcversion + '.0' + + # split and convert numeric string parts to actual integers + return list(map(int, rpcversion.split('.'))) diff --git a/contrib/pyln-client/pyln/client/gossmap.py b/contrib/pyln-client/pyln/client/gossmap.py index 4d72209e8e0c..ad6e681b861d 100755 --- a/contrib/pyln-client/pyln/client/gossmap.py +++ b/contrib/pyln-client/pyln/client/gossmap.py @@ -3,18 +3,21 @@ from pyln.spec.bolt7 import (channel_announcement, channel_update, node_announcement) from pyln.proto import ShortChannelId, PublicKey -from typing import Any, Dict, List, Optional, Union, cast +from typing import Any, Dict, List, Set, Optional, Union import io +import base64 +import socket import struct +import time # These duplicate constants in lightning/common/gossip_store.h GOSSIP_STORE_MAJOR_VERSION = (0 << 5) GOSSIP_STORE_MAJOR_VERSION_MASK = 0xE0 -GOSSIP_STORE_LEN_DELETED_BIT = 0x80000000 -GOSSIP_STORE_LEN_PUSH_BIT = 0x40000000 -GOSSIP_STORE_LEN_RATELIMIT_BIT = 0x20000000 -GOSSIP_STORE_LEN_MASK = (0x0000FFFF) +GOSSIP_STORE_LEN_DELETED_BIT = 0x8000 +GOSSIP_STORE_LEN_PUSH_BIT = 0x4000 +GOSSIP_STORE_LEN_RATELIMIT_BIT = 0x2000 +GOSSIP_STORE_ZOMBIE_BIT = 0x1000 # These duplicate constants in lightning/gossipd/gossip_store_wiregen.h WIRE_GOSSIP_STORE_PRIVATE_CHANNEL = 4104 @@ -24,34 +27,111 @@ WIRE_GOSSIP_STORE_CHANNEL_AMOUNT = 4101 -class GossipStoreHeader(object): - def __init__(self, buf: bytes): - length, self.crc, self.timestamp = struct.unpack('>III', buf) - self.deleted = (length & GOSSIP_STORE_LEN_DELETED_BIT) != 0 - self.length = (length & GOSSIP_STORE_LEN_MASK) +class LnFeatureBits(object): + """ feature flags taken from bolts.git/09-features.md + + Flags are numbered from the least-significant bit, at bit 0 (i.e. 0x1, + an _even_ bit). They are generally assigned in pairs so that features + can be introduced as optional (_odd_ bits) and later upgraded to be compulsory + (_even_ bits), which will be refused by outdated nodes: + + CONTEXT: + * `I`: presented in the `init` message. + * `N`: presented in the `node_announcement` messages + * `C`: presented in the `channel_announcement` message. + * `C-`: presented in the `channel_announcement` message, but always odd (optional). + * `C+`: presented in the `channel_announcement` message, but always even (required). + * `9`: presented in [BOLT 11](11-payment-encoding.md) invoices. + + FEATURE_NAME # CONTEXT # PRs + ----------------------------------------------------------------- """ + OPTION_DATA_LOSS_PROTECT = 0 # IN + INITIAL_ROUTING_SYNC = 2 # I + OPTION_UPFRONT_SHUTDOWN_SCRIPT = 4 # IN + GOSSIP_QUERIES = 6 # IN + VAR_ONION_OPTIN = 8 # IN9 + GOSSIP_QUERIES_EX = 10 # IN + OPTION_STATIC_REMOTEKEY = 12 # IN + PAYMENT_SECRET = 14 # IN9 + BASIC_MPP = 16 # IN9 + OPTION_SUPPORT_LARGE_CHANNEL = 18 # IN + OPTION_ANCHOR_OUTPUTS = 20 # IN + OPTION_ANCHORS_ZERO_FEE_HTLC_TX = 22 # IN + OPTION_SHUTDOWN_ANYSEGWIT = 26 # IN + OPTION_CHANNEL_TYPE = 44 # IN + OPTION_SCID_ALIAS = 46 # IN + OPTION_PAYMENT_METADATA = 48 # 9 + OPTION_ZEROCONF = 50 # IN + + OPTION_PROPOSED_ROUTE_BLINDING = 24 # IN9 #765 #798 + OPTION_PROPOSED_DUAL_FUND = 28 # IN #851 #1009 + OPTION_PROPOSED_ALTERNATIVE_FEERATES = 32 # IN #1036 + OPTION_PROPOSED_QUIESCE = 34 # IN #869 #868 + OPTION_PROPOSED_ONION_MESSAGES = 38 # IN #759 + OPTION_PROPOSED_WANT_PEER_BACKUP_STORAGE = 40 # IN #881 + OPTION_PROPOSED_PROVIDE_PEER_BACKUP = 42 # IN #881 + OPTION_PROPOSED_TRAMPOLINE_ROUTING = 56 # IN9 #836 + OPTION_PROPOSED_UPFRONT_FEE = 56 # IN9 #1052 + OPTION_PROPOSED_CLOSING_REJECTED = 60 # IN #1016 + OPTION_PROPOSED_SPLICE = 62 # IN #863 + + +def _parse_features(featurebytes): + # featurebytes e.g.: [136, 160, 0, 8, 2, 105, 162] + result = 0 + for byte in featurebytes: + result <<= 8 + result |= byte + return result + + +class GossipStoreMsgHeader(object): + def __init__(self, buf: bytes, off: int): + self.flags, self.length, self.crc, self.timestamp = struct.unpack('>HHII', buf) + self.off = off + self.deleted = (self.flags & GOSSIP_STORE_LEN_DELETED_BIT) != 0 + self.ratelimit = (self.flags & GOSSIP_STORE_LEN_RATELIMIT_BIT) != 0 + self.zombie = (self.flags & GOSSIP_STORE_ZOMBIE_BIT) != 0 class GossmapHalfchannel(object): """One direction of a GossmapChannel.""" def __init__(self, channel: 'GossmapChannel', direction: int, - timestamp: int, cltv_expiry_delta: int, - htlc_minimum_msat: int, htlc_maximum_msat: int, - fee_base_msat: int, fee_proportional_millionths: int): - + fields: Dict[str, Any], hdr: GossipStoreMsgHeader): + assert direction in [0, 1], "direction can only be 0 or 1" self.channel = channel self.direction = direction self.source = channel.node1 if direction == 0 else channel.node2 self.destination = channel.node2 if direction == 0 else channel.node1 - - self.timestamp: int = timestamp - self.cltv_expiry_delta: int = cltv_expiry_delta - self.htlc_minimum_msat: int = htlc_minimum_msat - self.htlc_maximum_msat: Optional[int] = htlc_maximum_msat - self.fee_base_msat: int = fee_base_msat - self.fee_proportional_millionths: int = fee_proportional_millionths + self.fields: Dict[str, Any] = fields + self.hdr: GossipStoreMsgHeader = hdr + + self.timestamp: int = fields['timestamp'] + self.cltv_expiry_delta: int = fields['cltv_expiry_delta'] + self.htlc_minimum_msat: int = fields['htlc_minimum_msat'] + self.htlc_maximum_msat: Optional[int] = fields.get('htlc_maximum_msat', None) + self.fee_base_msat: int = fields['fee_base_msat'] + self.fee_proportional_millionths: int = fields['fee_proportional_millionths'] + self.disabled = fields['channel_flags'] & 2 > 0 + + # Cache the _scidd and hash to have faster operation later + # Unfortunately the @final decorator only comes for python3.8 + self._scidd = f"{self.channel.scid}/{self.direction}" + self._numscidd = direction << 63 | self.channel.scid.to_int() def __repr__(self): - return "GossmapHalfchannel[{}x{}]".format(str(self.channel.scid), self.direction) + return f"GossmapHalfchannel[{self._scidd}]" + + def __eq__(self, other): + if not isinstance(other, GossmapHalfchannel): + return False + return self._numscidd == other._numscidd + + def __str__(self): + return self._scidd + + def __hash__(self): + return self._numscidd class GossmapNodeId(object): @@ -62,6 +142,9 @@ def __init__(self, buf: Union[bytes, str]): raise ValueError("{} is not a valid node_id".format(buf.hex())) self.nodeid = buf + self._hash = self.nodeid.__hash__() + self._str = self.nodeid.hex() + def to_pubkey(self) -> PublicKey: return PublicKey(self.nodeid) @@ -76,11 +159,14 @@ def __lt__(self, other): return self.nodeid.__lt__(other.nodeid) # yes, that works def __hash__(self): - return self.nodeid.__hash__() + return self._hash def __repr__(self): return "GossmapNodeId[{}]".format(self.nodeid.hex()) + def __str__(self): + return self._str + @classmethod def from_str(cls, s: str): if s.startswith('0x'): @@ -91,66 +177,92 @@ def from_str(cls, s: str): class GossmapChannel(object): - """A channel: fields of channel_announcement are in .fields, optional updates are in .updates_fields, which can be None if there has been no channel update.""" + """A channel: fields of channel_announcement are in .fields, + optional updates are in .half_channels[0/1].fields """ def __init__(self, fields: Dict[str, Any], - announce_offset: int, - scid, + scid: Union[ShortChannelId, str], node1: 'GossmapNode', node2: 'GossmapNode', - is_private: bool): - self.fields = fields - self.announce_offset = announce_offset + is_private: bool, + hdr: GossipStoreMsgHeader): + self.fields: Dict[str, Any] = fields + self.hdr: GossipStoreMsgHeader = hdr + self.is_private = is_private - self.scid = scid + self.scid = ShortChannelId.from_str(scid) if isinstance(scid, str) else scid self.node1 = node1 self.node2 = node2 - self.updates_fields: List[Optional[Dict[str, Any]]] = [None, None] - self.updates_offset: List[Optional[int]] = [None, None] self.satoshis = None self.half_channels: List[Optional[GossmapHalfchannel]] = [None, None] + self.features = _parse_features(fields['features']) def _update_channel(self, direction: int, fields: Dict[str, Any], - off: int): - self.updates_fields[direction] = fields - self.updates_offset[direction] = off - - half = GossmapHalfchannel(self, direction, - fields['timestamp'], - fields['cltv_expiry_delta'], - fields['htlc_minimum_msat'], - fields.get('htlc_maximum_msat', None), - fields['fee_base_msat'], - fields['fee_proportional_millionths']) + hdr: GossipStoreMsgHeader): + + half = GossmapHalfchannel(self, direction, fields, hdr) self.half_channels[direction] = half def get_direction(self, direction: int): """ returns the GossmapHalfchannel if known by channel_update """ - if not 0 <= direction <= 1: - raise ValueError("direction can only be 0 or 1") + assert direction in [0, 1], "direction can only be 0 or 1" return self.half_channels[direction] def __repr__(self): return "GossmapChannel[{}]".format(str(self.scid)) + def __str__(self): + return str(self.scid) -class GossmapNode(object): - """A node: fields of node_announcement are in .announce_fields, which can be None of there has been no node announcement. + def __eq__(self, other): + if not isinstance(other, GossmapChannel): + return False + return self.scid.__eq__(other.scid) + + def __hash__(self): + return self.scid.__hash__() + + def has_feature(self, bit): + return 3 << bit & self.features != 0 + + def has_feature_compulsory(self, bit): + return 1 << bit & self.features != 0 + + def has_feature_optional(self, bit): + return 2 << bit & self.features != 0 + + def has_features(self, *bits): + for bit in bits: + if not self.has_feature(bit): + return False + return True -.channels is a list of the GossmapChannels attached to this node. -""" + def is_tor_only(c): + """ Checks if a channel has TOR only nodes on both ends """ + return c.node1.is_tor_only() and c.node2.is_tor_only() + + +class GossmapNode(object): + """A node: fields of node_announcement are in .fields, + which can be None if there has been no node announcement. + .channels is a list of the GossmapChannels attached to this node.""" def __init__(self, node_id: Union[GossmapNodeId, bytes, str]): if isinstance(node_id, bytes) or isinstance(node_id, str): node_id = GossmapNodeId(node_id) - self.announce_fields: Optional[Dict[str, Any]] = None - self.announce_offset: Optional[int] = None + self.fields: Optional[Dict[str, Any]] = None + self.hdr: GossipStoreMsgHeader = None self.channels: List[GossmapChannel] = [] self.node_id = node_id + self.announced = False + + self._hash = self.node_id.__hash__() def __repr__(self): - return "GossmapNode[{}]".format(self.node_id.nodeid.hex()) + if hasattr(self, 'alias'): + return f"GossmapNode[{self.node_id.nodeid.hex()}, \"{self.alias}\"]" + return f"GossmapNode[{self.node_id.nodeid.hex()}]" def __eq__(self, other): if not isinstance(other, GossmapNode): @@ -162,6 +274,120 @@ def __lt__(self, other): raise ValueError(f"Cannot compare GossmapNode with {type(other)}") return self.node_id.__lt__(other.node_id) + def __hash__(self): + return self._hash + + def __str__(self): + return str(self.node_id) + + def has_feature(self, bit): + if not self.announced: + return None + return 3 << bit & self.features != 0 + + def has_feature_compulsory(self, bit): + if not self.announced: + return None + return 1 << bit & self.features != 0 + + def has_feature_optional(self, bit): + if not self.announced: + return None + return 2 << bit & self.features != 0 + + def has_features(self, *bits): + if not self.announced: + return None + for bit in bits: + if not self.has_feature(bit): + return False + return True + + def _parse_addresses(self, data: bytes): + """ parse address descriptors defined in bolts 07-routing-gossip.md """ + result = [] + try: + stream = io.BytesIO(data) + while stream.tell() < len(data): + _type = int.from_bytes(stream.read(1), byteorder='big') + if _type == 1: # IPv4 length 6 + ip = socket.inet_ntoa(stream.read(4)) + port = int.from_bytes(stream.read(2), byteorder='big') + result.append(f"{ip}:{port}") + elif _type == 2: # IPv6 length 18 + ip = socket.inet_ntop(socket.AF_INET6, stream.read(16)) + port = int.from_bytes(stream.read(2), byteorder='big') + result.append(f"[{ip}]:{port}") + elif _type == 3: # TORv2 length 12 (deprecated) + stream.read(12) + elif _type == 4: # TORv3 length 37 + addr = base64.b32encode(stream.read(35)).decode('ascii').lower() + port = int.from_bytes(stream.read(2), byteorder='big') + result.append(f"{addr}.onion:{port}") + elif _type == 5: # DNS up to 258 + hostname_len = int.from_bytes(stream.read(1), byteorder='big') + hostname = stream.read(hostname_len).decode('ascii') + port = int.from_bytes(stream.read(2), byteorder='big') + result.append(f"{hostname}:{port}") + else: # Stop parsing at the first unknown type + break + # we simply pass exceptions and return what we were able to read so far + except Exception: + pass + self.addresses = result + + def get_address_type(self, idx: int): + """ I know this can be more sophisticated, but works """ + if not self.announced or len(self.addresses) <= idx: + return None + addrstr = self.addresses[idx] + if ".onion:" in addrstr: + return 'tor' + if addrstr[0].isdigit(): + return 'ipv4' + if addrstr.startswith("["): + return 'ipv6' + return 'dns' + + def has_clearnet(self): + """ Checks if a node has one or more clearnet addresses """ + if not self.announced or len(self.addresses) == 0: + return False + for i in range(len(self.addresses)): + if self.get_address_type(i) != 'tor': + return True + return False + + def has_tor(self): + """ Checks if a node has one or more TOR addresses """ + if not self.announced or len(self.addresses) == 0: + return False + for i in range(len(self.addresses)): + if self.get_address_type(i) == 'tor': + return True + return False + + def is_tor_only(self): + """ Checks if a node has only TOR and no addresses announced """ + if not self.announced or len(self.addresses) == 0: + return False + for i in range(len(self.addresses)): + if self.get_address_type(i) != 'tor': + return False + return True + + def is_tor_strict(self): + """ Checks if a node is TOR only + and is not publicly connected to any non-TOR nodes """ + if not self.is_tor_only(): + return False + for c in self.channels: + other = c.node1 if self != c.node1 else c.node2 + if other.has_tor(): + continue + return False + return True + class Gossmap(object): """Class to represent the gossip map of the network""" @@ -169,25 +395,25 @@ def __init__(self, store_filename: str = "gossip_store"): self.store_filename = store_filename self.store_file = open(store_filename, "rb") self.store_buf = bytes() + self.bytes_read = 0 self.nodes: Dict[GossmapNodeId, GossmapNode] = {} self.channels: Dict[ShortChannelId, GossmapChannel] = {} self._last_scid: Optional[str] = None version = self.store_file.read(1)[0] if (version & GOSSIP_STORE_MAJOR_VERSION_MASK) != GOSSIP_STORE_MAJOR_VERSION: raise ValueError("Invalid gossip store version {}".format(version)) - self.bytes_read = 1 + self.processing_time = 0 + self.orphan_channel_updates = set() self.refresh() def _new_channel(self, fields: Dict[str, Any], - announce_offset: int, scid: ShortChannelId, node1: GossmapNode, node2: GossmapNode, - is_private: bool): - c = GossmapChannel(fields, announce_offset, - scid, node1, node2, - is_private) + is_private: bool, + hdr: GossipStoreMsgHeader): + c = GossmapChannel(fields, scid, node1, node2, is_private, hdr) self._last_scid = scid self.channels[scid] = c node1.channels.append(c) @@ -204,7 +430,7 @@ def _del_channel(self, scid: ShortChannelId): if len(c.node2.channels) == 0: del self.nodes[c.node2.node_id] - def _add_channel(self, rec: bytes, off: int, is_private: bool): + def _add_channel(self, rec: bytes, is_private: bool, hdr: GossipStoreMsgHeader): fields = channel_announcement.read(io.BytesIO(rec[2:]), {}) # Add nodes one the fly node1_id = GossmapNodeId(fields['node_id_1']) @@ -213,43 +439,153 @@ def _add_channel(self, rec: bytes, off: int, is_private: bool): self.nodes[node1_id] = GossmapNode(node1_id) if node2_id not in self.nodes: self.nodes[node2_id] = GossmapNode(node2_id) - self._new_channel(fields, off, + self._new_channel(fields, ShortChannelId.from_int(fields['short_channel_id']), self.get_node(node1_id), self.get_node(node2_id), - is_private) + is_private, hdr) def _set_channel_amount(self, rec: bytes): """ Sets channel capacity of last added channel """ sats, = struct.unpack(">Q", rec[2:]) self.channels[self._last_scid].satoshis = sats - def get_channel(self, short_channel_id: ShortChannelId): + def get_channel(self, short_channel_id: Union[ShortChannelId, str]): """ Resolves a channel by its short channel id """ if isinstance(short_channel_id, str): short_channel_id = ShortChannelId.from_str(short_channel_id) return self.channels.get(short_channel_id) + def get_halfchannel(self, + short_channel_id: Union[ShortChannelId, str], + direction: int): + """ Returns a GossmapHalfchannel identified by a scid and direction. """ + assert short_channel_id is not None + if isinstance(short_channel_id, str): + short_channel_id = ShortChannelId.from_str(short_channel_id) + assert direction in [0, 1], "direction can only be 0 or 1" + channel = self.get_channel(short_channel_id) + return channel.half_channels[direction] + + def get_neighbors_hc(self, + source: Union[GossmapNodeId, str, None] = None, + destination: Union[GossmapNodeId, str, None] = None, + depth: int = 0, + excludes: Union[Set[Any], List[Any]] = set()): + """ Returns a set[GossmapHalfchannel]` from `source` or towards + `destination` node ID. Using the optional `depth` greater than `0` + will result in a second, third, ... order list of connected + channels towards or from that node. + Note: only one of `source` or `destination` can be given. """ + assert (source is None) ^ (destination is None), "Only one of source or destination must be given" + assert depth >= 0, "Depth cannot be smaller than 0" + node = self.get_node(source if source else destination) + assert node is not None, "source or destination unknown" + if isinstance(excludes, List): + excludes = set(excludes) + + # first get set of reachable nodes ... + reachable = self.get_neighbors(source, destination, depth, excludes) + # and iterate and check any each source/dest channel from here + result = set() + for node in reachable: + for channel in node.channels: + if channel in excludes: + continue + other = channel.node1 if node != channel.node1 else channel.node2 + if other in reachable or other in excludes: + continue + direction = 0 + if source is not None and node > other: + direction = 1 + if destination is not None and node < other: + direction = 1 + hc = channel.half_channels[direction] + # skip excluded or non existent halfchannels + if hc is None or hc in excludes: + continue + result.add(hc) + return result + def get_node(self, node_id: Union[GossmapNodeId, str]): """ Resolves a node by its public key node_id """ if isinstance(node_id, str): node_id = GossmapNodeId.from_str(node_id) - return self.nodes.get(cast(GossmapNodeId, node_id)) + return self.nodes.get(node_id) + + def get_neighbors(self, + source: Union[GossmapNodeId, str, None] = None, + destination: Union[GossmapNodeId, str, None] = None, + depth: int = 0, + excludes: Union[Set[Any], List[Any]] = set()): + """ Returns a set of nodes within a given depth from a source node """ + assert (source is None) ^ (destination is None), "Only one of source or destination must be given" + assert depth >= 0, "Depth cannot be smaller than 0" + node = self.get_node(source if source else destination) + assert node is not None, "source or destination unknown" + if isinstance(excludes, List): + excludes = set(excludes) + + result = set() + result.add(node) + inner = set() + inner.add(node) + while depth > 0: + shell = set() + for node in inner: + for channel in node.channels: + if channel in excludes: # skip excluded channels + continue + other = channel.node1 if channel.node1 != node else channel.node2 + direction = 0 + if source is not None and node > other: + direction = 1 + if destination is not None and node < other: + direction = 1 + if channel.half_channels[direction] is None: + continue # one way channel in the wrong direction + halfchannel = channel.half_channels[direction] + if halfchannel in excludes: # skip excluded halfchannels + continue + # skip excluded or already seen nodes + if other in excludes or other in inner or other in result: + continue + shell.add(other) + if len(shell) == 0: + break + depth -= 1 + result.update(shell) + inner = shell + return result - def _update_channel(self, rec: bytes, off: int): + def _update_channel(self, rec: bytes, hdr: GossipStoreMsgHeader): fields = channel_update.read(io.BytesIO(rec[2:]), {}) direction = fields['channel_flags'] & 1 - c = self.channels[ShortChannelId.from_int(fields['short_channel_id'])] - c._update_channel(direction, fields, off) + scid = ShortChannelId.from_int(fields['short_channel_id']) + if scid in self.channels: + c = self.channels[scid] + c._update_channel(direction, fields, hdr) + else: + self.orphan_channel_updates.add(scid) - def _add_node_announcement(self, rec: bytes, off: int): + def _add_node_announcement(self, rec: bytes, hdr: GossipStoreMsgHeader): fields = node_announcement.read(io.BytesIO(rec[2:]), {}) node_id = GossmapNodeId(fields['node_id']) - self.nodes[node_id].announce_fields = fields - self.nodes[node_id].announce_offset = off + if node_id not in self.nodes: + self.nodes[node_id] = GossmapNode(node_id) + node = self.nodes[node_id] + node.fields = fields + node.hdr = hdr + + # read metadata + node.features = _parse_features(fields['features']) + node.timestamp = fields['timestamp'] + node.alias = bytes(fields['alias']).decode('utf-8') + node.rgb = fields['rgb_color'] + node._parse_addresses(bytes(fields['addresses'])) + node.announced = True def reopen_store(self): - """FIXME: Implement!""" - assert False + assert False, "FIXME: Implement!" def _remove_channel_by_deletemsg(self, rec: bytes): scidint, = struct.unpack(">Q", rec[2:]) @@ -261,53 +597,54 @@ def _remove_channel_by_deletemsg(self, rec: bytes): def _pull_bytes(self, length: int) -> bool: """Pull bytes from file into our internal buffer""" if len(self.store_buf) < length: - self.store_buf += self.store_file.read(length - - len(self.store_buf)) + self.store_buf += self.store_file.read(length - len(self.store_buf)) + self.bytes_read += len(self.store_buf) return len(self.store_buf) >= length def _read_record(self) -> Optional[bytes]: """If a whole record is not in the file, returns None. If deleted, returns empty.""" + off = self.bytes_read + 1 if not self._pull_bytes(12): - return None - hdr = GossipStoreHeader(self.store_buf[:12]) + return None, None + hdr = GossipStoreMsgHeader(self.store_buf[:12], off) if not self._pull_bytes(12 + hdr.length): - return None - self.bytes_read += len(self.store_buf) - ret = self.store_buf[12:] + return None, hdr + rec = self.store_buf[12:] self.store_buf = bytes() - if hdr.deleted: - ret = bytes() - return ret + return rec, hdr def refresh(self): """Catch up with any changes to the gossip store""" + start_time = time.time() while True: - off = self.bytes_read - rec = self._read_record() - # EOF? - if rec is None: + rec, hdr = self._read_record() + if rec is None: # EOF break - # Deleted? - if len(rec) == 0: + if hdr.deleted: # Skip deleted records + continue + if hdr.zombie: continue rectype, = struct.unpack(">H", rec[:2]) if rectype == channel_announcement.number: - self._add_channel(rec, off, False) + self._add_channel(rec, False, hdr) elif rectype == WIRE_GOSSIP_STORE_PRIVATE_CHANNEL: - self._add_channel(rec[2 + 8 + 2:], off + 2 + 8 + 2, True) + hdr.off += 2 + 8 + 2 + self._add_channel(rec[2 + 8 + 2:], True, hdr) elif rectype == WIRE_GOSSIP_STORE_CHANNEL_AMOUNT: self._set_channel_amount(rec) elif rectype == channel_update.number: - self._update_channel(rec, off) + self._update_channel(rec, hdr) elif rectype == WIRE_GOSSIP_STORE_PRIVATE_UPDATE: - self._update_channel(rec[2 + 2:], off + 2 + 2) + hdr.off += 2 + 2 + self._update_channel(rec[2 + 2:], hdr) elif rectype == WIRE_GOSSIP_STORE_DELETE_CHAN: self._remove_channel_by_deletemsg(rec) elif rectype == node_announcement.number: - self._add_node_announcement(rec, off) + self._add_node_announcement(rec, hdr) elif rectype == WIRE_GOSSIP_STORE_ENDED: self.reopen_store() else: continue + self.processing_time += time.time() - start_time diff --git a/contrib/pyln-client/pyln/client/gossmapstats.py b/contrib/pyln-client/pyln/client/gossmapstats.py new file mode 100644 index 000000000000..5479e2dc908b --- /dev/null +++ b/contrib/pyln-client/pyln/client/gossmapstats.py @@ -0,0 +1,208 @@ +from pyln.client import Gossmap, GossmapChannel, GossmapNode, GossmapHalfchannel, LnFeatureBits +from typing import Iterable, List, Optional, Callable + +import operator +import statistics + + +class GossmapStats(object): + def __init__(self, g: Gossmap): + self.g = g + + # First the generic filter functions + def filter_nodes(self, predicate: Callable[[GossmapNode], bool], nodes: Optional[Iterable[GossmapNode]] = None) -> List[GossmapNode]: + """ Filter nodes using an arbitrary function or lamda predicate. """ + if nodes is None: + nodes = self.g.nodes.values() + return [n for n in nodes if predicate(n)] + + def filter_channels(self, predicate: Callable[[GossmapChannel], bool], channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapChannel]: + """ Filters channels using an arbitrary function or lambda predicate. """ + if channels is None: + channels = self.g.channels.values() + return [c for c in channels if predicate(c)] + + def filter_halfchannels(self, predicate: Callable[[GossmapHalfchannel], bool], channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapHalfchannel]: + """ Filters half-channels using an arbitrary function or lambda predicate. """ + if channels is None: + channels = self.g.channels.values() + hc0 = [c.half_channels[0] for c in channels if c.half_channels[0] is not None and predicate(c.half_channels[0])] + hc1 = [c.half_channels[1] for c in channels if c.half_channels[1] is not None and predicate(c.half_channels[1])] + return hc0 + hc1 + + # Now a bunch of predefined specific filter methods + def filter_nodes_ratelimited(self, nodes: Optional[Iterable[GossmapNode]] = None) -> List[GossmapNode]: + """ Filters nodes being marked by cln as ratelimited, when they send out too many updates. """ + return self.filter_nodes(lambda n: n.hdr is not None and n.hdr.ratelimit, nodes) + + def filter_nodes_unannounced(self, nodes: Optional[Iterable[GossmapNode]] = None) -> List[GossmapNode]: + """ Filters nodes that are only known by a channel, i.e. missing a node_announcement. + Usually happens when a peer has been offline for a while. """ + return self.filter_nodes(lambda n: not n.announced, nodes) + + def filter_nodes_feature(self, bit, nodes: Optional[Iterable[GossmapNode]] = None) -> List[GossmapNode]: + """Filters nodes based on node_announcement feature bits. """ + return self.filter_nodes(lambda n: n.announced and 3 << bit & n.features != 0, nodes) + + def filter_nodes_feature_compulsory(self, bit, nodes: Optional[Iterable[GossmapNode]] = None) -> List[GossmapNode]: + """Filters nodes based on node_announcement feature bits. """ + return self.filter_nodes(lambda n: n.announced and 1 << bit & n.features != 0, nodes) + + def filter_nodes_feature_optional(self, bit, nodes: Optional[Iterable[GossmapNode]] = None) -> List[GossmapNode]: + """Filters nodes based on node_announcement feature bits. """ + return self.filter_nodes(lambda n: n.announced and 2 << bit & n.features != 0, nodes) + + def filter_nodes_address_type(self, typestr, nodes: Optional[Iterable[GossmapNode]] = None) -> List[GossmapNode]: + """ Filters nodes having at least one address of typetr: 'ipv4', 'ipv6', 'tor' or 'dns'. """ + return self.filter_nodes(lambda n: n.announced and len([idx for idx in range(len(n.addresses)) if n.get_address_type(idx) == typestr]) > 0, nodes) + + def filter_nodes_tor_only(self, nodes: Optional[Iterable[GossmapNode]] = None) -> List[GossmapNode]: + """ Filters nodes that only announce TOR addresses, if any. """ + return self.filter_nodes(lambda n: n.is_tor_only(), nodes) + + def filter_nodes_tor_strict(self, nodes: Optional[Iterable[GossmapNode]] = None) -> List[GossmapNode]: + """ Filters TOR only nodes that don't (or possibly can't) connect to non-TOR nodes. """ + return self.filter_nodes(lambda n: n.is_tor_strict(), nodes) + + def filter_nodes_no_addresses(self, nodes: Optional[Iterable[GossmapNode]] = None) -> List[GossmapNode]: + """ Filters nodes that don't announce any addresses. """ + return self.filter_nodes(lambda n: n.announced and len(n.addresses) == 0, nodes) + + def filter_nodes_channel_count(self, count, op=operator.ge, nodes: Optional[Iterable[GossmapNode]] = None) -> List[GossmapNode]: + """ Filters nodes by its channel count (default op: being greater or eaqual). """ + return self.filter_nodes(lambda n: op(len(n.channels), count), nodes) + + def filter_channels_feature(self, bit, channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapChannel]: + """ Filters channels based on channel_announcement feature bits. """ + return self.filter_channels(lambda c: 3 << bit & c.features != 0, channels) + + def filter_channels_feature_compulsory(self, bit, channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapChannel]: + """ Filters channels based on channel_announcement feature bits. """ + return self.filter_channels(lambda c: 1 << bit & c.features != 0, channels) + + def filter_channels_feature_optional(self, bit, channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapChannel]: + """ Filters channels based on channel_announcement feature bits. """ + return self.filter_channels(lambda c: 2 << bit & c.features != 0, channels) + + def filter_channels_unidirectional(self, channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapChannel]: + """ Filters channels that are known only in one direction, i.e. other peer seems offline for a long time. """ + return self.filter_channels(lambda c: c.half_channels[0] is None or c.half_channels[1] is None, channels) + + def filter_channels_nosatoshis(self, channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapChannel]: + """ Filters channels with missing WIRE_GOSSIP_STORE_CHANNEL_AMOUNT. This should not happen. """ + return self.filter_channels(lambda c: c.satoshis is None, channels) + + def filter_channels_tor_only(self, channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapChannel]: + """ Filters all channels that are connected to TOR only nodes on both ends. """ + return self.filter_channels(lambda c: c.is_tor_only(), channels) + + def filter_channels_capacity(self, satoshis, op=operator.ge, channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapChannel]: + """ Filter channels by its capacity (default op: being greater or equal). """ + return self.filter_channels(lambda c: c.satoshis is not None and op(c.satoshis, satoshis), channels) + + def filter_channels_disabled_bidirectional(self, channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapChannel]: + """ Filters channels that are disabled in both directions. """ + return self.filter_channels(lambda c: c.half_channels[0] is not None and c.half_channels[0].disabled and c.half_channels[1] is not None and c.half_channels[1].disabled, channels) + + def filter_channels_disabled_unidirectional(self, channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapChannel]: + """ Filters channels that are disabled only in one direction. """ + if channels is None: + channels = self.g.channels.values() + hc0 = [c for c in channels if c.half_channels[0] is not None and c.half_channels[0].disabled and (c.half_channels[1] is None or not c.half_channels[1].disabled)] + hc1 = [c for c in channels if c.half_channels[1] is not None and c.half_channels[1].disabled and (c.half_channels[0] is None or not c.half_channels[0].disabled)] + return hc0 + hc1 + + def filter_halfchannels_fee_base(self, msat, op=operator.le, channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapHalfchannel]: + """ Filters half-channels by its base fee (default op: being lower or equal). """ + return self.filter_halfchannels(lambda hc: op(hc.fee_base_msat, msat), channels) + + def filter_halfchannels_fee_ppm(self, msat, op=operator.le, channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapHalfchannel]: + """ Filters half-channels by its ppm fee (default op: being lower or equal). """ + return self.filter_halfchannels(lambda hc: op(hc.fee_proportional_millionths, msat), channels) + + def filter_halfchannels_disabled(self, channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapHalfchannel]: + """ Filters half-channels that are disabled. """ + return self.filter_halfchannels(lambda hc: hc.disabled, channels) + + def filter_halfchannels_ratelimited(self, channels: Optional[Iterable[GossmapChannel]] = None) -> List[GossmapHalfchannel]: + """ Filters half-channels that are being marked as ratelimited for sending out too many updates. """ + return self.filter_halfchannels(lambda hc: hc.hdr.ratelimit, channels) + + def quantiles_nodes_channel_count(self, tiles=100, nodes: Optional[Iterable[GossmapNode]] = None) -> List[float]: + if nodes is None: + nodes = self.g.nodes.values() + return statistics.quantiles([len(n.channels) for n in nodes], n=tiles) + + def quantiles_channels_capacity(self, tiles=100, channels: Optional[Iterable[GossmapChannel]] = None) -> List[float]: + if channels is None: + channels = self.g.channels.values() + return statistics.quantiles([c.satoshis for c in channels if c.satoshis is not None], n=tiles) + + def quantiles_halfchannels_fee_base(self, tiles=100, channels: Optional[Iterable[GossmapChannel]] = None) -> List[float]: + if channels is None: + channels = self.g.channels.values() + hc0 = [c.half_channels[0].fee_base_msat for c in channels if c.half_channels[0] is not None] + hc1 = [c.half_channels[1].fee_base_msat for c in channels if c.half_channels[1] is not None] + return statistics.quantiles(hc0 + hc1, n=tiles) + + def quantiles_halfchannels_fee_ppm(self, tiles=100, channels: Optional[Iterable[GossmapChannel]] = None) -> List[float]: + if channels is None: + channels = self.g.channels.values() + hc0 = [c.half_channels[0].fee_proportional_millionths for c in channels if c.half_channels[0] is not None] + hc1 = [c.half_channels[1].fee_proportional_millionths for c in channels if c.half_channels[1] is not None] + return statistics.quantiles(hc0 + hc1, n=tiles) + + def print_stats(self): + print("#### pyln-client gossmap stats ####") + print(f"The gossip_store has a total of {len(self.g.nodes)} nodes and {len(self.g.channels)} channels.") + print(f"Total processing time was {self.g.processing_time} seconds.") + print("") + + print("CONSISTENCY") + print(f" - {len(self.filter_nodes_unannounced())} orphan nodes without a node_announcement, only known from a channel_announcement.") + print(f" - {len(self.g.orphan_channel_updates)} orphan channel_updates without a prior channel_announcement.") + print(f" - {len(self.filter_nodes_ratelimited())} nodes marked as ratelimited. (sending too many updates).") + print(f" - {len(self.filter_halfchannels_ratelimited())} half-channels marked as ratelimited. (sending too many updates).") + print(f" - {len(self.filter_channels_nosatoshis())} channels without capacity (missing WIRE_GOSSIP_STORE_CHANNEL_AMOUNT). Should be 0.") + print("") + + print("STRUCTURE") + print(f" - {len(self.filter_channels_unidirectional())} channels that are known only in one direction, other peer seems offline for a long time.") + print(f" - {len(self.filter_halfchannels_disabled())} total disabled half-channels.") + print(f" - {len(self.filter_channels_disabled_unidirectional())} channels are only disabled in one direction.") + print(f" - {len(self.filter_channels_disabled_bidirectional())} channels are disabled in both directions.") + print(f" - channel_count per node quantiles(10): {self.quantiles_nodes_channel_count(10)}.") + print(f" - channel_capacity quantiles(10): {self.quantiles_channels_capacity(10)}.") + print("") + + print("ADDRESSES") + print(f" - {len(self.filter_nodes_address_type('ipv4'))} nodes announce IPv4 addresses.") + print(f" - {len(self.filter_nodes_address_type('ipv6'))} nodes announce IPv6 addresses.") + print(f" - {len(self.filter_nodes_address_type('tor'))} nodes announce TOR addresses.") + print(f" - {len(self.filter_nodes_address_type('dns'))} nodes announce DNS addresses.") + print(f" - {len(self.filter_nodes_no_addresses())} don't announce any address.") + print(f" - {len(self.filter_nodes_tor_only())} nodes announce only TOR addresses, if any.") + print(f" - {len(self.filter_nodes_tor_strict())} nodes announce only TOR addresses and don't, or possibly can't, connect to non-TOR nodes.") + print(f" - {len(self.filter_channels_tor_only())} channels are connected TOR only nodes on both ends.") + print("") + + print("FEES") + print(f" - {len(self.filter_halfchannels_fee_base(0))} half-channels have a base_fee of 0msat.") + print(f" - {len(self.filter_halfchannels_fee_base(1000, operator.ge))} half-channels have a base_fee >= 1000msat.") + print(f" - {len(self.filter_halfchannels_fee_ppm(0))} half-channels have a ppm_fee of 0.") + print(f" - {len(self.filter_halfchannels_fee_ppm(1000, operator.ge))} half-channels have a ppm_fee >= 1000.") + print(f" - base_fee quantiles(10): {self.quantiles_halfchannels_fee_base(10)}.") + print(f" - ppm_fee quantiles(10): {self.quantiles_halfchannels_fee_ppm(10)}.") + print("") + + print("FEATURES") + print(f" - {len(self.filter_nodes_feature_compulsory(LnFeatureBits.OPTION_DATA_LOSS_PROTECT))} nodes require data loss protection.") + print(f" - {len(self.filter_nodes_feature(LnFeatureBits.GOSSIP_QUERIES))} nodes support gossip queries.") + print(f" - {len(self.filter_nodes_feature(LnFeatureBits.GOSSIP_QUERIES_EX))} nodes support extended gossip queries.") + print(f" - {len(self.filter_nodes_feature(LnFeatureBits.BASIC_MPP))} nodes support basic MPP.") + print(f" - {len(self.filter_nodes_feature(LnFeatureBits.OPTION_ANCHOR_OUTPUTS))} nodes support anchor outputs.") + print(f" - {len(self.filter_nodes_feature(LnFeatureBits.OPTION_SCID_ALIAS))} nodes support scid alias.") + print(f" - {len(self.filter_nodes_feature(LnFeatureBits.OPTION_ZEROCONF))} nodes support zeroconf.") + print("") + + print("#### pyln-client gossmap END ####") diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index 15272b1d5a76..70c1d0f279f3 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -503,12 +503,14 @@ def replace_amounts(obj): """ if isinstance(obj, dict): for k, v in obj.items(): - if k.endswith('msat'): + # Objects ending in msat are not treated specially! + if k.endswith('msat') and not isinstance(v, dict): if isinstance(v, list): obj[k] = [Millisatoshi(e) for e in v] # FIXME: Deprecated "listconfigs" gives two 'null' fields: # "lease-fee-base-msat": null, # "channel-fee-max-base-msat": null, + # FIXME: Removed for v23.08, delete this code in 24.08? elif v is None: obj[k] = None else: diff --git a/contrib/pyln-client/pyln/client/plugin.py b/contrib/pyln-client/pyln/client/plugin.py index e53bcbeda6df..2673febaba0d 100644 --- a/contrib/pyln-client/pyln/client/plugin.py +++ b/contrib/pyln-client/pyln/client/plugin.py @@ -912,7 +912,7 @@ def _getmanifest(self, **kwargs) -> JSONType: m["long_description"] = method.long_desc manifest = { - 'options': list(self.options.values()), + 'options': list({k: v for k, v in d.items() if v is not None} for d in self.options.values()), 'rpcmethods': methods, 'subscriptions': list(self.subscriptions.keys()), 'hooks': hooks, diff --git a/contrib/pyln-client/pyproject.toml b/contrib/pyln-client/pyproject.toml index 220610286e51..aa6f701fc99c 100644 --- a/contrib/pyln-client/pyproject.toml +++ b/contrib/pyln-client/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pyln-client" -version = "22.11rc1" +version = "23.05" description = "Client library and plugin library for Core Lightning" authors = ["Christian Decker "] license = "BSD-MIT" diff --git a/contrib/pyln-client/tests/data/gossip_store.mesh-3x3.xz b/contrib/pyln-client/tests/data/gossip_store.mesh-3x3.xz new file mode 100644 index 000000000000..1ed9a48cc233 Binary files /dev/null and b/contrib/pyln-client/tests/data/gossip_store.mesh-3x3.xz differ diff --git a/contrib/pyln-client/tests/test_clnutils.py b/contrib/pyln-client/tests/test_clnutils.py new file mode 100644 index 000000000000..410a23d1e892 --- /dev/null +++ b/contrib/pyln-client/tests/test_clnutils.py @@ -0,0 +1,43 @@ +from pyln.client.clnutils import cln_parse_rpcversion + + +def test_rpcversion(): + foo = cln_parse_rpcversion("0.11.2") + assert(foo[0] == 0) + assert(foo[1] == 11) + assert(foo[2] == 2) + + foo = cln_parse_rpcversion("0.11.2rc2-modded") + assert(foo[0] == 0) + assert(foo[1] == 11) + assert(foo[2] == 2) + + foo = cln_parse_rpcversion("22.11") + assert(foo[0] == 22) + assert(foo[1] == 11) + assert(foo[2] == 0) + + foo = cln_parse_rpcversion("22.11rc1") + assert(foo[0] == 22) + assert(foo[1] == 11) + assert(foo[2] == 0) + + foo = cln_parse_rpcversion("22.11rc1-modded") + assert(foo[0] == 22) + assert(foo[1] == 11) + assert(foo[2] == 0) + + foo = cln_parse_rpcversion("22.11-modded") + assert(foo[0] == 22) + assert(foo[1] == 11) + assert(foo[2] == 0) + + foo = cln_parse_rpcversion("22.11.0") + assert(foo[0] == 22) + assert(foo[1] == 11) + assert(foo[2] == 0) + + foo = cln_parse_rpcversion("22.11.1") + assert(foo[0] == 22) + assert(foo[1] == 11) + assert(foo[2] == 1) diff --git a/contrib/pyln-client/tests/test_gossmap.py b/contrib/pyln-client/tests/test_gossmap.py index e834003206ff..3a6e87bc1037 100644 --- a/contrib/pyln-client/tests/test_gossmap.py +++ b/contrib/pyln-client/tests/test_gossmap.py @@ -70,7 +70,7 @@ def test_gossmap_halfchannel(tmp_path): assert chan.node2 == n2 half0 = chan.get_direction(0) - half1 = chan.get_direction(1) + half1 = g.get_halfchannel("103x1x1", 1) assert half0 assert half1 assert half0.direction == 0 @@ -119,3 +119,178 @@ def test_objects(): assert boltz_node < acinq_node assert acinq_node > boltz_node assert boltz_node != acinq_node + + +def test_mesh(tmp_path): + """This gossip store is a nice mesh created with pyln-testing: + + l1--l2--l3 + | | | + l4--l5--l6 + | | | + l7--l8--l9 + """ + sfile = unxz_data_tmp("gossip_store.mesh-3x3.xz", tmp_path, "gossip_store", "xb") + g = Gossmap(sfile) + assert len(g.nodes) == 9 + assert len(g.channels) == 12 + + nodeids = ['0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518', + '022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59', + '035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d', + '0382ce59ebf18be7d84677c2e35f23294b9992ceca95491fcf8a56c6cb2d9de199', + '032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e', + '0265b6ab5ec860cd257865d61ef0bbf5b3339c36cbda8b26b74e7f1dca490b6518', + '0269f9862c311261241e5aee7abe0ec93c88613cc8f3c5f33cb1eea90d2bc4ddb6', + '03a7fd8070eea99341418fefe0b31086054d09cff64649eec3605db2340631c616', + '030eeb52087b9dbb27b7aec79ca5249369f6ce7b20a5684ce38d9f4595a21c2fda'] + scid12 = '103x1x0' + scid14 = '105x1x1' + scid23 = '107x1x1' + scid25 = '109x1x1' + scid36 = '111x1x0' + scid45 = '113x1x0' + scid47 = '115x1x1' + scid56 = '117x1x1' + scid58 = '119x1x0' + scid69 = '121x1x1' + scid78 = '123x1x1' + scid89 = '125x1x1' + scids = [scid12, scid14, scid23, scid25, scid36, scid45, scid47, scid56, + scid58, scid69, scid78, scid89] + + nodes = [g.get_node(nid) for nid in nodeids] + + # check all nodes are there + for nodeid in nodeids: + node = g.get_node(nodeid) + assert node + assert str(node.node_id) == nodeid + for channel in node.channels: + assert str(channel.scid) in scids + + # assert all channels are there + for scid in scids: + channel = g.get_channel(scid) + assert channel + assert str(channel.scid) == scid + assert channel.half_channels[0] + assert channel.half_channels[1] + + # check basic relations + # get_neighbors l5 in the middle depth=0 returns just that node + result = g.get_neighbors(source=nodeids[4]) + assert len(result) == 1 + assert str(next(iter(result)).node_id) == nodeids[4] + result = g.get_neighbors(source=nodeids[4], depth=1) + assert len(result) == 5 + # on depth=1 the cross l2, l4, l5, l6, l8 must be returned + assert nodes[1] in result + assert nodes[3] in result + assert nodes[4] in result + assert nodes[5] in result + assert nodes[7] in result + # on depth>=2 all nodes must be returned as we visited the whole graph + for d in range(2, 4): + result = g.get_neighbors(source=nodeids[4], depth=d) + assert len(result) == 9 + for node in nodes: + assert node in result + # get_neighbors on l9 with depth=3 must return all but l1 + result = g.get_neighbors(nodeids[8], depth=3) + assert len(result) == 8 + assert nodes[0] not in result + # get_neighbors on l9 with depth=4 and excludes l5 must return all but l5 + result = g.get_neighbors(nodeids[8], depth=4, excludes=[nodes[4]]) + assert len(result) == 8 + assert nodes[4] not in result + + # get_neighbors_hc l5 in the middle expect: 25, 45, 65 and 85 + result = g.get_neighbors_hc(source=nodeids[4]) + exp_ids = [nodeids[1], nodeids[3], nodeids[5], nodeids[7]] + exp_scidds = [scid25 + '/1', scid45 + '/0', scid56 + '/1', scid58 + '/0'] + assert len(result) == len(exp_ids) + for halfchan in result: + assert str(halfchan.source.node_id) == nodeids[4] + assert str(halfchan.destination.node_id) in exp_ids + assert str(halfchan) in exp_scidds + + # same but other direction + result = g.get_neighbors_hc(destination=nodeids[4]) + exp_ids = [nodeids[1], nodeids[3], nodeids[5], nodeids[7]] + exp_scidds = [scid25 + '/0', scid45 + '/1', scid56 + '/0', scid58 + '/1'] + assert len(result) == len(exp_ids) + for halfchan in result: + assert str(halfchan.destination.node_id) == nodeids[4] + assert str(halfchan.source.node_id) in exp_ids + assert str(halfchan) in exp_scidds + + # get all channels which have l1 as destination + result = g.get_neighbors_hc(destination=nodeids[0]) + exp_ids = [nodeids[1], nodeids[3]] + exp_scidds = [scid12 + '/0', scid14 + '/1'] + assert len(result) == len(exp_ids) + for halfchan in result: + assert str(halfchan.destination.node_id) == nodeids[0] + assert str(halfchan.source.node_id) in exp_ids + assert str(halfchan) in exp_scidds + + # l5 as destination in the middle but depth=1, so the outer ring + # epxect: 12, 14, 32, 36, 74, 78, 98, 96 + result = g.get_neighbors_hc(destination=nodeids[4], depth=1) + exp_scidds = [scid12 + '/1', scid14 + '/0', scid23 + '/1', scid36 + '/1', + scid47 + '/0', scid69 + '/1', scid78 + '/0', scid89 + '/0'] + assert len(result) == len(exp_scidds) + for halfchan in result: + assert str(halfchan) in exp_scidds + + # same but other direction + result = g.get_neighbors_hc(source=nodeids[4], depth=1) + exp_scidds = [scid12 + '/0', scid14 + '/1', scid23 + '/0', scid36 + '/0', + scid47 + '/1', scid69 + '/0', scid78 + '/1', scid89 + '/1'] + assert len(result) == len(exp_scidds) + for halfchan in result: + assert str(halfchan) in exp_scidds + + # l9 as destination and depth=2 expect: 23 25 45 47 + result = g.get_neighbors_hc(destination=nodeids[8], depth=2) + exp_scidds = [scid23 + '/0', scid25 + '/0', scid45 + '/1', scid47 + '/1'] + assert len(result) == len(exp_scidds) + for halfchan in result: + assert str(halfchan) in exp_scidds + + # l9 as destination depth=2 exclude=[l7] expect: 23 25 45 + result = g.get_neighbors_hc(destination=nodeids[8], depth=2, excludes=[nodes[6]]) + exp_scidds = [scid23 + '/0', scid25 + '/0', scid45 + '/1'] + assert len(result) == len(exp_scidds) + for halfchan in result: + assert str(halfchan) in exp_scidds + + # same as above, but excludes halfchannels of l7 expect: 23 25 45 + hcs = [c.half_channels[0] for c in nodes[6].channels] + hcs += [c.half_channels[1] for c in nodes[6].channels] + result = g.get_neighbors_hc(destination=nodeids[8], depth=2, excludes=hcs) + exp_scidds = [scid23 + '/0', scid25 + '/0', scid45 + '/1'] + assert len(result) == len(exp_scidds) + for halfchan in result: + assert str(halfchan) in exp_scidds + + # again, same as above, but excludes channels of l7 expect: 23 25 45 + chs = [c for c in nodes[6].channels] + result = g.get_neighbors_hc(destination=nodeids[8], depth=2, excludes=chs) + exp_scidds = [scid23 + '/0', scid25 + '/0', scid45 + '/1'] + assert len(result) == len(exp_scidds) + for halfchan in result: + assert str(halfchan) in exp_scidds + + # l9 as destination and depth=3 expect: 12 14 + result = g.get_neighbors_hc(destination=nodeids[8], depth=3) + exp_scidds = [scid12 + '/1', scid14 + '/0'] + assert len(result) == len(exp_scidds) + for halfchan in result: + assert str(halfchan) in exp_scidds + + # l9 as destination and depth>=4 expect: empty set + for d in range(4, 6): + result = g.get_neighbors_hc(destination=nodeids[8], depth=d) + assert len(result) == 0 diff --git a/contrib/pyln-proto/pyln/proto/__init__.py b/contrib/pyln-proto/pyln/proto/__init__.py index 6acf3cd64c2a..44ac9994fe16 100644 --- a/contrib/pyln-proto/pyln/proto/__init__.py +++ b/contrib/pyln-proto/pyln/proto/__init__.py @@ -4,7 +4,7 @@ from .onion import OnionPayload, TlvPayload, LegacyOnionPayload from .wire import LightningConnection, LightningServerSocket -__version__ = "22.11rc1" +__version__ = "23.05" __all__ = [ "Invoice", diff --git a/contrib/pyln-proto/pyln/proto/primitives.py b/contrib/pyln-proto/pyln/proto/primitives.py index d9deb6a9c248..1de342f3f0ca 100644 --- a/contrib/pyln-proto/pyln/proto/primitives.py +++ b/contrib/pyln-proto/pyln/proto/primitives.py @@ -62,9 +62,7 @@ def from_int(cls, i): @classmethod def from_str(self, s): - block, txnum, outnum = s.split('x') - return ShortChannelId(block=int(block), txnum=int(txnum), - outnum=int(outnum)) + return ShortChannelId(*map(int, s.split('x'))) def to_int(self): return self.block << 40 | self.txnum << 16 | self.outnum diff --git a/contrib/pyln-proto/pyproject.toml b/contrib/pyln-proto/pyproject.toml index 9565e796e8d7..d4dd88403e50 100644 --- a/contrib/pyln-proto/pyproject.toml +++ b/contrib/pyln-proto/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pyln-proto" -version = "22.11rc1" +version = "23.05" description = "This package implements some of the Lightning Network protocol in pure python. It is intended for protocol testing and some minor tooling only. It is not deemed secure enough to handle any amount of real funds (you have been warned!)." authors = ["Christian Decker "] license = "BSD-MIT" @@ -15,7 +15,7 @@ python = "^3.7" base58 = "^2.1.1" bitstring = "^3.1.9" coincurve = "^17.0.0" -cryptography = "^36.0.1" +cryptography = "^41.0.1" PySocks = "^1.7.1" [tool.poetry.dev-dependencies] diff --git a/contrib/pyln-testing/pyln/testing/__init__.py b/contrib/pyln-testing/pyln/testing/__init__.py index 716038e11398..9cf6bca081eb 100644 --- a/contrib/pyln-testing/pyln/testing/__init__.py +++ b/contrib/pyln-testing/pyln/testing/__init__.py @@ -1,4 +1,4 @@ -__version__ = "22.11rc1" +__version__ = "23.05" __all__ = [ "__version__", diff --git a/contrib/pyln-testing/pyln/testing/fixtures.py b/contrib/pyln-testing/pyln/testing/fixtures.py index 795b67ecf246..bf3293d24452 100644 --- a/contrib/pyln-testing/pyln/testing/fixtures.py +++ b/contrib/pyln-testing/pyln/testing/fixtures.py @@ -1,6 +1,6 @@ from concurrent import futures from pyln.testing.db import SqliteDbProvider, PostgresDbProvider -from pyln.testing.utils import NodeFactory, BitcoinD, ElementsD, env, DEVELOPER, LightningNode, TEST_DEBUG, Throttler +from pyln.testing.utils import NodeFactory, BitcoinD, ElementsD, env, DEVELOPER, LightningNode, TEST_DEBUG from pyln.client import Millisatoshi from typing import Dict @@ -206,11 +206,6 @@ def teardown_checks(request): raise ValueError(str(errors)) -@pytest.fixture -def throttler(test_base_dir): - yield Throttler(test_base_dir) - - def _extra_validator(is_request: bool): """JSON Schema validator with additions for our specialized types""" def is_hex(checker, instance): @@ -300,7 +295,7 @@ def is_feerate(checker, instance): return True if not checker.is_type(instance, "string"): return False - if instance in ("urgent", "normal", "slow"): + if instance in ("urgent", "normal", "slow", "minimum"): return True if instance in ("opening", "mutual_close", "unilateral_close", "delayed_to_us", "htlc_resolution", "penalty", "min_acceptable", "max_acceptable"): return True @@ -353,7 +348,7 @@ def is_msat_request(checker, instance): return False def is_msat_response(checker, instance): - """String number ending in msat (deprecated) or integer""" + """An integer, but we convert to Millisatoshi in JSON parsing""" return type(instance) is Millisatoshi def is_txid(checker, instance): @@ -451,7 +446,7 @@ def jsonschemas(): @pytest.fixture -def node_factory(request, directory, test_name, bitcoind, executor, db_provider, teardown_checks, node_cls, throttler, jsonschemas): +def node_factory(request, directory, test_name, bitcoind, executor, db_provider, teardown_checks, node_cls, jsonschemas): nf = NodeFactory( request, test_name, @@ -460,7 +455,6 @@ def node_factory(request, directory, test_name, bitcoind, executor, db_provider, directory=directory, db_provider=db_provider, node_cls=node_cls, - throttler=throttler, jsonschemas=jsonschemas, ) diff --git a/contrib/pyln-testing/pyln/testing/grpc2py.py b/contrib/pyln-testing/pyln/testing/grpc2py.py index 28b366c8bdda..42a85d30a81b 100644 --- a/contrib/pyln-testing/pyln/testing/grpc2py.py +++ b/contrib/pyln-testing/pyln/testing/grpc2py.py @@ -8,12 +8,10 @@ def hexlify(b): return b if b is None else b.hex() + def amount2msat(a): return a.msat -def amount_or_all2msat(a): - breakpoint() - def remove_default(d): # grpc is really not good at empty values, they get replaced with the type's default value... @@ -59,7 +57,6 @@ def getinfo2py(m): "lightning_dir": m.lightning_dir, # PrimitiveField in generate_composite "blockheight": m.blockheight, # PrimitiveField in generate_composite "network": m.network, # PrimitiveField in generate_composite - "msatoshi_fees_collected": m.msatoshi_fees_collected, # PrimitiveField in generate_composite "fees_collected_msat": amount2msat(m.fees_collected_msat), # PrimitiveField in generate_composite "address": [getinfo_address2py(i) for i in m.address], # ArrayField[composite] in generate_composite "binding": [getinfo_binding2py(i) for i in m.binding], # ArrayField[composite] in generate_composite @@ -100,8 +97,6 @@ def listpeers_peers_channels_inflight2py(m): def listpeers_peers_channels_funding2py(m): return remove_default({ - "local_msat": amount2msat(m.local_msat), # PrimitiveField in generate_composite - "remote_msat": amount2msat(m.remote_msat), # PrimitiveField in generate_composite "pushed_msat": amount2msat(m.pushed_msat), # PrimitiveField in generate_composite "local_funds_msat": amount2msat(m.local_funds_msat), # PrimitiveField in generate_composite "remote_funds_msat": amount2msat(m.remote_funds_msat), # PrimitiveField in generate_composite @@ -185,6 +180,7 @@ def listpeers_peers2py(m): return remove_default({ "id": hexlify(m.id), # PrimitiveField in generate_composite "connected": m.connected, # PrimitiveField in generate_composite + "num_channels": m.num_channels, # PrimitiveField in generate_composite "log": [listpeers_peers_log2py(i) for i in m.log], # ArrayField[composite] in generate_composite "channels": [listpeers_peers_channels2py(i) for i in m.channels], # ArrayField[composite] in generate_composite "netaddr": [m.netaddr for i in m.netaddr], # ArrayField[primitive] in generate_composite @@ -222,6 +218,7 @@ def listfunds_channels2py(m): "funding_output": m.funding_output, # PrimitiveField in generate_composite "connected": m.connected, # PrimitiveField in generate_composite "state": str(m.state), # EnumField in generate_composite + "channel_id": hexlify(m.channel_id), # PrimitiveField in generate_composite "short_channel_id": m.short_channel_id, # PrimitiveField in generate_composite }) @@ -492,8 +489,6 @@ def listtransactions_transactions_inputs2py(m): "txid": hexlify(m.txid), # PrimitiveField in generate_composite "index": m.index, # PrimitiveField in generate_composite "sequence": m.sequence, # PrimitiveField in generate_composite - "type": str(m.item_type), # EnumField in generate_composite - "channel": m.channel, # PrimitiveField in generate_composite }) @@ -502,8 +497,6 @@ def listtransactions_transactions_outputs2py(m): "index": m.index, # PrimitiveField in generate_composite "amount_msat": amount2msat(m.amount_msat), # PrimitiveField in generate_composite "script_pub_key": hexlify(m.script_pub_key), # PrimitiveField in generate_composite - "type": str(m.item_type), # EnumField in generate_composite - "channel": m.channel, # PrimitiveField in generate_composite }) @@ -725,15 +718,442 @@ def txsend2py(m): }) +def listpeerchannels_channels_channel_type2py(m): + return remove_default({ + "bits": [m.bits for i in m.bits], # ArrayField[primitive] in generate_composite + "names": [str(i) for i in m.names], # ArrayField[composite] in generate_composite + }) + + +def listpeerchannels_channels_feerate2py(m): + return remove_default({ + "perkw": m.perkw, # PrimitiveField in generate_composite + "perkb": m.perkb, # PrimitiveField in generate_composite + }) + + +def listpeerchannels_channels_inflight2py(m): + return remove_default({ + "funding_txid": hexlify(m.funding_txid), # PrimitiveField in generate_composite + "funding_outnum": m.funding_outnum, # PrimitiveField in generate_composite + "feerate": m.feerate, # PrimitiveField in generate_composite + "total_funding_msat": amount2msat(m.total_funding_msat), # PrimitiveField in generate_composite + "our_funding_msat": amount2msat(m.our_funding_msat), # PrimitiveField in generate_composite + "scratch_txid": hexlify(m.scratch_txid), # PrimitiveField in generate_composite + }) + + +def listpeerchannels_channels_funding2py(m): + return remove_default({ + "pushed_msat": amount2msat(m.pushed_msat), # PrimitiveField in generate_composite + "local_funds_msat": amount2msat(m.local_funds_msat), # PrimitiveField in generate_composite + "remote_funds_msat": amount2msat(m.remote_funds_msat), # PrimitiveField in generate_composite + "fee_paid_msat": amount2msat(m.fee_paid_msat), # PrimitiveField in generate_composite + "fee_rcvd_msat": amount2msat(m.fee_rcvd_msat), # PrimitiveField in generate_composite + }) + + +def listpeerchannels_channels_alias2py(m): + return remove_default({ + "local": m.local, # PrimitiveField in generate_composite + "remote": m.remote, # PrimitiveField in generate_composite + }) + + +def listpeerchannels_channels_state_changes2py(m): + return remove_default({ + "timestamp": m.timestamp, # PrimitiveField in generate_composite + "old_state": str(m.old_state), # EnumField in generate_composite + "new_state": str(m.new_state), # EnumField in generate_composite + "cause": str(m.cause), # EnumField in generate_composite + "message": m.message, # PrimitiveField in generate_composite + }) + + +def listpeerchannels_channels_htlcs2py(m): + return remove_default({ + "direction": str(m.direction), # EnumField in generate_composite + "id": m.id, # PrimitiveField in generate_composite + "amount_msat": amount2msat(m.amount_msat), # PrimitiveField in generate_composite + "expiry": m.expiry, # PrimitiveField in generate_composite + "payment_hash": hexlify(m.payment_hash), # PrimitiveField in generate_composite + "local_trimmed": m.local_trimmed, # PrimitiveField in generate_composite + "status": m.status, # PrimitiveField in generate_composite + "state": str(m.state), # EnumField in generate_composite + }) + + +def listpeerchannels_channels2py(m): + return remove_default({ + "peer_id": hexlify(m.peer_id), # PrimitiveField in generate_composite + "peer_connected": m.peer_connected, # PrimitiveField in generate_composite + "state": str(m.state), # EnumField in generate_composite + "scratch_txid": hexlify(m.scratch_txid), # PrimitiveField in generate_composite + "owner": m.owner, # PrimitiveField in generate_composite + "short_channel_id": m.short_channel_id, # PrimitiveField in generate_composite + "channel_id": hexlify(m.channel_id), # PrimitiveField in generate_composite + "funding_txid": hexlify(m.funding_txid), # PrimitiveField in generate_composite + "funding_outnum": m.funding_outnum, # PrimitiveField in generate_composite + "initial_feerate": m.initial_feerate, # PrimitiveField in generate_composite + "last_feerate": m.last_feerate, # PrimitiveField in generate_composite + "next_feerate": m.next_feerate, # PrimitiveField in generate_composite + "next_fee_step": m.next_fee_step, # PrimitiveField in generate_composite + "inflight": [listpeerchannels_channels_inflight2py(i) for i in m.inflight], # ArrayField[composite] in generate_composite + "close_to": hexlify(m.close_to), # PrimitiveField in generate_composite + "private": m.private, # PrimitiveField in generate_composite + "opener": str(m.opener), # EnumField in generate_composite + "closer": str(m.closer), # EnumField in generate_composite + "features": [str(i) for i in m.features], # ArrayField[composite] in generate_composite + "to_us_msat": amount2msat(m.to_us_msat), # PrimitiveField in generate_composite + "min_to_us_msat": amount2msat(m.min_to_us_msat), # PrimitiveField in generate_composite + "max_to_us_msat": amount2msat(m.max_to_us_msat), # PrimitiveField in generate_composite + "total_msat": amount2msat(m.total_msat), # PrimitiveField in generate_composite + "fee_base_msat": amount2msat(m.fee_base_msat), # PrimitiveField in generate_composite + "fee_proportional_millionths": m.fee_proportional_millionths, # PrimitiveField in generate_composite + "dust_limit_msat": amount2msat(m.dust_limit_msat), # PrimitiveField in generate_composite + "max_total_htlc_in_msat": amount2msat(m.max_total_htlc_in_msat), # PrimitiveField in generate_composite + "their_reserve_msat": amount2msat(m.their_reserve_msat), # PrimitiveField in generate_composite + "our_reserve_msat": amount2msat(m.our_reserve_msat), # PrimitiveField in generate_composite + "spendable_msat": amount2msat(m.spendable_msat), # PrimitiveField in generate_composite + "receivable_msat": amount2msat(m.receivable_msat), # PrimitiveField in generate_composite + "minimum_htlc_in_msat": amount2msat(m.minimum_htlc_in_msat), # PrimitiveField in generate_composite + "minimum_htlc_out_msat": amount2msat(m.minimum_htlc_out_msat), # PrimitiveField in generate_composite + "maximum_htlc_out_msat": amount2msat(m.maximum_htlc_out_msat), # PrimitiveField in generate_composite + "their_to_self_delay": m.their_to_self_delay, # PrimitiveField in generate_composite + "our_to_self_delay": m.our_to_self_delay, # PrimitiveField in generate_composite + "max_accepted_htlcs": m.max_accepted_htlcs, # PrimitiveField in generate_composite + "state_changes": [listpeerchannels_channels_state_changes2py(i) for i in m.state_changes], # ArrayField[composite] in generate_composite + "status": [m.status for i in m.status], # ArrayField[primitive] in generate_composite + "in_payments_offered": m.in_payments_offered, # PrimitiveField in generate_composite + "in_offered_msat": amount2msat(m.in_offered_msat), # PrimitiveField in generate_composite + "in_payments_fulfilled": m.in_payments_fulfilled, # PrimitiveField in generate_composite + "in_fulfilled_msat": amount2msat(m.in_fulfilled_msat), # PrimitiveField in generate_composite + "out_payments_offered": m.out_payments_offered, # PrimitiveField in generate_composite + "out_offered_msat": amount2msat(m.out_offered_msat), # PrimitiveField in generate_composite + "out_payments_fulfilled": m.out_payments_fulfilled, # PrimitiveField in generate_composite + "out_fulfilled_msat": amount2msat(m.out_fulfilled_msat), # PrimitiveField in generate_composite + "htlcs": [listpeerchannels_channels_htlcs2py(i) for i in m.htlcs], # ArrayField[composite] in generate_composite + "close_to_addr": m.close_to_addr, # PrimitiveField in generate_composite + }) + + +def listpeerchannels2py(m): + return remove_default({ + "channels": [listpeerchannels_channels2py(i) for i in m.channels], # ArrayField[composite] in generate_composite + }) + + +def listclosedchannels_closedchannels_alias2py(m): + return remove_default({ + "local": m.local, # PrimitiveField in generate_composite + "remote": m.remote, # PrimitiveField in generate_composite + }) + + +def listclosedchannels_closedchannels_channel_type2py(m): + return remove_default({ + "bits": [m.bits for i in m.bits], # ArrayField[primitive] in generate_composite + "names": [str(i) for i in m.names], # ArrayField[composite] in generate_composite + }) + + +def listclosedchannels_closedchannels2py(m): + return remove_default({ + "peer_id": hexlify(m.peer_id), # PrimitiveField in generate_composite + "channel_id": hexlify(m.channel_id), # PrimitiveField in generate_composite + "short_channel_id": m.short_channel_id, # PrimitiveField in generate_composite + "opener": str(m.opener), # EnumField in generate_composite + "closer": str(m.closer), # EnumField in generate_composite + "private": m.private, # PrimitiveField in generate_composite + "total_local_commitments": m.total_local_commitments, # PrimitiveField in generate_composite + "total_remote_commitments": m.total_remote_commitments, # PrimitiveField in generate_composite + "total_htlcs_sent": m.total_htlcs_sent, # PrimitiveField in generate_composite + "funding_txid": hexlify(m.funding_txid), # PrimitiveField in generate_composite + "funding_outnum": m.funding_outnum, # PrimitiveField in generate_composite + "leased": m.leased, # PrimitiveField in generate_composite + "funding_fee_paid_msat": amount2msat(m.funding_fee_paid_msat), # PrimitiveField in generate_composite + "funding_fee_rcvd_msat": amount2msat(m.funding_fee_rcvd_msat), # PrimitiveField in generate_composite + "funding_pushed_msat": amount2msat(m.funding_pushed_msat), # PrimitiveField in generate_composite + "total_msat": amount2msat(m.total_msat), # PrimitiveField in generate_composite + "final_to_us_msat": amount2msat(m.final_to_us_msat), # PrimitiveField in generate_composite + "min_to_us_msat": amount2msat(m.min_to_us_msat), # PrimitiveField in generate_composite + "max_to_us_msat": amount2msat(m.max_to_us_msat), # PrimitiveField in generate_composite + "last_commitment_txid": hexlify(m.last_commitment_txid), # PrimitiveField in generate_composite + "last_commitment_fee_msat": amount2msat(m.last_commitment_fee_msat), # PrimitiveField in generate_composite + "close_cause": str(m.close_cause), # EnumField in generate_composite + }) + + +def listclosedchannels2py(m): + return remove_default({ + "closedchannels": [listclosedchannels_closedchannels2py(i) for i in m.closedchannels], # ArrayField[composite] in generate_composite + }) + + +def decodepay_fallbacks2py(m): + return remove_default({ + "type": str(m.item_type), # EnumField in generate_composite + "addr": m.addr, # PrimitiveField in generate_composite + "hex": hexlify(m.hex), # PrimitiveField in generate_composite + }) + + +def decodepay_routes2py(m): + return remove_default({ + "pubkey": hexlify(m.pubkey), # PrimitiveField in generate_composite + "short_channel_id": m.short_channel_id, # PrimitiveField in generate_composite + "fee_base_msat": amount2msat(m.fee_base_msat), # PrimitiveField in generate_composite + "fee_proportional_millionths": m.fee_proportional_millionths, # PrimitiveField in generate_composite + "cltv_expiry_delta": m.cltv_expiry_delta, # PrimitiveField in generate_composite + }) + + +def decodepay_extra2py(m): + return remove_default({ + "tag": m.tag, # PrimitiveField in generate_composite + "data": m.data, # PrimitiveField in generate_composite + }) + + +def decodepay2py(m): + return remove_default({ + "currency": m.currency, # PrimitiveField in generate_composite + "created_at": m.created_at, # PrimitiveField in generate_composite + "expiry": m.expiry, # PrimitiveField in generate_composite + "payee": hexlify(m.payee), # PrimitiveField in generate_composite + "amount_msat": amount2msat(m.amount_msat), # PrimitiveField in generate_composite + "payment_hash": hexlify(m.payment_hash), # PrimitiveField in generate_composite + "signature": hexlify(m.signature), # PrimitiveField in generate_composite + "description": m.description, # PrimitiveField in generate_composite + "description_hash": hexlify(m.description_hash), # PrimitiveField in generate_composite + "min_final_cltv_expiry": m.min_final_cltv_expiry, # PrimitiveField in generate_composite + "payment_secret": hexlify(m.payment_secret), # PrimitiveField in generate_composite + "features": hexlify(m.features), # PrimitiveField in generate_composite + "payment_metadata": hexlify(m.payment_metadata), # PrimitiveField in generate_composite + "fallbacks": [decodepay_fallbacks2py(i) for i in m.fallbacks], # ArrayField[composite] in generate_composite + "routes": [decodepay_routes2py(i) for i in m.routes], # ArrayField[composite] in generate_composite + "extra": [decodepay_extra2py(i) for i in m.extra], # ArrayField[composite] in generate_composite + }) + + +def decode_offer_paths_path2py(m): + return remove_default({ + "blinded_node_id": hexlify(m.blinded_node_id), # PrimitiveField in generate_composite + "encrypted_recipient_data": hexlify(m.encrypted_recipient_data), # PrimitiveField in generate_composite + }) + + +def decode_offer_paths2py(m): + return remove_default({ + "first_node_id": hexlify(m.first_node_id), # PrimitiveField in generate_composite + "blinding": hexlify(m.blinding), # PrimitiveField in generate_composite + "path": [decode_offer_paths_path2py(i) for i in m.path], # ArrayField[composite] in generate_composite + }) + + +def decode_offer_recurrence_paywindow2py(m): + return remove_default({ + "seconds_before": m.seconds_before, # PrimitiveField in generate_composite + "seconds_after": m.seconds_after, # PrimitiveField in generate_composite + "proportional_amount": m.proportional_amount, # PrimitiveField in generate_composite + }) + + +def decode_offer_recurrence2py(m): + return remove_default({ + "time_unit": m.time_unit, # PrimitiveField in generate_composite + "time_unit_name": m.time_unit_name, # PrimitiveField in generate_composite + "period": m.period, # PrimitiveField in generate_composite + "basetime": m.basetime, # PrimitiveField in generate_composite + "start_any_period": m.start_any_period, # PrimitiveField in generate_composite + "limit": m.limit, # PrimitiveField in generate_composite + }) + + +def decode_unknown_offer_tlvs2py(m): + return remove_default({ + "item_type": m.type, # PrimitiveField in generate_composite + "length": m.length, # PrimitiveField in generate_composite + "value": hexlify(m.value), # PrimitiveField in generate_composite + }) + + +def decode_unknown_invoice_request_tlvs2py(m): + return remove_default({ + "item_type": m.type, # PrimitiveField in generate_composite + "length": m.length, # PrimitiveField in generate_composite + "value": hexlify(m.value), # PrimitiveField in generate_composite + }) + + +def decode_invoice_paths_payinfo2py(m): + return remove_default({ + "fee_base_msat": amount2msat(m.fee_base_msat), # PrimitiveField in generate_composite + "fee_proportional_millionths": m.fee_proportional_millionths, # PrimitiveField in generate_composite + "cltv_expiry_delta": m.cltv_expiry_delta, # PrimitiveField in generate_composite + "features": hexlify(m.features), # PrimitiveField in generate_composite + }) + + +def decode_invoice_paths_path2py(m): + return remove_default({ + "blinded_node_id": hexlify(m.blinded_node_id), # PrimitiveField in generate_composite + "encrypted_recipient_data": hexlify(m.encrypted_recipient_data), # PrimitiveField in generate_composite + }) + + +def decode_invoice_paths2py(m): + return remove_default({ + "first_node_id": hexlify(m.first_node_id), # PrimitiveField in generate_composite + "blinding": hexlify(m.blinding), # PrimitiveField in generate_composite + "path": [decode_invoice_paths_path2py(i) for i in m.path], # ArrayField[composite] in generate_composite + }) + + +def decode_invoice_fallbacks2py(m): + return remove_default({ + "version": m.version, # PrimitiveField in generate_composite + "hex": hexlify(m.hex), # PrimitiveField in generate_composite + "address": m.address, # PrimitiveField in generate_composite + }) + + +def decode_unknown_invoice_tlvs2py(m): + return remove_default({ + "item_type": m.type, # PrimitiveField in generate_composite + "length": m.length, # PrimitiveField in generate_composite + "value": hexlify(m.value), # PrimitiveField in generate_composite + }) + + +def decode_fallbacks2py(m): + return remove_default({ + "warning_invoice_fallbacks_version_invalid": m.warning_invoice_fallbacks_version_invalid, # PrimitiveField in generate_composite + }) + + +def decode_routes2py(m): + return remove_default({ + "pubkey": hexlify(m.pubkey), # PrimitiveField in generate_composite + "short_channel_id": m.short_channel_id, # PrimitiveField in generate_composite + "fee_base_msat": amount2msat(m.fee_base_msat), # PrimitiveField in generate_composite + "fee_proportional_millionths": m.fee_proportional_millionths, # PrimitiveField in generate_composite + "cltv_expiry_delta": m.cltv_expiry_delta, # PrimitiveField in generate_composite + }) + + +def decode_extra2py(m): + return remove_default({ + "tag": m.tag, # PrimitiveField in generate_composite + "data": m.data, # PrimitiveField in generate_composite + }) + + +def decode_restrictions2py(m): + return remove_default({ + "alternatives": [m.alternatives for i in m.alternatives], # ArrayField[primitive] in generate_composite + "summary": m.summary, # PrimitiveField in generate_composite + }) + + +def decode2py(m): + return remove_default({ + "type": str(m.item_type), # EnumField in generate_composite + "valid": m.valid, # PrimitiveField in generate_composite + "offer_id": hexlify(m.offer_id), # PrimitiveField in generate_composite + "offer_chains": [hexlify(m.offer_chains) for i in hexlify(m.offer_chains)], # ArrayField[primitive] in generate_composite + "offer_metadata": hexlify(m.offer_metadata), # PrimitiveField in generate_composite + "offer_currency": m.offer_currency, # PrimitiveField in generate_composite + "warning_unknown_offer_currency": m.warning_unknown_offer_currency, # PrimitiveField in generate_composite + "currency_minor_unit": m.currency_minor_unit, # PrimitiveField in generate_composite + "offer_amount": m.offer_amount, # PrimitiveField in generate_composite + "offer_amount_msat": amount2msat(m.offer_amount_msat), # PrimitiveField in generate_composite + "offer_description": m.offer_description, # PrimitiveField in generate_composite + "offer_issuer": m.offer_issuer, # PrimitiveField in generate_composite + "offer_features": hexlify(m.offer_features), # PrimitiveField in generate_composite + "offer_absolute_expiry": m.offer_absolute_expiry, # PrimitiveField in generate_composite + "offer_quantity_max": m.offer_quantity_max, # PrimitiveField in generate_composite + "offer_paths": [decode_offer_paths2py(i) for i in m.offer_paths], # ArrayField[composite] in generate_composite + "offer_node_id": hexlify(m.offer_node_id), # PrimitiveField in generate_composite + "unknown_offer_tlvs": [decode_unknown_offer_tlvs2py(i) for i in m.unknown_offer_tlvs], # ArrayField[composite] in generate_composite + "warning_missing_offer_node_id": m.warning_missing_offer_node_id, # PrimitiveField in generate_composite + "warning_invalid_offer_description": m.warning_invalid_offer_description, # PrimitiveField in generate_composite + "warning_missing_offer_description": m.warning_missing_offer_description, # PrimitiveField in generate_composite + "warning_invalid_offer_currency": m.warning_invalid_offer_currency, # PrimitiveField in generate_composite + "warning_invalid_offer_issuer": m.warning_invalid_offer_issuer, # PrimitiveField in generate_composite + "invreq_metadata": hexlify(m.invreq_metadata), # PrimitiveField in generate_composite + "invreq_payer_id": hexlify(m.invreq_payer_id), # PrimitiveField in generate_composite + "invreq_chain": hexlify(m.invreq_chain), # PrimitiveField in generate_composite + "invreq_amount_msat": amount2msat(m.invreq_amount_msat), # PrimitiveField in generate_composite + "invreq_features": hexlify(m.invreq_features), # PrimitiveField in generate_composite + "invreq_quantity": m.invreq_quantity, # PrimitiveField in generate_composite + "invreq_payer_note": m.invreq_payer_note, # PrimitiveField in generate_composite + "invreq_recurrence_counter": m.invreq_recurrence_counter, # PrimitiveField in generate_composite + "invreq_recurrence_start": m.invreq_recurrence_start, # PrimitiveField in generate_composite + "unknown_invoice_request_tlvs": [decode_unknown_invoice_request_tlvs2py(i) for i in m.unknown_invoice_request_tlvs], # ArrayField[composite] in generate_composite + "warning_missing_invreq_metadata": m.warning_missing_invreq_metadata, # PrimitiveField in generate_composite + "warning_missing_invreq_payer_id": m.warning_missing_invreq_payer_id, # PrimitiveField in generate_composite + "warning_invalid_invreq_payer_note": m.warning_invalid_invreq_payer_note, # PrimitiveField in generate_composite + "warning_missing_invoice_request_signature": m.warning_missing_invoice_request_signature, # PrimitiveField in generate_composite + "warning_invalid_invoice_request_signature": m.warning_invalid_invoice_request_signature, # PrimitiveField in generate_composite + "invoice_paths": [decode_invoice_paths2py(i) for i in m.invoice_paths], # ArrayField[composite] in generate_composite + "invoice_created_at": m.invoice_created_at, # PrimitiveField in generate_composite + "invoice_relative_expiry": m.invoice_relative_expiry, # PrimitiveField in generate_composite + "invoice_payment_hash": hexlify(m.invoice_payment_hash), # PrimitiveField in generate_composite + "invoice_amount_msat": amount2msat(m.invoice_amount_msat), # PrimitiveField in generate_composite + "invoice_fallbacks": [decode_invoice_fallbacks2py(i) for i in m.invoice_fallbacks], # ArrayField[composite] in generate_composite + "invoice_features": hexlify(m.invoice_features), # PrimitiveField in generate_composite + "invoice_node_id": hexlify(m.invoice_node_id), # PrimitiveField in generate_composite + "invoice_recurrence_basetime": m.invoice_recurrence_basetime, # PrimitiveField in generate_composite + "unknown_invoice_tlvs": [decode_unknown_invoice_tlvs2py(i) for i in m.unknown_invoice_tlvs], # ArrayField[composite] in generate_composite + "warning_missing_invoice_paths": m.warning_missing_invoice_paths, # PrimitiveField in generate_composite + "warning_missing_invoice_blindedpay": m.warning_missing_invoice_blindedpay, # PrimitiveField in generate_composite + "warning_missing_invoice_created_at": m.warning_missing_invoice_created_at, # PrimitiveField in generate_composite + "warning_missing_invoice_payment_hash": m.warning_missing_invoice_payment_hash, # PrimitiveField in generate_composite + "warning_missing_invoice_amount": m.warning_missing_invoice_amount, # PrimitiveField in generate_composite + "warning_missing_invoice_recurrence_basetime": m.warning_missing_invoice_recurrence_basetime, # PrimitiveField in generate_composite + "warning_missing_invoice_node_id": m.warning_missing_invoice_node_id, # PrimitiveField in generate_composite + "warning_missing_invoice_signature": m.warning_missing_invoice_signature, # PrimitiveField in generate_composite + "warning_invalid_invoice_signature": m.warning_invalid_invoice_signature, # PrimitiveField in generate_composite + "fallbacks": [decode_fallbacks2py(i) for i in m.fallbacks], # ArrayField[composite] in generate_composite + "created_at": m.created_at, # PrimitiveField in generate_composite + "expiry": m.expiry, # PrimitiveField in generate_composite + "payee": hexlify(m.payee), # PrimitiveField in generate_composite + "payment_hash": hexlify(m.payment_hash), # PrimitiveField in generate_composite + "description_hash": hexlify(m.description_hash), # PrimitiveField in generate_composite + "min_final_cltv_expiry": m.min_final_cltv_expiry, # PrimitiveField in generate_composite + "payment_secret": hexlify(m.payment_secret), # PrimitiveField in generate_composite + "payment_metadata": hexlify(m.payment_metadata), # PrimitiveField in generate_composite + "routes": [decode_routes2py(i) for i in m.routes], # ArrayField[composite] in generate_composite + "extra": [decode_extra2py(i) for i in m.extra], # ArrayField[composite] in generate_composite + "unique_id": m.unique_id, # PrimitiveField in generate_composite + "version": m.version, # PrimitiveField in generate_composite + "string": m.string, # PrimitiveField in generate_composite + "restrictions": [decode_restrictions2py(i) for i in m.restrictions], # ArrayField[composite] in generate_composite + "warning_rune_invalid_utf8": m.warning_rune_invalid_utf8, # PrimitiveField in generate_composite + "hex": hexlify(m.hex), # PrimitiveField in generate_composite + }) + + def disconnect2py(m): return remove_default({ }) +def feerates_perkb_estimates2py(m): + return remove_default({ + "blockcount": m.blockcount, # PrimitiveField in generate_composite + "feerate": m.feerate, # PrimitiveField in generate_composite + "smoothed_feerate": m.smoothed_feerate, # PrimitiveField in generate_composite + }) + + def feerates_perkb2py(m): return remove_default({ "min_acceptable": m.min_acceptable, # PrimitiveField in generate_composite "max_acceptable": m.max_acceptable, # PrimitiveField in generate_composite + "floor": m.floor, # PrimitiveField in generate_composite + "estimates": [feerates_perkb_estimates2py(i) for i in m.estimates], # ArrayField[composite] in generate_composite "opening": m.opening, # PrimitiveField in generate_composite "mutual_close": m.mutual_close, # PrimitiveField in generate_composite "unilateral_close": m.unilateral_close, # PrimitiveField in generate_composite @@ -743,10 +1163,20 @@ def feerates_perkb2py(m): }) +def feerates_perkw_estimates2py(m): + return remove_default({ + "blockcount": m.blockcount, # PrimitiveField in generate_composite + "feerate": m.feerate, # PrimitiveField in generate_composite + "smoothed_feerate": m.smoothed_feerate, # PrimitiveField in generate_composite + }) + + def feerates_perkw2py(m): return remove_default({ "min_acceptable": m.min_acceptable, # PrimitiveField in generate_composite "max_acceptable": m.max_acceptable, # PrimitiveField in generate_composite + "floor": m.floor, # PrimitiveField in generate_composite + "estimates": [feerates_perkw_estimates2py(i) for i in m.estimates], # ArrayField[composite] in generate_composite "opening": m.opening, # PrimitiveField in generate_composite "mutual_close": m.mutual_close, # PrimitiveField in generate_composite "unilateral_close": m.unilateral_close, # PrimitiveField in generate_composite @@ -788,7 +1218,6 @@ def getroute_route2py(m): "id": hexlify(m.id), # PrimitiveField in generate_composite "channel": m.channel, # PrimitiveField in generate_composite "direction": m.direction, # PrimitiveField in generate_composite - "msatoshi": m.msatoshi, # PrimitiveField in generate_composite "amount_msat": amount2msat(m.amount_msat), # PrimitiveField in generate_composite "delay": m.delay, # PrimitiveField in generate_composite "style": str(m.style), # EnumField in generate_composite @@ -851,6 +1280,12 @@ def ping2py(m): }) +def sendcustommsg2py(m): + return remove_default({ + "status": m.status, # PrimitiveField in generate_composite + }) + + def setchannel_channels2py(m): return remove_default({ "peer_id": hexlify(m.peer_id), # PrimitiveField in generate_composite @@ -871,6 +1306,12 @@ def setchannel2py(m): }) +def signinvoice2py(m): + return remove_default({ + "bolt11": m.bolt11, # PrimitiveField in generate_composite + }) + + def signmessage2py(m): return remove_default({ "signature": hexlify(m.signature), # PrimitiveField in generate_composite @@ -882,3 +1323,13 @@ def signmessage2py(m): def stop2py(m): return remove_default({ }) + + +def preapprovekeysend2py(m): + return remove_default({ + }) + + +def preapproveinvoice2py(m): + return remove_default({ + }) diff --git a/contrib/pyln-testing/pyln/testing/node_pb2.py b/contrib/pyln-testing/pyln/testing/node_pb2.py index bef1498d0811..d98f2c54292e 100644 --- a/contrib/pyln-testing/pyln/testing/node_pb2.py +++ b/contrib/pyln-testing/pyln/testing/node_pb2.py @@ -15,7 +15,7 @@ from . import primitives_pb2 as primitives__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nnode.proto\x12\x03\x63ln\x1a\x10primitives.proto\"\x10\n\x0eGetinfoRequest\"\xf4\x04\n\x0fGetinfoResponse\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05\x61lias\x18\x02 \x01(\t\x12\r\n\x05\x63olor\x18\x03 \x01(\x0c\x12\x11\n\tnum_peers\x18\x04 \x01(\r\x12\x1c\n\x14num_pending_channels\x18\x05 \x01(\r\x12\x1b\n\x13num_active_channels\x18\x06 \x01(\r\x12\x1d\n\x15num_inactive_channels\x18\x07 \x01(\r\x12\x0f\n\x07version\x18\x08 \x01(\t\x12\x15\n\rlightning_dir\x18\t \x01(\t\x12\x33\n\x0cour_features\x18\n \x01(\x0b\x32\x18.cln.GetinfoOur_featuresH\x00\x88\x01\x01\x12\x13\n\x0b\x62lockheight\x18\x0b \x01(\r\x12\x0f\n\x07network\x18\x0c \x01(\t\x12$\n\x17msatoshi_fees_collected\x18\x12 \x01(\x04H\x01\x88\x01\x01\x12(\n\x13\x66\x65\x65s_collected_msat\x18\r \x01(\x0b\x32\x0b.cln.Amount\x12$\n\x07\x61\x64\x64ress\x18\x0e \x03(\x0b\x32\x13.cln.GetinfoAddress\x12$\n\x07\x62inding\x18\x0f \x03(\x0b\x32\x13.cln.GetinfoBinding\x12\"\n\x15warning_bitcoind_sync\x18\x10 \x01(\tH\x02\x88\x01\x01\x12$\n\x17warning_lightningd_sync\x18\x11 \x01(\tH\x03\x88\x01\x01\x42\x0f\n\r_our_featuresB\x1a\n\x18_msatoshi_fees_collectedB\x18\n\x16_warning_bitcoind_syncB\x1a\n\x18_warning_lightningd_sync\"S\n\x13GetinfoOur_features\x12\x0c\n\x04init\x18\x01 \x01(\x0c\x12\x0c\n\x04node\x18\x02 \x01(\x0c\x12\x0f\n\x07\x63hannel\x18\x03 \x01(\x0c\x12\x0f\n\x07invoice\x18\x04 \x01(\x0c\"\xd3\x01\n\x0eGetinfoAddress\x12\x39\n\titem_type\x18\x01 \x01(\x0e\x32&.cln.GetinfoAddress.GetinfoAddressType\x12\x0c\n\x04port\x18\x02 \x01(\r\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x00\x88\x01\x01\"V\n\x12GetinfoAddressType\x12\x07\n\x03\x44NS\x10\x00\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x12\r\n\tWEBSOCKET\x10\x05\x42\n\n\x08_address\"\xfb\x01\n\x0eGetinfoBinding\x12\x39\n\titem_type\x18\x01 \x01(\x0e\x32&.cln.GetinfoBinding.GetinfoBindingType\x12\x14\n\x07\x61\x64\x64ress\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x11\n\x04port\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x13\n\x06socket\x18\x04 \x01(\tH\x02\x88\x01\x01\"P\n\x12GetinfoBindingType\x12\x10\n\x0cLOCAL_SOCKET\x10\x00\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x42\n\n\x08_addressB\x07\n\x05_portB\t\n\x07_socket\"H\n\x10ListpeersRequest\x12\x0f\n\x02id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x12\n\x05level\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x05\n\x03_idB\x08\n\x06_level\"7\n\x11ListpeersResponse\x12\"\n\x05peers\x18\x01 \x03(\x0b\x32\x13.cln.ListpeersPeers\"\xe2\x01\n\x0eListpeersPeers\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x11\n\tconnected\x18\x02 \x01(\x08\x12#\n\x03log\x18\x03 \x03(\x0b\x32\x16.cln.ListpeersPeersLog\x12-\n\x08\x63hannels\x18\x04 \x03(\x0b\x32\x1b.cln.ListpeersPeersChannels\x12\x0f\n\x07netaddr\x18\x05 \x03(\t\x12\x18\n\x0bremote_addr\x18\x07 \x01(\tH\x00\x88\x01\x01\x12\x15\n\x08\x66\x65\x61tures\x18\x06 \x01(\x0cH\x01\x88\x01\x01\x42\x0e\n\x0c_remote_addrB\x0b\n\t_features\"\xfd\x02\n\x11ListpeersPeersLog\x12?\n\titem_type\x18\x01 \x01(\x0e\x32,.cln.ListpeersPeersLog.ListpeersPeersLogType\x12\x18\n\x0bnum_skipped\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x11\n\x04time\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x13\n\x06source\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x10\n\x03log\x18\x05 \x01(\tH\x03\x88\x01\x01\x12\x14\n\x07node_id\x18\x06 \x01(\x0cH\x04\x88\x01\x01\x12\x11\n\x04\x64\x61ta\x18\x07 \x01(\x0cH\x05\x88\x01\x01\"i\n\x15ListpeersPeersLogType\x12\x0b\n\x07SKIPPED\x10\x00\x12\n\n\x06\x42ROKEN\x10\x01\x12\x0b\n\x07UNUSUAL\x10\x02\x12\x08\n\x04INFO\x10\x03\x12\t\n\x05\x44\x45\x42UG\x10\x04\x12\t\n\x05IO_IN\x10\x05\x12\n\n\x06IO_OUT\x10\x06\x42\x0e\n\x0c_num_skippedB\x07\n\x05_timeB\t\n\x07_sourceB\x06\n\x04_logB\n\n\x08_node_idB\x07\n\x05_data\"\xd6\x17\n\x16ListpeersPeersChannels\x12\x46\n\x05state\x18\x01 \x01(\x0e\x32\x37.cln.ListpeersPeersChannels.ListpeersPeersChannelsState\x12\x19\n\x0cscratch_txid\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x38\n\x07\x66\x65\x65rate\x18\x03 \x01(\x0b\x32\".cln.ListpeersPeersChannelsFeerateH\x01\x88\x01\x01\x12\x12\n\x05owner\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x1d\n\x10short_channel_id\x18\x05 \x01(\tH\x03\x88\x01\x01\x12\x17\n\nchannel_id\x18\x06 \x01(\x0cH\x04\x88\x01\x01\x12\x19\n\x0c\x66unding_txid\x18\x07 \x01(\x0cH\x05\x88\x01\x01\x12\x1b\n\x0e\x66unding_outnum\x18\x08 \x01(\rH\x06\x88\x01\x01\x12\x1c\n\x0finitial_feerate\x18\t \x01(\tH\x07\x88\x01\x01\x12\x19\n\x0clast_feerate\x18\n \x01(\tH\x08\x88\x01\x01\x12\x19\n\x0cnext_feerate\x18\x0b \x01(\tH\t\x88\x01\x01\x12\x1a\n\rnext_fee_step\x18\x0c \x01(\rH\n\x88\x01\x01\x12\x35\n\x08inflight\x18\r \x03(\x0b\x32#.cln.ListpeersPeersChannelsInflight\x12\x15\n\x08\x63lose_to\x18\x0e \x01(\x0cH\x0b\x88\x01\x01\x12\x14\n\x07private\x18\x0f \x01(\x08H\x0c\x88\x01\x01\x12 \n\x06opener\x18\x10 \x01(\x0e\x32\x10.cln.ChannelSide\x12%\n\x06\x63loser\x18\x11 \x01(\x0e\x32\x10.cln.ChannelSideH\r\x88\x01\x01\x12\x10\n\x08\x66\x65\x61tures\x18\x12 \x03(\t\x12\x38\n\x07\x66unding\x18\x13 \x01(\x0b\x32\".cln.ListpeersPeersChannelsFundingH\x0e\x88\x01\x01\x12$\n\nto_us_msat\x18\x14 \x01(\x0b\x32\x0b.cln.AmountH\x0f\x88\x01\x01\x12(\n\x0emin_to_us_msat\x18\x15 \x01(\x0b\x32\x0b.cln.AmountH\x10\x88\x01\x01\x12(\n\x0emax_to_us_msat\x18\x16 \x01(\x0b\x32\x0b.cln.AmountH\x11\x88\x01\x01\x12$\n\ntotal_msat\x18\x17 \x01(\x0b\x32\x0b.cln.AmountH\x12\x88\x01\x01\x12\'\n\rfee_base_msat\x18\x18 \x01(\x0b\x32\x0b.cln.AmountH\x13\x88\x01\x01\x12(\n\x1b\x66\x65\x65_proportional_millionths\x18\x19 \x01(\rH\x14\x88\x01\x01\x12)\n\x0f\x64ust_limit_msat\x18\x1a \x01(\x0b\x32\x0b.cln.AmountH\x15\x88\x01\x01\x12\x30\n\x16max_total_htlc_in_msat\x18\x1b \x01(\x0b\x32\x0b.cln.AmountH\x16\x88\x01\x01\x12,\n\x12their_reserve_msat\x18\x1c \x01(\x0b\x32\x0b.cln.AmountH\x17\x88\x01\x01\x12*\n\x10our_reserve_msat\x18\x1d \x01(\x0b\x32\x0b.cln.AmountH\x18\x88\x01\x01\x12(\n\x0espendable_msat\x18\x1e \x01(\x0b\x32\x0b.cln.AmountH\x19\x88\x01\x01\x12)\n\x0freceivable_msat\x18\x1f \x01(\x0b\x32\x0b.cln.AmountH\x1a\x88\x01\x01\x12.\n\x14minimum_htlc_in_msat\x18 \x01(\x0b\x32\x0b.cln.AmountH\x1b\x88\x01\x01\x12/\n\x15minimum_htlc_out_msat\x18\x30 \x01(\x0b\x32\x0b.cln.AmountH\x1c\x88\x01\x01\x12/\n\x15maximum_htlc_out_msat\x18\x31 \x01(\x0b\x32\x0b.cln.AmountH\x1d\x88\x01\x01\x12 \n\x13their_to_self_delay\x18! \x01(\rH\x1e\x88\x01\x01\x12\x1e\n\x11our_to_self_delay\x18\" \x01(\rH\x1f\x88\x01\x01\x12\x1f\n\x12max_accepted_htlcs\x18# \x01(\rH \x88\x01\x01\x12\x34\n\x05\x61lias\x18\x32 \x01(\x0b\x32 .cln.ListpeersPeersChannelsAliasH!\x88\x01\x01\x12\x0e\n\x06status\x18% \x03(\t\x12 \n\x13in_payments_offered\x18& \x01(\x04H\"\x88\x01\x01\x12)\n\x0fin_offered_msat\x18\' \x01(\x0b\x32\x0b.cln.AmountH#\x88\x01\x01\x12\"\n\x15in_payments_fulfilled\x18( \x01(\x04H$\x88\x01\x01\x12+\n\x11in_fulfilled_msat\x18) \x01(\x0b\x32\x0b.cln.AmountH%\x88\x01\x01\x12!\n\x14out_payments_offered\x18* \x01(\x04H&\x88\x01\x01\x12*\n\x10out_offered_msat\x18+ \x01(\x0b\x32\x0b.cln.AmountH\'\x88\x01\x01\x12#\n\x16out_payments_fulfilled\x18, \x01(\x04H(\x88\x01\x01\x12,\n\x12out_fulfilled_msat\x18- \x01(\x0b\x32\x0b.cln.AmountH)\x88\x01\x01\x12/\n\x05htlcs\x18. \x03(\x0b\x32 .cln.ListpeersPeersChannelsHtlcs\x12\x1a\n\rclose_to_addr\x18/ \x01(\tH*\x88\x01\x01\"\xa1\x02\n\x1bListpeersPeersChannelsState\x12\x0c\n\x08OPENINGD\x10\x00\x12\x1c\n\x18\x43HANNELD_AWAITING_LOCKIN\x10\x01\x12\x13\n\x0f\x43HANNELD_NORMAL\x10\x02\x12\x1a\n\x16\x43HANNELD_SHUTTING_DOWN\x10\x03\x12\x18\n\x14\x43LOSINGD_SIGEXCHANGE\x10\x04\x12\x15\n\x11\x43LOSINGD_COMPLETE\x10\x05\x12\x17\n\x13\x41WAITING_UNILATERAL\x10\x06\x12\x16\n\x12\x46UNDING_SPEND_SEEN\x10\x07\x12\x0b\n\x07ONCHAIN\x10\x08\x12\x17\n\x13\x44UALOPEND_OPEN_INIT\x10\t\x12\x1d\n\x19\x44UALOPEND_AWAITING_LOCKIN\x10\nB\x0f\n\r_scratch_txidB\n\n\x08_feerateB\x08\n\x06_ownerB\x13\n\x11_short_channel_idB\r\n\x0b_channel_idB\x0f\n\r_funding_txidB\x11\n\x0f_funding_outnumB\x12\n\x10_initial_feerateB\x0f\n\r_last_feerateB\x0f\n\r_next_feerateB\x10\n\x0e_next_fee_stepB\x0b\n\t_close_toB\n\n\x08_privateB\t\n\x07_closerB\n\n\x08_fundingB\r\n\x0b_to_us_msatB\x11\n\x0f_min_to_us_msatB\x11\n\x0f_max_to_us_msatB\r\n\x0b_total_msatB\x10\n\x0e_fee_base_msatB\x1e\n\x1c_fee_proportional_millionthsB\x12\n\x10_dust_limit_msatB\x19\n\x17_max_total_htlc_in_msatB\x15\n\x13_their_reserve_msatB\x13\n\x11_our_reserve_msatB\x11\n\x0f_spendable_msatB\x12\n\x10_receivable_msatB\x17\n\x15_minimum_htlc_in_msatB\x18\n\x16_minimum_htlc_out_msatB\x18\n\x16_maximum_htlc_out_msatB\x16\n\x14_their_to_self_delayB\x14\n\x12_our_to_self_delayB\x15\n\x13_max_accepted_htlcsB\x08\n\x06_aliasB\x16\n\x14_in_payments_offeredB\x12\n\x10_in_offered_msatB\x18\n\x16_in_payments_fulfilledB\x14\n\x12_in_fulfilled_msatB\x17\n\x15_out_payments_offeredB\x13\n\x11_out_offered_msatB\x19\n\x17_out_payments_fulfilledB\x15\n\x13_out_fulfilled_msatB\x10\n\x0e_close_to_addr\"=\n\x1dListpeersPeersChannelsFeerate\x12\r\n\x05perkw\x18\x01 \x01(\r\x12\r\n\x05perkb\x18\x02 \x01(\r\"\xc5\x01\n\x1eListpeersPeersChannelsInflight\x12\x14\n\x0c\x66unding_txid\x18\x01 \x01(\x0c\x12\x16\n\x0e\x66unding_outnum\x18\x02 \x01(\r\x12\x0f\n\x07\x66\x65\x65rate\x18\x03 \x01(\t\x12\'\n\x12total_funding_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10our_funding_msat\x18\x05 \x01(\x0b\x32\x0b.cln.Amount\x12\x14\n\x0cscratch_txid\x18\x06 \x01(\x0c\"\x87\x03\n\x1dListpeersPeersChannelsFunding\x12$\n\nlocal_msat\x18\x01 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12%\n\x0bremote_msat\x18\x02 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12%\n\x0bpushed_msat\x18\x03 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12%\n\x10local_funds_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12&\n\x11remote_funds_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\'\n\rfee_paid_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\'\n\rfee_rcvd_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x42\r\n\x0b_local_msatB\x0e\n\x0c_remote_msatB\x0e\n\x0c_pushed_msatB\x10\n\x0e_fee_paid_msatB\x10\n\x0e_fee_rcvd_msat\"[\n\x1bListpeersPeersChannelsAlias\x12\x12\n\x05local\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06remote\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_localB\t\n\x07_remote\"\xd2\x02\n\x1bListpeersPeersChannelsHtlcs\x12X\n\tdirection\x18\x01 \x01(\x0e\x32\x45.cln.ListpeersPeersChannelsHtlcs.ListpeersPeersChannelsHtlcsDirection\x12\n\n\x02id\x18\x02 \x01(\x04\x12 \n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.Amount\x12\x0e\n\x06\x65xpiry\x18\x04 \x01(\r\x12\x14\n\x0cpayment_hash\x18\x05 \x01(\x0c\x12\x1a\n\rlocal_trimmed\x18\x06 \x01(\x08H\x00\x88\x01\x01\x12\x13\n\x06status\x18\x07 \x01(\tH\x01\x88\x01\x01\"7\n$ListpeersPeersChannelsHtlcsDirection\x12\x06\n\x02IN\x10\x00\x12\x07\n\x03OUT\x10\x01\x42\x10\n\x0e_local_trimmedB\t\n\x07_status\"0\n\x10ListfundsRequest\x12\x12\n\x05spent\x18\x01 \x01(\x08H\x00\x88\x01\x01\x42\x08\n\x06_spent\"e\n\x11ListfundsResponse\x12&\n\x07outputs\x18\x01 \x03(\x0b\x32\x15.cln.ListfundsOutputs\x12(\n\x08\x63hannels\x18\x02 \x03(\x0b\x32\x16.cln.ListfundsChannels\"\x83\x03\n\x10ListfundsOutputs\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\x0e\n\x06output\x18\x02 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.Amount\x12\x14\n\x0cscriptpubkey\x18\x04 \x01(\x0c\x12\x14\n\x07\x61\x64\x64ress\x18\x05 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0credeemscript\x18\x06 \x01(\x0cH\x01\x88\x01\x01\x12<\n\x06status\x18\x07 \x01(\x0e\x32,.cln.ListfundsOutputs.ListfundsOutputsStatus\x12\x10\n\x08reserved\x18\t \x01(\x08\x12\x18\n\x0b\x62lockheight\x18\x08 \x01(\rH\x02\x88\x01\x01\"Q\n\x16ListfundsOutputsStatus\x12\x0f\n\x0bUNCONFIRMED\x10\x00\x12\r\n\tCONFIRMED\x10\x01\x12\t\n\x05SPENT\x10\x02\x12\x0c\n\x08IMMATURE\x10\x03\x42\n\n\x08_addressB\x0f\n\r_redeemscriptB\x0e\n\x0c_blockheight\"\x83\x02\n\x11ListfundsChannels\x12\x0f\n\x07peer_id\x18\x01 \x01(\x0c\x12$\n\x0four_amount_msat\x18\x02 \x01(\x0b\x32\x0b.cln.Amount\x12 \n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.Amount\x12\x14\n\x0c\x66unding_txid\x18\x04 \x01(\x0c\x12\x16\n\x0e\x66unding_output\x18\x05 \x01(\r\x12\x11\n\tconnected\x18\x06 \x01(\x08\x12 \n\x05state\x18\x07 \x01(\x0e\x32\x11.cln.ChannelState\x12\x1d\n\x10short_channel_id\x18\x08 \x01(\tH\x00\x88\x01\x01\x42\x13\n\x11_short_channel_id\"\xdd\x02\n\x0eSendpayRequest\x12 \n\x05route\x18\x01 \x03(\x0b\x32\x11.cln.SendpayRoute\x12\x14\n\x0cpayment_hash\x18\x02 \x01(\x0c\x12\x12\n\x05label\x18\x03 \x01(\tH\x00\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x05 \x01(\tH\x02\x88\x01\x01\x12\x1b\n\x0epayment_secret\x18\x06 \x01(\x0cH\x03\x88\x01\x01\x12\x13\n\x06partid\x18\x07 \x01(\rH\x04\x88\x01\x01\x12\x1a\n\rlocalinvreqid\x18\x0b \x01(\x0cH\x05\x88\x01\x01\x12\x14\n\x07groupid\x18\t \x01(\x04H\x06\x88\x01\x01\x42\x08\n\x06_labelB\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\x11\n\x0f_payment_secretB\t\n\x07_partidB\x10\n\x0e_localinvreqidB\n\n\x08_groupid\"\xd1\x04\n\x0fSendpayResponse\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x14\n\x07groupid\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x32\n\x06status\x18\x04 \x01(\x0e\x32\".cln.SendpayResponse.SendpayStatus\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x06 \x01(\x0cH\x02\x88\x01\x01\x12\x12\n\ncreated_at\x18\x07 \x01(\x04\x12\x19\n\x0c\x63ompleted_at\x18\x0f \x01(\x04H\x03\x88\x01\x01\x12%\n\x10\x61mount_sent_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\t \x01(\tH\x04\x88\x01\x01\x12\x13\n\x06partid\x18\n \x01(\x04H\x05\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x0b \x01(\tH\x06\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x0c \x01(\tH\x07\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\r \x01(\x0cH\x08\x88\x01\x01\x12\x14\n\x07message\x18\x0e \x01(\tH\t\x88\x01\x01\"*\n\rSendpayStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x42\n\n\x08_groupidB\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x0f\n\r_completed_atB\x08\n\x06_labelB\t\n\x07_partidB\t\n\x07_bolt11B\t\n\x07_bolt12B\x13\n\x11_payment_preimageB\n\n\x08_message\"\\\n\x0cSendpayRoute\x12 \n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.Amount\x12\n\n\x02id\x18\x02 \x01(\x0c\x12\r\n\x05\x64\x65lay\x18\x03 \x01(\r\x12\x0f\n\x07\x63hannel\x18\x04 \x01(\t\"\x93\x01\n\x13ListchannelsRequest\x12\x1d\n\x10short_channel_id\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06source\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x03 \x01(\x0cH\x02\x88\x01\x01\x42\x13\n\x11_short_channel_idB\t\n\x07_sourceB\x0e\n\x0c_destination\"C\n\x14ListchannelsResponse\x12+\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x19.cln.ListchannelsChannels\"\xa0\x03\n\x14ListchannelsChannels\x12\x0e\n\x06source\x18\x01 \x01(\x0c\x12\x13\n\x0b\x64\x65stination\x18\x02 \x01(\x0c\x12\x18\n\x10short_channel_id\x18\x03 \x01(\t\x12\x0e\n\x06public\x18\x04 \x01(\x08\x12 \n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.Amount\x12\x15\n\rmessage_flags\x18\x06 \x01(\r\x12\x15\n\rchannel_flags\x18\x07 \x01(\r\x12\x0e\n\x06\x61\x63tive\x18\x08 \x01(\x08\x12\x13\n\x0blast_update\x18\t \x01(\r\x12\x1d\n\x15\x62\x61se_fee_millisatoshi\x18\n \x01(\r\x12\x19\n\x11\x66\x65\x65_per_millionth\x18\x0b \x01(\r\x12\r\n\x05\x64\x65lay\x18\x0c \x01(\r\x12&\n\x11htlc_minimum_msat\x18\r \x01(\x0b\x32\x0b.cln.Amount\x12+\n\x11htlc_maximum_msat\x18\x0e \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x10\n\x08\x66\x65\x61tures\x18\x0f \x01(\x0c\x42\x14\n\x12_htlc_maximum_msat\"#\n\x10\x41\x64\x64gossipRequest\x12\x0f\n\x07message\x18\x01 \x01(\x0c\"\x13\n\x11\x41\x64\x64gossipResponse\"o\n\x17\x41utocleaninvoiceRequest\x12\x17\n\nexpired_by\x18\x01 \x01(\x04H\x00\x88\x01\x01\x12\x1a\n\rcycle_seconds\x18\x02 \x01(\x04H\x01\x88\x01\x01\x42\r\n\x0b_expired_byB\x10\n\x0e_cycle_seconds\"\x81\x01\n\x18\x41utocleaninvoiceResponse\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\x12\x17\n\nexpired_by\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x1a\n\rcycle_seconds\x18\x03 \x01(\x04H\x01\x88\x01\x01\x42\r\n\x0b_expired_byB\x10\n\x0e_cycle_seconds\"U\n\x13\x43heckmessageRequest\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\r\n\x05zbase\x18\x02 \x01(\t\x12\x13\n\x06pubkey\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x42\t\n\x07_pubkey\"8\n\x14\x43heckmessageResponse\x12\x10\n\x08verified\x18\x01 \x01(\x08\x12\x0e\n\x06pubkey\x18\x02 \x01(\x0c\"\xcb\x02\n\x0c\x43loseRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\x1e\n\x11unilateraltimeout\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x03 \x01(\tH\x01\x88\x01\x01\x12!\n\x14\x66\x65\x65_negotiation_step\x18\x04 \x01(\tH\x02\x88\x01\x01\x12)\n\rwrong_funding\x18\x05 \x01(\x0b\x32\r.cln.OutpointH\x03\x88\x01\x01\x12\x1f\n\x12\x66orce_lease_closed\x18\x06 \x01(\x08H\x04\x88\x01\x01\x12\x1e\n\x08\x66\x65\x65range\x18\x07 \x03(\x0b\x32\x0c.cln.FeerateB\x14\n\x12_unilateraltimeoutB\x0e\n\x0c_destinationB\x17\n\x15_fee_negotiation_stepB\x10\n\x0e_wrong_fundingB\x15\n\x13_force_lease_closed\"\xab\x01\n\rCloseResponse\x12/\n\titem_type\x18\x01 \x01(\x0e\x32\x1c.cln.CloseResponse.CloseType\x12\x0f\n\x02tx\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x11\n\x04txid\x18\x03 \x01(\x0cH\x01\x88\x01\x01\"5\n\tCloseType\x12\n\n\x06MUTUAL\x10\x00\x12\x0e\n\nUNILATERAL\x10\x01\x12\x0c\n\x08UNOPENED\x10\x02\x42\x05\n\x03_txB\x07\n\x05_txid\"T\n\x0e\x43onnectRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\x11\n\x04host\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x11\n\x04port\x18\x03 \x01(\rH\x01\x88\x01\x01\x42\x07\n\x05_hostB\x07\n\x05_port\"\xb4\x01\n\x0f\x43onnectResponse\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x10\n\x08\x66\x65\x61tures\x18\x02 \x01(\x0c\x12\x38\n\tdirection\x18\x03 \x01(\x0e\x32%.cln.ConnectResponse.ConnectDirection\x12$\n\x07\x61\x64\x64ress\x18\x04 \x01(\x0b\x32\x13.cln.ConnectAddress\"#\n\x10\x43onnectDirection\x12\x06\n\x02IN\x10\x00\x12\x07\n\x03OUT\x10\x01\"\xfb\x01\n\x0e\x43onnectAddress\x12\x39\n\titem_type\x18\x01 \x01(\x0e\x32&.cln.ConnectAddress.ConnectAddressType\x12\x13\n\x06socket\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x11\n\x04port\x18\x04 \x01(\rH\x02\x88\x01\x01\"P\n\x12\x43onnectAddressType\x12\x10\n\x0cLOCAL_SOCKET\x10\x00\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x42\t\n\x07_socketB\n\n\x08_addressB\x07\n\x05_port\"J\n\x14\x43reateinvoiceRequest\x12\x11\n\tinvstring\x18\x01 \x01(\t\x12\r\n\x05label\x18\x02 \x01(\t\x12\x10\n\x08preimage\x18\x03 \x01(\x0c\"\x81\x05\n\x15\x43reateinvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x06\x62olt11\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x04 \x01(\x0c\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12>\n\x06status\x18\x06 \x01(\x0e\x32..cln.CreateinvoiceResponse.CreateinvoiceStatus\x12\x13\n\x0b\x64\x65scription\x18\x07 \x01(\t\x12\x12\n\nexpires_at\x18\x08 \x01(\x04\x12\x16\n\tpay_index\x18\t \x01(\x04H\x03\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12\x14\n\x07paid_at\x18\x0b \x01(\x04H\x05\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\x06\x88\x01\x01\x12\x1b\n\x0elocal_offer_id\x18\r \x01(\x0cH\x07\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x0f \x01(\tH\x08\x88\x01\x01\"8\n\x13\x43reateinvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x12\n\n\x06UNPAID\x10\x02\x42\t\n\x07_bolt11B\t\n\x07_bolt12B\x0e\n\x0c_amount_msatB\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x13\n\x11_payment_preimageB\x11\n\x0f_local_offer_idB\x14\n\x12_invreq_payer_note\"\xb4\x02\n\x10\x44\x61tastoreRequest\x12\x0b\n\x03key\x18\x05 \x03(\t\x12\x13\n\x06string\x18\x06 \x01(\tH\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12\x36\n\x04mode\x18\x03 \x01(\x0e\x32#.cln.DatastoreRequest.DatastoreModeH\x02\x88\x01\x01\x12\x17\n\ngeneration\x18\x04 \x01(\x04H\x03\x88\x01\x01\"p\n\rDatastoreMode\x12\x0f\n\x0bMUST_CREATE\x10\x00\x12\x10\n\x0cMUST_REPLACE\x10\x01\x12\x15\n\x11\x43REATE_OR_REPLACE\x10\x02\x12\x0f\n\x0bMUST_APPEND\x10\x03\x12\x14\n\x10\x43REATE_OR_APPEND\x10\x04\x42\t\n\x07_stringB\x06\n\x04_hexB\x07\n\x05_modeB\r\n\x0b_generation\"\x82\x01\n\x11\x44\x61tastoreResponse\x12\x0b\n\x03key\x18\x05 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x06string\x18\x04 \x01(\tH\x02\x88\x01\x01\x42\r\n\x0b_generationB\x06\n\x04_hexB\t\n\x07_string\"\x9d\x01\n\x12\x43reateonionRequest\x12\"\n\x04hops\x18\x01 \x03(\x0b\x32\x14.cln.CreateonionHops\x12\x11\n\tassocdata\x18\x02 \x01(\x0c\x12\x18\n\x0bsession_key\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x12\x17\n\nonion_size\x18\x04 \x01(\rH\x01\x88\x01\x01\x42\x0e\n\x0c_session_keyB\r\n\x0b_onion_size\"<\n\x13\x43reateonionResponse\x12\r\n\x05onion\x18\x01 \x01(\x0c\x12\x16\n\x0eshared_secrets\x18\x02 \x03(\x0c\"2\n\x0f\x43reateonionHops\x12\x0e\n\x06pubkey\x18\x01 \x01(\x0c\x12\x0f\n\x07payload\x18\x02 \x01(\x0c\"J\n\x13\x44\x65ldatastoreRequest\x12\x0b\n\x03key\x18\x03 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\r\n\x0b_generation\"\x85\x01\n\x14\x44\x65ldatastoreResponse\x12\x0b\n\x03key\x18\x05 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x06string\x18\x04 \x01(\tH\x02\x88\x01\x01\x42\r\n\x0b_generationB\x06\n\x04_hexB\t\n\x07_string\"H\n\x18\x44\x65lexpiredinvoiceRequest\x12\x1a\n\rmaxexpirytime\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\x10\n\x0e_maxexpirytime\"\x1b\n\x19\x44\x65lexpiredinvoiceResponse\"\xb6\x01\n\x11\x44\x65linvoiceRequest\x12\r\n\x05label\x18\x01 \x01(\t\x12\x37\n\x06status\x18\x02 \x01(\x0e\x32\'.cln.DelinvoiceRequest.DelinvoiceStatus\x12\x15\n\x08\x64\x65sconly\x18\x03 \x01(\x08H\x00\x88\x01\x01\"5\n\x10\x44\x65linvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x12\n\n\x06UNPAID\x10\x02\x42\x0b\n\t_desconly\"\xc5\x03\n\x12\x44\x65linvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x06\x62olt11\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x03 \x01(\tH\x01\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x05 \x01(\tH\x03\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x06 \x01(\x0c\x12\x38\n\x06status\x18\x07 \x01(\x0e\x32(.cln.DelinvoiceResponse.DelinvoiceStatus\x12\x12\n\nexpires_at\x18\x08 \x01(\x04\x12\x1b\n\x0elocal_offer_id\x18\t \x01(\x0cH\x04\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x0b \x01(\tH\x05\x88\x01\x01\"5\n\x10\x44\x65linvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x12\n\n\x06UNPAID\x10\x02\x42\t\n\x07_bolt11B\t\n\x07_bolt12B\x0e\n\x0c_amount_msatB\x0e\n\x0c_descriptionB\x11\n\x0f_local_offer_idB\x14\n\x12_invreq_payer_note\"\xb8\x02\n\x0eInvoiceRequest\x12%\n\x0b\x61mount_msat\x18\n \x01(\x0b\x32\x10.cln.AmountOrAny\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\r\n\x05label\x18\x03 \x01(\t\x12\x13\n\x06\x65xpiry\x18\x07 \x01(\x04H\x00\x88\x01\x01\x12\x11\n\tfallbacks\x18\x04 \x03(\t\x12\x15\n\x08preimage\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\"\n\x15\x65xposeprivatechannels\x18\x08 \x01(\x08H\x02\x88\x01\x01\x12\x11\n\x04\x63ltv\x18\x06 \x01(\rH\x03\x88\x01\x01\x12\x19\n\x0c\x64\x65schashonly\x18\t \x01(\x08H\x04\x88\x01\x01\x42\t\n\x07_expiryB\x0b\n\t_preimageB\x18\n\x16_exposeprivatechannelsB\x07\n\x05_cltvB\x0f\n\r_deschashonly\"\xe7\x02\n\x0fInvoiceResponse\x12\x0e\n\x06\x62olt11\x18\x01 \x01(\t\x12\x14\n\x0cpayment_hash\x18\x02 \x01(\x0c\x12\x16\n\x0epayment_secret\x18\x03 \x01(\x0c\x12\x12\n\nexpires_at\x18\x04 \x01(\x04\x12\x1d\n\x10warning_capacity\x18\x05 \x01(\tH\x00\x88\x01\x01\x12\x1c\n\x0fwarning_offline\x18\x06 \x01(\tH\x01\x88\x01\x01\x12\x1d\n\x10warning_deadends\x18\x07 \x01(\tH\x02\x88\x01\x01\x12#\n\x16warning_private_unused\x18\x08 \x01(\tH\x03\x88\x01\x01\x12\x18\n\x0bwarning_mpp\x18\t \x01(\tH\x04\x88\x01\x01\x42\x13\n\x11_warning_capacityB\x12\n\x10_warning_offlineB\x13\n\x11_warning_deadendsB\x19\n\x17_warning_private_unusedB\x0e\n\x0c_warning_mpp\"#\n\x14ListdatastoreRequest\x12\x0b\n\x03key\x18\x02 \x03(\t\"G\n\x15ListdatastoreResponse\x12.\n\tdatastore\x18\x01 \x03(\x0b\x32\x1b.cln.ListdatastoreDatastore\"\x87\x01\n\x16ListdatastoreDatastore\x12\x0b\n\x03key\x18\x01 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x06string\x18\x04 \x01(\tH\x02\x88\x01\x01\x42\r\n\x0b_generationB\x06\n\x04_hexB\t\n\x07_string\"\xa9\x01\n\x13ListinvoicesRequest\x12\x12\n\x05label\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tinvstring\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x03 \x01(\x0cH\x02\x88\x01\x01\x12\x15\n\x08offer_id\x18\x04 \x01(\tH\x03\x88\x01\x01\x42\x08\n\x06_labelB\x0c\n\n_invstringB\x0f\n\r_payment_hashB\x0b\n\t_offer_id\"C\n\x14ListinvoicesResponse\x12+\n\x08invoices\x18\x01 \x03(\x0b\x32\x19.cln.ListinvoicesInvoices\"\xa2\x05\n\x14ListinvoicesInvoices\x12\r\n\x05label\x18\x01 \x01(\t\x12\x18\n\x0b\x64\x65scription\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x44\n\x06status\x18\x04 \x01(\x0e\x32\x34.cln.ListinvoicesInvoices.ListinvoicesInvoicesStatus\x12\x12\n\nexpires_at\x18\x05 \x01(\x04\x12%\n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x02\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x08 \x01(\tH\x03\x88\x01\x01\x12\x1b\n\x0elocal_offer_id\x18\t \x01(\x0cH\x04\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x0f \x01(\tH\x05\x88\x01\x01\x12\x16\n\tpay_index\x18\x0b \x01(\x04H\x06\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\x0c \x01(\x0b\x32\x0b.cln.AmountH\x07\x88\x01\x01\x12\x14\n\x07paid_at\x18\r \x01(\x04H\x08\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0e \x01(\x0cH\t\x88\x01\x01\"?\n\x1aListinvoicesInvoicesStatus\x12\n\n\x06UNPAID\x10\x00\x12\x08\n\x04PAID\x10\x01\x12\x0b\n\x07\x45XPIRED\x10\x02\x42\x0e\n\x0c_descriptionB\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\t\n\x07_bolt12B\x11\n\x0f_local_offer_idB\x14\n\x12_invreq_payer_noteB\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x13\n\x11_payment_preimage\"\x8a\x03\n\x10SendonionRequest\x12\r\n\x05onion\x18\x01 \x01(\x0c\x12*\n\tfirst_hop\x18\x02 \x01(\x0b\x32\x17.cln.SendonionFirst_hop\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x12\n\x05label\x18\x04 \x01(\tH\x00\x88\x01\x01\x12\x16\n\x0eshared_secrets\x18\x05 \x03(\x0c\x12\x13\n\x06partid\x18\x06 \x01(\rH\x01\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x02\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x0c \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\t \x01(\x0cH\x04\x88\x01\x01\x12\x1a\n\rlocalinvreqid\x18\r \x01(\x0cH\x05\x88\x01\x01\x12\x14\n\x07groupid\x18\x0b \x01(\x04H\x06\x88\x01\x01\x42\x08\n\x06_labelB\t\n\x07_partidB\t\n\x07_bolt11B\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x10\n\x0e_localinvreqidB\n\n\x08_groupid\"\x8b\x04\n\x11SendonionResponse\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x14\n\x0cpayment_hash\x18\x02 \x01(\x0c\x12\x36\n\x06status\x18\x03 \x01(\x0e\x32&.cln.SendonionResponse.SendonionStatus\x12%\n\x0b\x61mount_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\x12\n\ncreated_at\x18\x06 \x01(\x04\x12%\n\x10\x61mount_sent_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\x08 \x01(\tH\x02\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\t \x01(\tH\x03\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\n \x01(\tH\x04\x88\x01\x01\x12\x13\n\x06partid\x18\r \x01(\x04H\x05\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0b \x01(\x0cH\x06\x88\x01\x01\x12\x14\n\x07message\x18\x0c \x01(\tH\x07\x88\x01\x01\",\n\x0fSendonionStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x42\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x08\n\x06_labelB\t\n\x07_bolt11B\t\n\x07_bolt12B\t\n\x07_partidB\x13\n\x11_payment_preimageB\n\n\x08_message\"Q\n\x12SendonionFirst_hop\x12\n\n\x02id\x18\x01 \x01(\x0c\x12 \n\x0b\x61mount_msat\x18\x02 \x01(\x0b\x32\x0b.cln.Amount\x12\r\n\x05\x64\x65lay\x18\x03 \x01(\r\"\xeb\x01\n\x13ListsendpaysRequest\x12\x13\n\x06\x62olt11\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12@\n\x06status\x18\x03 \x01(\x0e\x32+.cln.ListsendpaysRequest.ListsendpaysStatusH\x02\x88\x01\x01\";\n\x12ListsendpaysStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x42\t\n\x07_bolt11B\x0f\n\r_payment_hashB\t\n\x07_status\"C\n\x14ListsendpaysResponse\x12+\n\x08payments\x18\x01 \x03(\x0b\x32\x19.cln.ListsendpaysPayments\"\xd4\x04\n\x14ListsendpaysPayments\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x0f\n\x07groupid\x18\x02 \x01(\x04\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x44\n\x06status\x18\x04 \x01(\x0e\x32\x34.cln.ListsendpaysPayments.ListsendpaysPaymentsStatus\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x06 \x01(\x0cH\x01\x88\x01\x01\x12\x12\n\ncreated_at\x18\x07 \x01(\x04\x12%\n\x10\x61mount_sent_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\t \x01(\tH\x02\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\n \x01(\tH\x03\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x0e \x01(\tH\x04\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x0b \x01(\tH\x05\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\x06\x88\x01\x01\x12\x17\n\nerroronion\x18\r \x01(\x0cH\x07\x88\x01\x01\"C\n\x1aListsendpaysPaymentsStatus\x12\x0b\n\x07PENDING\x10\x00\x12\n\n\x06\x46\x41ILED\x10\x01\x12\x0c\n\x08\x43OMPLETE\x10\x02\x42\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x08\n\x06_labelB\t\n\x07_bolt11B\x0e\n\x0c_descriptionB\t\n\x07_bolt12B\x13\n\x11_payment_preimageB\r\n\x0b_erroronion\"\x19\n\x17ListtransactionsRequest\"S\n\x18ListtransactionsResponse\x12\x37\n\x0ctransactions\x18\x01 \x03(\x0b\x32!.cln.ListtransactionsTransactions\"\x9a\x02\n\x1cListtransactionsTransactions\x12\x0c\n\x04hash\x18\x01 \x01(\x0c\x12\r\n\x05rawtx\x18\x02 \x01(\x0c\x12\x13\n\x0b\x62lockheight\x18\x03 \x01(\r\x12\x0f\n\x07txindex\x18\x04 \x01(\r\x12\x14\n\x07\x63hannel\x18\x06 \x01(\tH\x00\x88\x01\x01\x12\x10\n\x08locktime\x18\x07 \x01(\r\x12\x0f\n\x07version\x18\x08 \x01(\r\x12\x37\n\x06inputs\x18\t \x03(\x0b\x32\'.cln.ListtransactionsTransactionsInputs\x12\x39\n\x07outputs\x18\n \x03(\x0b\x32(.cln.ListtransactionsTransactionsOutputsB\n\n\x08_channel\"\x84\x04\n\"ListtransactionsTransactionsInputs\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\r\n\x05index\x18\x02 \x01(\r\x12\x10\n\x08sequence\x18\x03 \x01(\r\x12\x66\n\titem_type\x18\x04 \x01(\x0e\x32N.cln.ListtransactionsTransactionsInputs.ListtransactionsTransactionsInputsTypeH\x00\x88\x01\x01\x12\x14\n\x07\x63hannel\x18\x05 \x01(\tH\x01\x88\x01\x01\"\x96\x02\n&ListtransactionsTransactionsInputsType\x12\n\n\x06THEIRS\x10\x00\x12\x0b\n\x07\x44\x45POSIT\x10\x01\x12\x0c\n\x08WITHDRAW\x10\x02\x12\x13\n\x0f\x43HANNEL_FUNDING\x10\x03\x12\x18\n\x14\x43HANNEL_MUTUAL_CLOSE\x10\x04\x12\x1c\n\x18\x43HANNEL_UNILATERAL_CLOSE\x10\x05\x12\x11\n\rCHANNEL_SWEEP\x10\x06\x12\x18\n\x14\x43HANNEL_HTLC_SUCCESS\x10\x07\x12\x18\n\x14\x43HANNEL_HTLC_TIMEOUT\x10\x08\x12\x13\n\x0f\x43HANNEL_PENALTY\x10\t\x12\x1c\n\x18\x43HANNEL_UNILATERAL_CHEAT\x10\nB\x0c\n\n_item_typeB\n\n\x08_channel\"\xa0\x04\n#ListtransactionsTransactionsOutputs\x12\r\n\x05index\x18\x01 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12\x14\n\x0cscriptPubKey\x18\x03 \x01(\x0c\x12h\n\titem_type\x18\x04 \x01(\x0e\x32P.cln.ListtransactionsTransactionsOutputs.ListtransactionsTransactionsOutputsTypeH\x00\x88\x01\x01\x12\x14\n\x07\x63hannel\x18\x05 \x01(\tH\x01\x88\x01\x01\"\x97\x02\n\'ListtransactionsTransactionsOutputsType\x12\n\n\x06THEIRS\x10\x00\x12\x0b\n\x07\x44\x45POSIT\x10\x01\x12\x0c\n\x08WITHDRAW\x10\x02\x12\x13\n\x0f\x43HANNEL_FUNDING\x10\x03\x12\x18\n\x14\x43HANNEL_MUTUAL_CLOSE\x10\x04\x12\x1c\n\x18\x43HANNEL_UNILATERAL_CLOSE\x10\x05\x12\x11\n\rCHANNEL_SWEEP\x10\x06\x12\x18\n\x14\x43HANNEL_HTLC_SUCCESS\x10\x07\x12\x18\n\x14\x43HANNEL_HTLC_TIMEOUT\x10\x08\x12\x13\n\x0f\x43HANNEL_PENALTY\x10\t\x12\x1c\n\x18\x43HANNEL_UNILATERAL_CHEAT\x10\nB\x0c\n\n_item_typeB\n\n\x08_channel\"\xda\x03\n\nPayRequest\x12\x0e\n\x06\x62olt11\x18\x01 \x01(\t\x12%\n\x0b\x61mount_msat\x18\r \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x12\n\x05label\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x17\n\nriskfactor\x18\x08 \x01(\x01H\x02\x88\x01\x01\x12\x1a\n\rmaxfeepercent\x18\x04 \x01(\x01H\x03\x88\x01\x01\x12\x16\n\tretry_for\x18\x05 \x01(\rH\x04\x88\x01\x01\x12\x15\n\x08maxdelay\x18\x06 \x01(\rH\x05\x88\x01\x01\x12#\n\texemptfee\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\x1a\n\rlocalinvreqid\x18\x0e \x01(\x0cH\x07\x88\x01\x01\x12\x0f\n\x07\x65xclude\x18\n \x03(\t\x12 \n\x06maxfee\x18\x0b \x01(\x0b\x32\x0b.cln.AmountH\x08\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x0c \x01(\tH\t\x88\x01\x01\x42\x0e\n\x0c_amount_msatB\x08\n\x06_labelB\r\n\x0b_riskfactorB\x10\n\x0e_maxfeepercentB\x0c\n\n_retry_forB\x0b\n\t_maxdelayB\x0c\n\n_exemptfeeB\x10\n\x0e_localinvreqidB\t\n\x07_maxfeeB\x0e\n\x0c_description\"\xfb\x02\n\x0bPayResponse\x12\x18\n\x10payment_preimage\x18\x01 \x01(\x0c\x12\x18\n\x0b\x64\x65stination\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x12\n\ncreated_at\x18\x04 \x01(\x01\x12\r\n\x05parts\x18\x05 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10\x61mount_sent_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\'\n\x1awarning_partial_completion\x18\x08 \x01(\tH\x01\x88\x01\x01\x12*\n\x06status\x18\t \x01(\x0e\x32\x1a.cln.PayResponse.PayStatus\"2\n\tPayStatus\x12\x0c\n\x08\x43OMPLETE\x10\x00\x12\x0b\n\x07PENDING\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x42\x0e\n\x0c_destinationB\x1d\n\x1b_warning_partial_completion\"*\n\x10ListnodesRequest\x12\x0f\n\x02id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x05\n\x03_id\"7\n\x11ListnodesResponse\x12\"\n\x05nodes\x18\x01 \x03(\x0b\x32\x13.cln.ListnodesNodes\"\xe1\x01\n\x0eListnodesNodes\x12\x0e\n\x06nodeid\x18\x01 \x01(\x0c\x12\x1b\n\x0elast_timestamp\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x12\n\x05\x61lias\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x12\n\x05\x63olor\x18\x04 \x01(\x0cH\x02\x88\x01\x01\x12\x15\n\x08\x66\x65\x61tures\x18\x05 \x01(\x0cH\x03\x88\x01\x01\x12/\n\taddresses\x18\x06 \x03(\x0b\x32\x1c.cln.ListnodesNodesAddressesB\x11\n\x0f_last_timestampB\x08\n\x06_aliasB\x08\n\x06_colorB\x0b\n\t_features\"\xf7\x01\n\x17ListnodesNodesAddresses\x12K\n\titem_type\x18\x01 \x01(\x0e\x32\x38.cln.ListnodesNodesAddresses.ListnodesNodesAddressesType\x12\x0c\n\x04port\x18\x02 \x01(\r\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x00\x88\x01\x01\"_\n\x1bListnodesNodesAddressesType\x12\x07\n\x03\x44NS\x10\x00\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x12\r\n\tWEBSOCKET\x10\x05\x42\n\n\x08_address\"g\n\x15WaitanyinvoiceRequest\x12\x1a\n\rlastpay_index\x18\x01 \x01(\x04H\x00\x88\x01\x01\x12\x14\n\x07timeout\x18\x02 \x01(\x04H\x01\x88\x01\x01\x42\x10\n\x0e_lastpay_indexB\n\n\x08_timeout\"\x93\x04\n\x16WaitanyinvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12@\n\x06status\x18\x04 \x01(\x0e\x32\x30.cln.WaitanyinvoiceResponse.WaitanyinvoiceStatus\x12\x12\n\nexpires_at\x18\x05 \x01(\x04\x12%\n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x08 \x01(\tH\x02\x88\x01\x01\x12\x16\n\tpay_index\x18\t \x01(\x04H\x03\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12\x14\n\x07paid_at\x18\x0b \x01(\x04H\x05\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\x06\x88\x01\x01\"-\n\x14WaitanyinvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x42\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\t\n\x07_bolt12B\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x13\n\x11_payment_preimage\"#\n\x12WaitinvoiceRequest\x12\r\n\x05label\x18\x01 \x01(\t\"\x87\x04\n\x13WaitinvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12:\n\x06status\x18\x04 \x01(\x0e\x32*.cln.WaitinvoiceResponse.WaitinvoiceStatus\x12\x12\n\nexpires_at\x18\x05 \x01(\x04\x12%\n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x08 \x01(\tH\x02\x88\x01\x01\x12\x16\n\tpay_index\x18\t \x01(\x04H\x03\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12\x14\n\x07paid_at\x18\x0b \x01(\x04H\x05\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\x06\x88\x01\x01\"*\n\x11WaitinvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x42\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\t\n\x07_bolt12B\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x13\n\x11_payment_preimage\"\x8e\x01\n\x12WaitsendpayRequest\x12\x14\n\x0cpayment_hash\x18\x01 \x01(\x0c\x12\x14\n\x07timeout\x18\x03 \x01(\rH\x00\x88\x01\x01\x12\x13\n\x06partid\x18\x02 \x01(\x04H\x01\x88\x01\x01\x12\x14\n\x07groupid\x18\x04 \x01(\x04H\x02\x88\x01\x01\x42\n\n\x08_timeoutB\t\n\x07_partidB\n\n\x08_groupid\"\xb2\x04\n\x13WaitsendpayResponse\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x14\n\x07groupid\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12:\n\x06status\x18\x04 \x01(\x0e\x32*.cln.WaitsendpayResponse.WaitsendpayStatus\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x06 \x01(\x0cH\x02\x88\x01\x01\x12\x12\n\ncreated_at\x18\x07 \x01(\x04\x12\x19\n\x0c\x63ompleted_at\x18\x0e \x01(\x01H\x03\x88\x01\x01\x12%\n\x10\x61mount_sent_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\t \x01(\tH\x04\x88\x01\x01\x12\x13\n\x06partid\x18\n \x01(\x04H\x05\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x0b \x01(\tH\x06\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x0c \x01(\tH\x07\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\r \x01(\x0cH\x08\x88\x01\x01\"!\n\x11WaitsendpayStatus\x12\x0c\n\x08\x43OMPLETE\x10\x00\x42\n\n\x08_groupidB\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x0f\n\r_completed_atB\x08\n\x06_labelB\t\n\x07_partidB\t\n\x07_bolt11B\t\n\x07_bolt12B\x13\n\x11_payment_preimage\"\x8d\x01\n\x0eNewaddrRequest\x12@\n\x0b\x61\x64\x64resstype\x18\x01 \x01(\x0e\x32&.cln.NewaddrRequest.NewaddrAddresstypeH\x00\x88\x01\x01\")\n\x12NewaddrAddresstype\x12\n\n\x06\x42\x45\x43H32\x10\x00\x12\x07\n\x03\x41LL\x10\x02\x42\x0e\n\x0c_addresstype\"[\n\x0fNewaddrResponse\x12\x13\n\x06\x62\x65\x63h32\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0bp2sh_segwit\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\t\n\x07_bech32B\x0e\n\x0c_p2sh_segwit\"\xca\x01\n\x0fWithdrawRequest\x12\x13\n\x0b\x64\x65stination\x18\x01 \x01(\t\x12&\n\x07satoshi\x18\x02 \x01(\x0b\x32\x10.cln.AmountOrAllH\x00\x88\x01\x01\x12\"\n\x07\x66\x65\x65rate\x18\x05 \x01(\x0b\x32\x0c.cln.FeerateH\x01\x88\x01\x01\x12\x14\n\x07minconf\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\x1c\n\x05utxos\x18\x04 \x03(\x0b\x32\r.cln.OutpointB\n\n\x08_satoshiB\n\n\x08_feerateB\n\n\x08_minconf\":\n\x10WithdrawResponse\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\x12\x0c\n\x04psbt\x18\x03 \x01(\t\"\x82\x03\n\x0eKeysendRequest\x12\x13\n\x0b\x64\x65stination\x18\x01 \x01(\x0c\x12 \n\x0b\x61mount_msat\x18\n \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x1a\n\rmaxfeepercent\x18\x04 \x01(\x01H\x01\x88\x01\x01\x12\x16\n\tretry_for\x18\x05 \x01(\rH\x02\x88\x01\x01\x12\x15\n\x08maxdelay\x18\x06 \x01(\rH\x03\x88\x01\x01\x12#\n\texemptfee\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12+\n\nroutehints\x18\x08 \x01(\x0b\x32\x12.cln.RoutehintListH\x05\x88\x01\x01\x12&\n\textratlvs\x18\t \x01(\x0b\x32\x0e.cln.TlvStreamH\x06\x88\x01\x01\x42\x08\n\x06_labelB\x10\n\x0e_maxfeepercentB\x0c\n\n_retry_forB\x0b\n\t_maxdelayB\x0c\n\n_exemptfeeB\r\n\x0b_routehintsB\x0c\n\n_extratlvs\"\xf2\x02\n\x0fKeysendResponse\x12\x18\n\x10payment_preimage\x18\x01 \x01(\x0c\x12\x18\n\x0b\x64\x65stination\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x12\n\ncreated_at\x18\x04 \x01(\x01\x12\r\n\x05parts\x18\x05 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10\x61mount_sent_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\'\n\x1awarning_partial_completion\x18\x08 \x01(\tH\x01\x88\x01\x01\x12\x32\n\x06status\x18\t \x01(\x0e\x32\".cln.KeysendResponse.KeysendStatus\"\x1d\n\rKeysendStatus\x12\x0c\n\x08\x43OMPLETE\x10\x00\x42\x0e\n\x0c_destinationB\x1d\n\x1b_warning_partial_completion\"\xbc\x02\n\x0f\x46undpsbtRequest\x12!\n\x07satoshi\x18\x01 \x01(\x0b\x32\x10.cln.AmountOrAll\x12\x1d\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.Feerate\x12\x13\n\x0bstartweight\x18\x03 \x01(\r\x12\x14\n\x07minconf\x18\x04 \x01(\rH\x00\x88\x01\x01\x12\x14\n\x07reserve\x18\x05 \x01(\rH\x01\x88\x01\x01\x12\x15\n\x08locktime\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x1f\n\x12min_witness_weight\x18\x07 \x01(\rH\x03\x88\x01\x01\x12\x1d\n\x10\x65xcess_as_change\x18\x08 \x01(\x08H\x04\x88\x01\x01\x42\n\n\x08_minconfB\n\n\x08_reserveB\x0b\n\t_locktimeB\x15\n\x13_min_witness_weightB\x13\n\x11_excess_as_change\"\xd9\x01\n\x10\x46undpsbtResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x16\n\x0e\x66\x65\x65rate_per_kw\x18\x02 \x01(\r\x12\x1e\n\x16\x65stimated_final_weight\x18\x03 \x01(\r\x12 \n\x0b\x65xcess_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12\x1a\n\rchange_outnum\x18\x05 \x01(\rH\x00\x88\x01\x01\x12/\n\x0creservations\x18\x06 \x03(\x0b\x32\x19.cln.FundpsbtReservationsB\x10\n\x0e_change_outnum\"u\n\x14\x46undpsbtReservations\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\x0c\n\x04vout\x18\x02 \x01(\r\x12\x14\n\x0cwas_reserved\x18\x03 \x01(\x08\x12\x10\n\x08reserved\x18\x04 \x01(\x08\x12\x19\n\x11reserved_to_block\x18\x05 \x01(\r\"A\n\x0fSendpsbtRequest\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x14\n\x07reserve\x18\x02 \x01(\x08H\x00\x88\x01\x01\x42\n\n\x08_reserve\",\n\x10SendpsbtResponse\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\"1\n\x0fSignpsbtRequest\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x10\n\x08signonly\x18\x02 \x03(\r\"\'\n\x10SignpsbtResponse\x12\x13\n\x0bsigned_psbt\x18\x01 \x01(\t\"\xdb\x02\n\x0fUtxopsbtRequest\x12\x1c\n\x07satoshi\x18\x01 \x01(\x0b\x32\x0b.cln.Amount\x12\x1d\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.Feerate\x12\x13\n\x0bstartweight\x18\x03 \x01(\r\x12\x1c\n\x05utxos\x18\x04 \x03(\x0b\x32\r.cln.Outpoint\x12\x14\n\x07reserve\x18\x05 \x01(\rH\x00\x88\x01\x01\x12\x17\n\nreservedok\x18\x08 \x01(\x08H\x01\x88\x01\x01\x12\x15\n\x08locktime\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x1f\n\x12min_witness_weight\x18\x07 \x01(\rH\x03\x88\x01\x01\x12\x1d\n\x10\x65xcess_as_change\x18\t \x01(\x08H\x04\x88\x01\x01\x42\n\n\x08_reserveB\r\n\x0b_reservedokB\x0b\n\t_locktimeB\x15\n\x13_min_witness_weightB\x13\n\x11_excess_as_change\"\xd9\x01\n\x10UtxopsbtResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x16\n\x0e\x66\x65\x65rate_per_kw\x18\x02 \x01(\r\x12\x1e\n\x16\x65stimated_final_weight\x18\x03 \x01(\r\x12 \n\x0b\x65xcess_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12\x1a\n\rchange_outnum\x18\x05 \x01(\rH\x00\x88\x01\x01\x12/\n\x0creservations\x18\x06 \x03(\x0b\x32\x19.cln.UtxopsbtReservationsB\x10\n\x0e_change_outnum\"u\n\x14UtxopsbtReservations\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\x0c\n\x04vout\x18\x02 \x01(\r\x12\x14\n\x0cwas_reserved\x18\x03 \x01(\x08\x12\x10\n\x08reserved\x18\x04 \x01(\x08\x12\x19\n\x11reserved_to_block\x18\x05 \x01(\r\" \n\x10TxdiscardRequest\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\"6\n\x11TxdiscardResponse\x12\x13\n\x0bunsigned_tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\"\xa4\x01\n\x10TxprepareRequest\x12 \n\x07outputs\x18\x05 \x03(\x0b\x32\x0f.cln.OutputDesc\x12\"\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.FeerateH\x00\x88\x01\x01\x12\x14\n\x07minconf\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x1c\n\x05utxos\x18\x04 \x03(\x0b\x32\r.cln.OutpointB\n\n\x08_feerateB\n\n\x08_minconf\"D\n\x11TxprepareResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x13\n\x0bunsigned_tx\x18\x02 \x01(\x0c\x12\x0c\n\x04txid\x18\x03 \x01(\x0c\"\x1d\n\rTxsendRequest\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\"8\n\x0eTxsendResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\n\n\x02tx\x18\x02 \x01(\x0c\x12\x0c\n\x04txid\x18\x03 \x01(\x0c\"=\n\x11\x44isconnectRequest\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x12\n\x05\x66orce\x18\x02 \x01(\x08H\x00\x88\x01\x01\x42\x08\n\x06_force\"\x14\n\x12\x44isconnectResponse\"k\n\x0f\x46\x65\x65ratesRequest\x12\x31\n\x05style\x18\x01 \x01(\x0e\x32\".cln.FeeratesRequest.FeeratesStyle\"%\n\rFeeratesStyle\x12\t\n\x05PERKB\x10\x00\x12\t\n\x05PERKW\x10\x01\"\x9c\x02\n\x10\x46\x65\x65ratesResponse\x12%\n\x18warning_missing_feerates\x18\x01 \x01(\tH\x00\x88\x01\x01\x12&\n\x05perkb\x18\x02 \x01(\x0b\x32\x12.cln.FeeratesPerkbH\x01\x88\x01\x01\x12&\n\x05perkw\x18\x03 \x01(\x0b\x32\x12.cln.FeeratesPerkwH\x02\x88\x01\x01\x12\x46\n\x15onchain_fee_estimates\x18\x04 \x01(\x0b\x32\".cln.FeeratesOnchain_fee_estimatesH\x03\x88\x01\x01\x42\x1b\n\x19_warning_missing_feeratesB\x08\n\x06_perkbB\x08\n\x06_perkwB\x18\n\x16_onchain_fee_estimates\"\xc3\x02\n\rFeeratesPerkb\x12\x16\n\x0emin_acceptable\x18\x01 \x01(\r\x12\x16\n\x0emax_acceptable\x18\x02 \x01(\r\x12\x14\n\x07opening\x18\x03 \x01(\rH\x00\x88\x01\x01\x12\x19\n\x0cmutual_close\x18\x04 \x01(\rH\x01\x88\x01\x01\x12\x1d\n\x10unilateral_close\x18\x05 \x01(\rH\x02\x88\x01\x01\x12\x1a\n\rdelayed_to_us\x18\x06 \x01(\rH\x03\x88\x01\x01\x12\x1c\n\x0fhtlc_resolution\x18\x07 \x01(\rH\x04\x88\x01\x01\x12\x14\n\x07penalty\x18\x08 \x01(\rH\x05\x88\x01\x01\x42\n\n\x08_openingB\x0f\n\r_mutual_closeB\x13\n\x11_unilateral_closeB\x10\n\x0e_delayed_to_usB\x12\n\x10_htlc_resolutionB\n\n\x08_penalty\"\xc3\x02\n\rFeeratesPerkw\x12\x16\n\x0emin_acceptable\x18\x01 \x01(\r\x12\x16\n\x0emax_acceptable\x18\x02 \x01(\r\x12\x14\n\x07opening\x18\x03 \x01(\rH\x00\x88\x01\x01\x12\x19\n\x0cmutual_close\x18\x04 \x01(\rH\x01\x88\x01\x01\x12\x1d\n\x10unilateral_close\x18\x05 \x01(\rH\x02\x88\x01\x01\x12\x1a\n\rdelayed_to_us\x18\x06 \x01(\rH\x03\x88\x01\x01\x12\x1c\n\x0fhtlc_resolution\x18\x07 \x01(\rH\x04\x88\x01\x01\x12\x14\n\x07penalty\x18\x08 \x01(\rH\x05\x88\x01\x01\x42\n\n\x08_openingB\x0f\n\r_mutual_closeB\x13\n\x11_unilateral_closeB\x10\n\x0e_delayed_to_usB\x12\n\x10_htlc_resolutionB\n\n\x08_penalty\"\xc1\x01\n\x1d\x46\x65\x65ratesOnchain_fee_estimates\x12 \n\x18opening_channel_satoshis\x18\x01 \x01(\x04\x12\x1d\n\x15mutual_close_satoshis\x18\x02 \x01(\x04\x12!\n\x19unilateral_close_satoshis\x18\x03 \x01(\x04\x12\x1d\n\x15htlc_timeout_satoshis\x18\x04 \x01(\x04\x12\x1d\n\x15htlc_success_satoshis\x18\x05 \x01(\x04\"\xe5\x03\n\x12\x46undchannelRequest\x12\n\n\x02id\x18\t \x01(\x0c\x12 \n\x06\x61mount\x18\x01 \x01(\x0b\x32\x10.cln.AmountOrAll\x12\"\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.FeerateH\x00\x88\x01\x01\x12\x15\n\x08\x61nnounce\x18\x03 \x01(\x08H\x01\x88\x01\x01\x12\x14\n\x07minconf\x18\n \x01(\rH\x02\x88\x01\x01\x12#\n\tpush_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x15\n\x08\x63lose_to\x18\x06 \x01(\tH\x04\x88\x01\x01\x12%\n\x0brequest_amt\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x05\x88\x01\x01\x12\x1a\n\rcompact_lease\x18\x08 \x01(\tH\x06\x88\x01\x01\x12\x1c\n\x05utxos\x18\x0b \x03(\x0b\x32\r.cln.Outpoint\x12\x15\n\x08mindepth\x18\x0c \x01(\rH\x07\x88\x01\x01\x12!\n\x07reserve\x18\r \x01(\x0b\x32\x0b.cln.AmountH\x08\x88\x01\x01\x42\n\n\x08_feerateB\x0b\n\t_announceB\n\n\x08_minconfB\x0c\n\n_push_msatB\x0b\n\t_close_toB\x0e\n\x0c_request_amtB\x10\n\x0e_compact_leaseB\x0b\n\t_mindepthB\n\n\x08_reserve\"\x9b\x01\n\x13\x46undchannelResponse\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\x12\x0e\n\x06outnum\x18\x03 \x01(\r\x12\x12\n\nchannel_id\x18\x04 \x01(\x0c\x12\x15\n\x08\x63lose_to\x18\x05 \x01(\x0cH\x00\x88\x01\x01\x12\x15\n\x08mindepth\x18\x06 \x01(\rH\x01\x88\x01\x01\x42\x0b\n\t_close_toB\x0b\n\t_mindepth\"\xec\x01\n\x0fGetrouteRequest\x12\n\n\x02id\x18\x01 \x01(\x0c\x12 \n\x0b\x61mount_msat\x18\t \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\nriskfactor\x18\x03 \x01(\x04\x12\x11\n\x04\x63ltv\x18\x04 \x01(\x01H\x00\x88\x01\x01\x12\x13\n\x06\x66romid\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\x18\n\x0b\x66uzzpercent\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x0f\n\x07\x65xclude\x18\x07 \x03(\t\x12\x14\n\x07maxhops\x18\x08 \x01(\rH\x03\x88\x01\x01\x42\x07\n\x05_cltvB\t\n\x07_fromidB\x0e\n\x0c_fuzzpercentB\n\n\x08_maxhops\"5\n\x10GetrouteResponse\x12!\n\x05route\x18\x01 \x03(\x0b\x32\x12.cln.GetrouteRoute\"\xe9\x01\n\rGetrouteRoute\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x0f\n\x07\x63hannel\x18\x02 \x01(\t\x12\x11\n\tdirection\x18\x03 \x01(\r\x12\x15\n\x08msatoshi\x18\x07 \x01(\x04H\x00\x88\x01\x01\x12 \n\x0b\x61mount_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12\r\n\x05\x64\x65lay\x18\x05 \x01(\r\x12\x34\n\x05style\x18\x06 \x01(\x0e\x32%.cln.GetrouteRoute.GetrouteRouteStyle\"\x1d\n\x12GetrouteRouteStyle\x12\x07\n\x03TLV\x10\x00\x42\x0b\n\t_msatoshi\"\x82\x02\n\x13ListforwardsRequest\x12@\n\x06status\x18\x01 \x01(\x0e\x32+.cln.ListforwardsRequest.ListforwardsStatusH\x00\x88\x01\x01\x12\x17\n\nin_channel\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0bout_channel\x18\x03 \x01(\tH\x02\x88\x01\x01\"L\n\x12ListforwardsStatus\x12\x0b\n\x07OFFERED\x10\x00\x12\x0b\n\x07SETTLED\x10\x01\x12\x10\n\x0cLOCAL_FAILED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\x42\t\n\x07_statusB\r\n\x0b_in_channelB\x0e\n\x0c_out_channel\"C\n\x14ListforwardsResponse\x12+\n\x08\x66orwards\x18\x01 \x03(\x0b\x32\x19.cln.ListforwardsForwards\"\xde\x04\n\x14ListforwardsForwards\x12\x12\n\nin_channel\x18\x01 \x01(\t\x12\x17\n\nin_htlc_id\x18\n \x01(\x04H\x00\x88\x01\x01\x12\x1c\n\x07in_msat\x18\x02 \x01(\x0b\x32\x0b.cln.Amount\x12\x44\n\x06status\x18\x03 \x01(\x0e\x32\x34.cln.ListforwardsForwards.ListforwardsForwardsStatus\x12\x15\n\rreceived_time\x18\x04 \x01(\x01\x12\x18\n\x0bout_channel\x18\x05 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0bout_htlc_id\x18\x0b \x01(\x04H\x02\x88\x01\x01\x12G\n\x05style\x18\t \x01(\x0e\x32\x33.cln.ListforwardsForwards.ListforwardsForwardsStyleH\x03\x88\x01\x01\x12\"\n\x08\x66\x65\x65_msat\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12\"\n\x08out_msat\x18\x08 \x01(\x0b\x32\x0b.cln.AmountH\x05\x88\x01\x01\"T\n\x1aListforwardsForwardsStatus\x12\x0b\n\x07OFFERED\x10\x00\x12\x0b\n\x07SETTLED\x10\x01\x12\x10\n\x0cLOCAL_FAILED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\"0\n\x19ListforwardsForwardsStyle\x12\n\n\x06LEGACY\x10\x00\x12\x07\n\x03TLV\x10\x01\x42\r\n\x0b_in_htlc_idB\x0e\n\x0c_out_channelB\x0e\n\x0c_out_htlc_idB\x08\n\x06_styleB\x0b\n\t_fee_msatB\x0b\n\t_out_msat\"\xdb\x01\n\x0fListpaysRequest\x12\x13\n\x06\x62olt11\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12\x38\n\x06status\x18\x03 \x01(\x0e\x32#.cln.ListpaysRequest.ListpaysStatusH\x02\x88\x01\x01\"7\n\x0eListpaysStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x42\t\n\x07_bolt11B\x0f\n\r_payment_hashB\t\n\x07_status\"3\n\x10ListpaysResponse\x12\x1f\n\x04pays\x18\x01 \x03(\x0b\x32\x11.cln.ListpaysPays\"\x87\x04\n\x0cListpaysPays\x12\x14\n\x0cpayment_hash\x18\x01 \x01(\x0c\x12\x34\n\x06status\x18\x02 \x01(\x0e\x32$.cln.ListpaysPays.ListpaysPaysStatus\x12\x18\n\x0b\x64\x65stination\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x12\x12\n\ncreated_at\x18\x04 \x01(\x04\x12\x19\n\x0c\x63ompleted_at\x18\x0c \x01(\x04H\x01\x88\x01\x01\x12\x12\n\x05label\x18\x05 \x01(\tH\x02\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x06 \x01(\tH\x03\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x0b \x01(\tH\x04\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x07 \x01(\tH\x05\x88\x01\x01\x12\x15\n\x08preimage\x18\r \x01(\x0cH\x06\x88\x01\x01\x12\x1c\n\x0fnumber_of_parts\x18\x0e \x01(\x04H\x07\x88\x01\x01\x12\x17\n\nerroronion\x18\n \x01(\x0cH\x08\x88\x01\x01\";\n\x12ListpaysPaysStatus\x12\x0b\n\x07PENDING\x10\x00\x12\n\n\x06\x46\x41ILED\x10\x01\x12\x0c\n\x08\x43OMPLETE\x10\x02\x42\x0e\n\x0c_destinationB\x0f\n\r_completed_atB\x08\n\x06_labelB\t\n\x07_bolt11B\x0e\n\x0c_descriptionB\t\n\x07_bolt12B\x0b\n\t_preimageB\x12\n\x10_number_of_partsB\r\n\x0b_erroronion\"Y\n\x0bPingRequest\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x10\n\x03len\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x16\n\tpongbytes\x18\x03 \x01(\rH\x01\x88\x01\x01\x42\x06\n\x04_lenB\x0c\n\n_pongbytes\"\x1e\n\x0cPingResponse\x12\x0e\n\x06totlen\x18\x01 \x01(\r\"\xf8\x01\n\x11SetchannelRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12!\n\x07\x66\x65\x65\x62\x61se\x18\x02 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x13\n\x06\x66\x65\x65ppm\x18\x03 \x01(\rH\x01\x88\x01\x01\x12!\n\x07htlcmin\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12!\n\x07htlcmax\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x19\n\x0c\x65nforcedelay\x18\x06 \x01(\rH\x04\x88\x01\x01\x42\n\n\x08_feebaseB\t\n\x07_feeppmB\n\n\x08_htlcminB\n\n\x08_htlcmaxB\x0f\n\r_enforcedelay\"?\n\x12SetchannelResponse\x12)\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x17.cln.SetchannelChannels\"\x94\x03\n\x12SetchannelChannels\x12\x0f\n\x07peer_id\x18\x01 \x01(\x0c\x12\x12\n\nchannel_id\x18\x02 \x01(\x0c\x12\x1d\n\x10short_channel_id\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\"\n\rfee_base_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12#\n\x1b\x66\x65\x65_proportional_millionths\x18\x05 \x01(\r\x12*\n\x15minimum_htlc_out_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12$\n\x17warning_htlcmin_too_low\x18\x07 \x01(\tH\x01\x88\x01\x01\x12*\n\x15maximum_htlc_out_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x18warning_htlcmax_too_high\x18\t \x01(\tH\x02\x88\x01\x01\x42\x13\n\x11_short_channel_idB\x1a\n\x18_warning_htlcmin_too_lowB\x1b\n\x19_warning_htlcmax_too_high\"%\n\x12SignmessageRequest\x12\x0f\n\x07message\x18\x01 \x01(\t\"F\n\x13SignmessageResponse\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12\r\n\x05recid\x18\x02 \x01(\x0c\x12\r\n\x05zbase\x18\x03 \x01(\t\"\r\n\x0bStopRequest\"\x0e\n\x0cStopResponse2\xb1\x17\n\x04Node\x12\x36\n\x07Getinfo\x12\x13.cln.GetinfoRequest\x1a\x14.cln.GetinfoResponse\"\x00\x12<\n\tListPeers\x12\x15.cln.ListpeersRequest\x1a\x16.cln.ListpeersResponse\"\x00\x12<\n\tListFunds\x12\x15.cln.ListfundsRequest\x1a\x16.cln.ListfundsResponse\"\x00\x12\x36\n\x07SendPay\x12\x13.cln.SendpayRequest\x1a\x14.cln.SendpayResponse\"\x00\x12\x45\n\x0cListChannels\x12\x18.cln.ListchannelsRequest\x1a\x19.cln.ListchannelsResponse\"\x00\x12<\n\tAddGossip\x12\x15.cln.AddgossipRequest\x1a\x16.cln.AddgossipResponse\"\x00\x12Q\n\x10\x41utoCleanInvoice\x12\x1c.cln.AutocleaninvoiceRequest\x1a\x1d.cln.AutocleaninvoiceResponse\"\x00\x12\x45\n\x0c\x43heckMessage\x12\x18.cln.CheckmessageRequest\x1a\x19.cln.CheckmessageResponse\"\x00\x12\x30\n\x05\x43lose\x12\x11.cln.CloseRequest\x1a\x12.cln.CloseResponse\"\x00\x12:\n\x0b\x43onnectPeer\x12\x13.cln.ConnectRequest\x1a\x14.cln.ConnectResponse\"\x00\x12H\n\rCreateInvoice\x12\x19.cln.CreateinvoiceRequest\x1a\x1a.cln.CreateinvoiceResponse\"\x00\x12<\n\tDatastore\x12\x15.cln.DatastoreRequest\x1a\x16.cln.DatastoreResponse\"\x00\x12\x42\n\x0b\x43reateOnion\x12\x17.cln.CreateonionRequest\x1a\x18.cln.CreateonionResponse\"\x00\x12\x45\n\x0c\x44\x65lDatastore\x12\x18.cln.DeldatastoreRequest\x1a\x19.cln.DeldatastoreResponse\"\x00\x12T\n\x11\x44\x65lExpiredInvoice\x12\x1d.cln.DelexpiredinvoiceRequest\x1a\x1e.cln.DelexpiredinvoiceResponse\"\x00\x12?\n\nDelInvoice\x12\x16.cln.DelinvoiceRequest\x1a\x17.cln.DelinvoiceResponse\"\x00\x12\x36\n\x07Invoice\x12\x13.cln.InvoiceRequest\x1a\x14.cln.InvoiceResponse\"\x00\x12H\n\rListDatastore\x12\x19.cln.ListdatastoreRequest\x1a\x1a.cln.ListdatastoreResponse\"\x00\x12\x45\n\x0cListInvoices\x12\x18.cln.ListinvoicesRequest\x1a\x19.cln.ListinvoicesResponse\"\x00\x12<\n\tSendOnion\x12\x15.cln.SendonionRequest\x1a\x16.cln.SendonionResponse\"\x00\x12\x45\n\x0cListSendPays\x12\x18.cln.ListsendpaysRequest\x1a\x19.cln.ListsendpaysResponse\"\x00\x12Q\n\x10ListTransactions\x12\x1c.cln.ListtransactionsRequest\x1a\x1d.cln.ListtransactionsResponse\"\x00\x12*\n\x03Pay\x12\x0f.cln.PayRequest\x1a\x10.cln.PayResponse\"\x00\x12<\n\tListNodes\x12\x15.cln.ListnodesRequest\x1a\x16.cln.ListnodesResponse\"\x00\x12K\n\x0eWaitAnyInvoice\x12\x1a.cln.WaitanyinvoiceRequest\x1a\x1b.cln.WaitanyinvoiceResponse\"\x00\x12\x42\n\x0bWaitInvoice\x12\x17.cln.WaitinvoiceRequest\x1a\x18.cln.WaitinvoiceResponse\"\x00\x12\x42\n\x0bWaitSendPay\x12\x17.cln.WaitsendpayRequest\x1a\x18.cln.WaitsendpayResponse\"\x00\x12\x36\n\x07NewAddr\x12\x13.cln.NewaddrRequest\x1a\x14.cln.NewaddrResponse\"\x00\x12\x39\n\x08Withdraw\x12\x14.cln.WithdrawRequest\x1a\x15.cln.WithdrawResponse\"\x00\x12\x36\n\x07KeySend\x12\x13.cln.KeysendRequest\x1a\x14.cln.KeysendResponse\"\x00\x12\x39\n\x08\x46undPsbt\x12\x14.cln.FundpsbtRequest\x1a\x15.cln.FundpsbtResponse\"\x00\x12\x39\n\x08SendPsbt\x12\x14.cln.SendpsbtRequest\x1a\x15.cln.SendpsbtResponse\"\x00\x12\x39\n\x08SignPsbt\x12\x14.cln.SignpsbtRequest\x1a\x15.cln.SignpsbtResponse\"\x00\x12\x39\n\x08UtxoPsbt\x12\x14.cln.UtxopsbtRequest\x1a\x15.cln.UtxopsbtResponse\"\x00\x12<\n\tTxDiscard\x12\x15.cln.TxdiscardRequest\x1a\x16.cln.TxdiscardResponse\"\x00\x12<\n\tTxPrepare\x12\x15.cln.TxprepareRequest\x1a\x16.cln.TxprepareResponse\"\x00\x12\x33\n\x06TxSend\x12\x12.cln.TxsendRequest\x1a\x13.cln.TxsendResponse\"\x00\x12?\n\nDisconnect\x12\x16.cln.DisconnectRequest\x1a\x17.cln.DisconnectResponse\"\x00\x12\x39\n\x08\x46\x65\x65rates\x12\x14.cln.FeeratesRequest\x1a\x15.cln.FeeratesResponse\"\x00\x12\x42\n\x0b\x46undChannel\x12\x17.cln.FundchannelRequest\x1a\x18.cln.FundchannelResponse\"\x00\x12\x39\n\x08GetRoute\x12\x14.cln.GetrouteRequest\x1a\x15.cln.GetrouteResponse\"\x00\x12\x45\n\x0cListForwards\x12\x18.cln.ListforwardsRequest\x1a\x19.cln.ListforwardsResponse\"\x00\x12\x39\n\x08ListPays\x12\x14.cln.ListpaysRequest\x1a\x15.cln.ListpaysResponse\"\x00\x12-\n\x04Ping\x12\x10.cln.PingRequest\x1a\x11.cln.PingResponse\"\x00\x12?\n\nSetChannel\x12\x16.cln.SetchannelRequest\x1a\x17.cln.SetchannelResponse\"\x00\x12\x42\n\x0bSignMessage\x12\x17.cln.SignmessageRequest\x1a\x18.cln.SignmessageResponse\"\x00\x12-\n\x04Stop\x12\x10.cln.StopRequest\x1a\x11.cln.StopResponse\"\x00\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nnode.proto\x12\x03\x63ln\x1a\x10primitives.proto\"\x10\n\x0eGetinfoRequest\"\xc1\x04\n\x0fGetinfoResponse\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x12\n\x05\x61lias\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\r\n\x05\x63olor\x18\x03 \x01(\x0c\x12\x11\n\tnum_peers\x18\x04 \x01(\r\x12\x1c\n\x14num_pending_channels\x18\x05 \x01(\r\x12\x1b\n\x13num_active_channels\x18\x06 \x01(\r\x12\x1d\n\x15num_inactive_channels\x18\x07 \x01(\r\x12\x0f\n\x07version\x18\x08 \x01(\t\x12\x15\n\rlightning_dir\x18\t \x01(\t\x12\x33\n\x0cour_features\x18\n \x01(\x0b\x32\x18.cln.GetinfoOur_featuresH\x01\x88\x01\x01\x12\x13\n\x0b\x62lockheight\x18\x0b \x01(\r\x12\x0f\n\x07network\x18\x0c \x01(\t\x12(\n\x13\x66\x65\x65s_collected_msat\x18\r \x01(\x0b\x32\x0b.cln.Amount\x12$\n\x07\x61\x64\x64ress\x18\x0e \x03(\x0b\x32\x13.cln.GetinfoAddress\x12$\n\x07\x62inding\x18\x0f \x03(\x0b\x32\x13.cln.GetinfoBinding\x12\"\n\x15warning_bitcoind_sync\x18\x10 \x01(\tH\x02\x88\x01\x01\x12$\n\x17warning_lightningd_sync\x18\x11 \x01(\tH\x03\x88\x01\x01\x42\x08\n\x06_aliasB\x0f\n\r_our_featuresB\x18\n\x16_warning_bitcoind_syncB\x1a\n\x18_warning_lightningd_sync\"S\n\x13GetinfoOur_features\x12\x0c\n\x04init\x18\x01 \x01(\x0c\x12\x0c\n\x04node\x18\x02 \x01(\x0c\x12\x0f\n\x07\x63hannel\x18\x03 \x01(\x0c\x12\x0f\n\x07invoice\x18\x04 \x01(\x0c\"\xc4\x01\n\x0eGetinfoAddress\x12\x39\n\titem_type\x18\x01 \x01(\x0e\x32&.cln.GetinfoAddress.GetinfoAddressType\x12\x0c\n\x04port\x18\x02 \x01(\r\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x00\x88\x01\x01\"G\n\x12GetinfoAddressType\x12\x07\n\x03\x44NS\x10\x00\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x42\n\n\x08_address\"\x8a\x02\n\x0eGetinfoBinding\x12\x39\n\titem_type\x18\x01 \x01(\x0e\x32&.cln.GetinfoBinding.GetinfoBindingType\x12\x14\n\x07\x61\x64\x64ress\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x11\n\x04port\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x13\n\x06socket\x18\x04 \x01(\tH\x02\x88\x01\x01\"_\n\x12GetinfoBindingType\x12\x10\n\x0cLOCAL_SOCKET\x10\x00\x12\r\n\tWEBSOCKET\x10\x05\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x42\n\n\x08_addressB\x07\n\x05_portB\t\n\x07_socket\"H\n\x10ListpeersRequest\x12\x0f\n\x02id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x12\n\x05level\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x05\n\x03_idB\x08\n\x06_level\"7\n\x11ListpeersResponse\x12\"\n\x05peers\x18\x01 \x03(\x0b\x32\x13.cln.ListpeersPeers\"\x8e\x02\n\x0eListpeersPeers\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x11\n\tconnected\x18\x02 \x01(\x08\x12\x19\n\x0cnum_channels\x18\x08 \x01(\rH\x00\x88\x01\x01\x12#\n\x03log\x18\x03 \x03(\x0b\x32\x16.cln.ListpeersPeersLog\x12-\n\x08\x63hannels\x18\x04 \x03(\x0b\x32\x1b.cln.ListpeersPeersChannels\x12\x0f\n\x07netaddr\x18\x05 \x03(\t\x12\x18\n\x0bremote_addr\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x15\n\x08\x66\x65\x61tures\x18\x06 \x01(\x0cH\x02\x88\x01\x01\x42\x0f\n\r_num_channelsB\x0e\n\x0c_remote_addrB\x0b\n\t_features\"\xfd\x02\n\x11ListpeersPeersLog\x12?\n\titem_type\x18\x01 \x01(\x0e\x32,.cln.ListpeersPeersLog.ListpeersPeersLogType\x12\x18\n\x0bnum_skipped\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x11\n\x04time\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x13\n\x06source\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x10\n\x03log\x18\x05 \x01(\tH\x03\x88\x01\x01\x12\x14\n\x07node_id\x18\x06 \x01(\x0cH\x04\x88\x01\x01\x12\x11\n\x04\x64\x61ta\x18\x07 \x01(\x0cH\x05\x88\x01\x01\"i\n\x15ListpeersPeersLogType\x12\x0b\n\x07SKIPPED\x10\x00\x12\n\n\x06\x42ROKEN\x10\x01\x12\x0b\n\x07UNUSUAL\x10\x02\x12\x08\n\x04INFO\x10\x03\x12\t\n\x05\x44\x45\x42UG\x10\x04\x12\t\n\x05IO_IN\x10\x05\x12\n\n\x06IO_OUT\x10\x06\x42\x0e\n\x0c_num_skippedB\x07\n\x05_timeB\t\n\x07_sourceB\x06\n\x04_logB\n\n\x08_node_idB\x07\n\x05_data\"\xd6\x17\n\x16ListpeersPeersChannels\x12\x46\n\x05state\x18\x01 \x01(\x0e\x32\x37.cln.ListpeersPeersChannels.ListpeersPeersChannelsState\x12\x19\n\x0cscratch_txid\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x38\n\x07\x66\x65\x65rate\x18\x03 \x01(\x0b\x32\".cln.ListpeersPeersChannelsFeerateH\x01\x88\x01\x01\x12\x12\n\x05owner\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x1d\n\x10short_channel_id\x18\x05 \x01(\tH\x03\x88\x01\x01\x12\x17\n\nchannel_id\x18\x06 \x01(\x0cH\x04\x88\x01\x01\x12\x19\n\x0c\x66unding_txid\x18\x07 \x01(\x0cH\x05\x88\x01\x01\x12\x1b\n\x0e\x66unding_outnum\x18\x08 \x01(\rH\x06\x88\x01\x01\x12\x1c\n\x0finitial_feerate\x18\t \x01(\tH\x07\x88\x01\x01\x12\x19\n\x0clast_feerate\x18\n \x01(\tH\x08\x88\x01\x01\x12\x19\n\x0cnext_feerate\x18\x0b \x01(\tH\t\x88\x01\x01\x12\x1a\n\rnext_fee_step\x18\x0c \x01(\rH\n\x88\x01\x01\x12\x35\n\x08inflight\x18\r \x03(\x0b\x32#.cln.ListpeersPeersChannelsInflight\x12\x15\n\x08\x63lose_to\x18\x0e \x01(\x0cH\x0b\x88\x01\x01\x12\x14\n\x07private\x18\x0f \x01(\x08H\x0c\x88\x01\x01\x12 \n\x06opener\x18\x10 \x01(\x0e\x32\x10.cln.ChannelSide\x12%\n\x06\x63loser\x18\x11 \x01(\x0e\x32\x10.cln.ChannelSideH\r\x88\x01\x01\x12\x10\n\x08\x66\x65\x61tures\x18\x12 \x03(\t\x12\x38\n\x07\x66unding\x18\x13 \x01(\x0b\x32\".cln.ListpeersPeersChannelsFundingH\x0e\x88\x01\x01\x12$\n\nto_us_msat\x18\x14 \x01(\x0b\x32\x0b.cln.AmountH\x0f\x88\x01\x01\x12(\n\x0emin_to_us_msat\x18\x15 \x01(\x0b\x32\x0b.cln.AmountH\x10\x88\x01\x01\x12(\n\x0emax_to_us_msat\x18\x16 \x01(\x0b\x32\x0b.cln.AmountH\x11\x88\x01\x01\x12$\n\ntotal_msat\x18\x17 \x01(\x0b\x32\x0b.cln.AmountH\x12\x88\x01\x01\x12\'\n\rfee_base_msat\x18\x18 \x01(\x0b\x32\x0b.cln.AmountH\x13\x88\x01\x01\x12(\n\x1b\x66\x65\x65_proportional_millionths\x18\x19 \x01(\rH\x14\x88\x01\x01\x12)\n\x0f\x64ust_limit_msat\x18\x1a \x01(\x0b\x32\x0b.cln.AmountH\x15\x88\x01\x01\x12\x30\n\x16max_total_htlc_in_msat\x18\x1b \x01(\x0b\x32\x0b.cln.AmountH\x16\x88\x01\x01\x12,\n\x12their_reserve_msat\x18\x1c \x01(\x0b\x32\x0b.cln.AmountH\x17\x88\x01\x01\x12*\n\x10our_reserve_msat\x18\x1d \x01(\x0b\x32\x0b.cln.AmountH\x18\x88\x01\x01\x12(\n\x0espendable_msat\x18\x1e \x01(\x0b\x32\x0b.cln.AmountH\x19\x88\x01\x01\x12)\n\x0freceivable_msat\x18\x1f \x01(\x0b\x32\x0b.cln.AmountH\x1a\x88\x01\x01\x12.\n\x14minimum_htlc_in_msat\x18 \x01(\x0b\x32\x0b.cln.AmountH\x1b\x88\x01\x01\x12/\n\x15minimum_htlc_out_msat\x18\x30 \x01(\x0b\x32\x0b.cln.AmountH\x1c\x88\x01\x01\x12/\n\x15maximum_htlc_out_msat\x18\x31 \x01(\x0b\x32\x0b.cln.AmountH\x1d\x88\x01\x01\x12 \n\x13their_to_self_delay\x18! \x01(\rH\x1e\x88\x01\x01\x12\x1e\n\x11our_to_self_delay\x18\" \x01(\rH\x1f\x88\x01\x01\x12\x1f\n\x12max_accepted_htlcs\x18# \x01(\rH \x88\x01\x01\x12\x34\n\x05\x61lias\x18\x32 \x01(\x0b\x32 .cln.ListpeersPeersChannelsAliasH!\x88\x01\x01\x12\x0e\n\x06status\x18% \x03(\t\x12 \n\x13in_payments_offered\x18& \x01(\x04H\"\x88\x01\x01\x12)\n\x0fin_offered_msat\x18\' \x01(\x0b\x32\x0b.cln.AmountH#\x88\x01\x01\x12\"\n\x15in_payments_fulfilled\x18( \x01(\x04H$\x88\x01\x01\x12+\n\x11in_fulfilled_msat\x18) \x01(\x0b\x32\x0b.cln.AmountH%\x88\x01\x01\x12!\n\x14out_payments_offered\x18* \x01(\x04H&\x88\x01\x01\x12*\n\x10out_offered_msat\x18+ \x01(\x0b\x32\x0b.cln.AmountH\'\x88\x01\x01\x12#\n\x16out_payments_fulfilled\x18, \x01(\x04H(\x88\x01\x01\x12,\n\x12out_fulfilled_msat\x18- \x01(\x0b\x32\x0b.cln.AmountH)\x88\x01\x01\x12/\n\x05htlcs\x18. \x03(\x0b\x32 .cln.ListpeersPeersChannelsHtlcs\x12\x1a\n\rclose_to_addr\x18/ \x01(\tH*\x88\x01\x01\"\xa1\x02\n\x1bListpeersPeersChannelsState\x12\x0c\n\x08OPENINGD\x10\x00\x12\x1c\n\x18\x43HANNELD_AWAITING_LOCKIN\x10\x01\x12\x13\n\x0f\x43HANNELD_NORMAL\x10\x02\x12\x1a\n\x16\x43HANNELD_SHUTTING_DOWN\x10\x03\x12\x18\n\x14\x43LOSINGD_SIGEXCHANGE\x10\x04\x12\x15\n\x11\x43LOSINGD_COMPLETE\x10\x05\x12\x17\n\x13\x41WAITING_UNILATERAL\x10\x06\x12\x16\n\x12\x46UNDING_SPEND_SEEN\x10\x07\x12\x0b\n\x07ONCHAIN\x10\x08\x12\x17\n\x13\x44UALOPEND_OPEN_INIT\x10\t\x12\x1d\n\x19\x44UALOPEND_AWAITING_LOCKIN\x10\nB\x0f\n\r_scratch_txidB\n\n\x08_feerateB\x08\n\x06_ownerB\x13\n\x11_short_channel_idB\r\n\x0b_channel_idB\x0f\n\r_funding_txidB\x11\n\x0f_funding_outnumB\x12\n\x10_initial_feerateB\x0f\n\r_last_feerateB\x0f\n\r_next_feerateB\x10\n\x0e_next_fee_stepB\x0b\n\t_close_toB\n\n\x08_privateB\t\n\x07_closerB\n\n\x08_fundingB\r\n\x0b_to_us_msatB\x11\n\x0f_min_to_us_msatB\x11\n\x0f_max_to_us_msatB\r\n\x0b_total_msatB\x10\n\x0e_fee_base_msatB\x1e\n\x1c_fee_proportional_millionthsB\x12\n\x10_dust_limit_msatB\x19\n\x17_max_total_htlc_in_msatB\x15\n\x13_their_reserve_msatB\x13\n\x11_our_reserve_msatB\x11\n\x0f_spendable_msatB\x12\n\x10_receivable_msatB\x17\n\x15_minimum_htlc_in_msatB\x18\n\x16_minimum_htlc_out_msatB\x18\n\x16_maximum_htlc_out_msatB\x16\n\x14_their_to_self_delayB\x14\n\x12_our_to_self_delayB\x15\n\x13_max_accepted_htlcsB\x08\n\x06_aliasB\x16\n\x14_in_payments_offeredB\x12\n\x10_in_offered_msatB\x18\n\x16_in_payments_fulfilledB\x14\n\x12_in_fulfilled_msatB\x17\n\x15_out_payments_offeredB\x13\n\x11_out_offered_msatB\x19\n\x17_out_payments_fulfilledB\x15\n\x13_out_fulfilled_msatB\x10\n\x0e_close_to_addr\"=\n\x1dListpeersPeersChannelsFeerate\x12\r\n\x05perkw\x18\x01 \x01(\r\x12\r\n\x05perkb\x18\x02 \x01(\r\"\xc5\x01\n\x1eListpeersPeersChannelsInflight\x12\x14\n\x0c\x66unding_txid\x18\x01 \x01(\x0c\x12\x16\n\x0e\x66unding_outnum\x18\x02 \x01(\r\x12\x0f\n\x07\x66\x65\x65rate\x18\x03 \x01(\t\x12\'\n\x12total_funding_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10our_funding_msat\x18\x05 \x01(\x0b\x32\x0b.cln.Amount\x12\x14\n\x0cscratch_txid\x18\x06 \x01(\x0c\"\x9b\x02\n\x1dListpeersPeersChannelsFunding\x12%\n\x0bpushed_msat\x18\x03 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12%\n\x10local_funds_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12&\n\x11remote_funds_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\'\n\rfee_paid_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\'\n\rfee_rcvd_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x42\x0e\n\x0c_pushed_msatB\x10\n\x0e_fee_paid_msatB\x10\n\x0e_fee_rcvd_msat\"[\n\x1bListpeersPeersChannelsAlias\x12\x12\n\x05local\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06remote\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_localB\t\n\x07_remote\"\xf1\x02\n\x1bListpeersPeersChannelsHtlcs\x12X\n\tdirection\x18\x01 \x01(\x0e\x32\x45.cln.ListpeersPeersChannelsHtlcs.ListpeersPeersChannelsHtlcsDirection\x12\n\n\x02id\x18\x02 \x01(\x04\x12 \n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.Amount\x12\x0e\n\x06\x65xpiry\x18\x04 \x01(\r\x12\x14\n\x0cpayment_hash\x18\x05 \x01(\x0c\x12\x1a\n\rlocal_trimmed\x18\x06 \x01(\x08H\x00\x88\x01\x01\x12\x13\n\x06status\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x1d\n\x05state\x18\x08 \x01(\x0e\x32\x0e.cln.HtlcState\"7\n$ListpeersPeersChannelsHtlcsDirection\x12\x06\n\x02IN\x10\x00\x12\x07\n\x03OUT\x10\x01\x42\x10\n\x0e_local_trimmedB\t\n\x07_status\"0\n\x10ListfundsRequest\x12\x12\n\x05spent\x18\x01 \x01(\x08H\x00\x88\x01\x01\x42\x08\n\x06_spent\"e\n\x11ListfundsResponse\x12&\n\x07outputs\x18\x01 \x03(\x0b\x32\x15.cln.ListfundsOutputs\x12(\n\x08\x63hannels\x18\x02 \x03(\x0b\x32\x16.cln.ListfundsChannels\"\x83\x03\n\x10ListfundsOutputs\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\x0e\n\x06output\x18\x02 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.Amount\x12\x14\n\x0cscriptpubkey\x18\x04 \x01(\x0c\x12\x14\n\x07\x61\x64\x64ress\x18\x05 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0credeemscript\x18\x06 \x01(\x0cH\x01\x88\x01\x01\x12<\n\x06status\x18\x07 \x01(\x0e\x32,.cln.ListfundsOutputs.ListfundsOutputsStatus\x12\x10\n\x08reserved\x18\t \x01(\x08\x12\x18\n\x0b\x62lockheight\x18\x08 \x01(\rH\x02\x88\x01\x01\"Q\n\x16ListfundsOutputsStatus\x12\x0f\n\x0bUNCONFIRMED\x10\x00\x12\r\n\tCONFIRMED\x10\x01\x12\t\n\x05SPENT\x10\x02\x12\x0c\n\x08IMMATURE\x10\x03\x42\n\n\x08_addressB\x0f\n\r_redeemscriptB\x0e\n\x0c_blockheight\"\xab\x02\n\x11ListfundsChannels\x12\x0f\n\x07peer_id\x18\x01 \x01(\x0c\x12$\n\x0four_amount_msat\x18\x02 \x01(\x0b\x32\x0b.cln.Amount\x12 \n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.Amount\x12\x14\n\x0c\x66unding_txid\x18\x04 \x01(\x0c\x12\x16\n\x0e\x66unding_output\x18\x05 \x01(\r\x12\x11\n\tconnected\x18\x06 \x01(\x08\x12 \n\x05state\x18\x07 \x01(\x0e\x32\x11.cln.ChannelState\x12\x17\n\nchannel_id\x18\t \x01(\x0cH\x00\x88\x01\x01\x12\x1d\n\x10short_channel_id\x18\x08 \x01(\tH\x01\x88\x01\x01\x42\r\n\x0b_channel_idB\x13\n\x11_short_channel_id\"\xdd\x02\n\x0eSendpayRequest\x12 \n\x05route\x18\x01 \x03(\x0b\x32\x11.cln.SendpayRoute\x12\x14\n\x0cpayment_hash\x18\x02 \x01(\x0c\x12\x12\n\x05label\x18\x03 \x01(\tH\x00\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x05 \x01(\tH\x02\x88\x01\x01\x12\x1b\n\x0epayment_secret\x18\x06 \x01(\x0cH\x03\x88\x01\x01\x12\x13\n\x06partid\x18\x07 \x01(\rH\x04\x88\x01\x01\x12\x1a\n\rlocalinvreqid\x18\x0b \x01(\x0cH\x05\x88\x01\x01\x12\x14\n\x07groupid\x18\t \x01(\x04H\x06\x88\x01\x01\x42\x08\n\x06_labelB\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\x11\n\x0f_payment_secretB\t\n\x07_partidB\x10\n\x0e_localinvreqidB\n\n\x08_groupid\"\xd1\x04\n\x0fSendpayResponse\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x14\n\x07groupid\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x32\n\x06status\x18\x04 \x01(\x0e\x32\".cln.SendpayResponse.SendpayStatus\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x06 \x01(\x0cH\x02\x88\x01\x01\x12\x12\n\ncreated_at\x18\x07 \x01(\x04\x12\x19\n\x0c\x63ompleted_at\x18\x0f \x01(\x04H\x03\x88\x01\x01\x12%\n\x10\x61mount_sent_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\t \x01(\tH\x04\x88\x01\x01\x12\x13\n\x06partid\x18\n \x01(\x04H\x05\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x0b \x01(\tH\x06\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x0c \x01(\tH\x07\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\r \x01(\x0cH\x08\x88\x01\x01\x12\x14\n\x07message\x18\x0e \x01(\tH\t\x88\x01\x01\"*\n\rSendpayStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x42\n\n\x08_groupidB\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x0f\n\r_completed_atB\x08\n\x06_labelB\t\n\x07_partidB\t\n\x07_bolt11B\t\n\x07_bolt12B\x13\n\x11_payment_preimageB\n\n\x08_message\"\\\n\x0cSendpayRoute\x12 \n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.Amount\x12\n\n\x02id\x18\x02 \x01(\x0c\x12\r\n\x05\x64\x65lay\x18\x03 \x01(\r\x12\x0f\n\x07\x63hannel\x18\x04 \x01(\t\"\x93\x01\n\x13ListchannelsRequest\x12\x1d\n\x10short_channel_id\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06source\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x03 \x01(\x0cH\x02\x88\x01\x01\x42\x13\n\x11_short_channel_idB\t\n\x07_sourceB\x0e\n\x0c_destination\"C\n\x14ListchannelsResponse\x12+\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x19.cln.ListchannelsChannels\"\xb3\x03\n\x14ListchannelsChannels\x12\x0e\n\x06source\x18\x01 \x01(\x0c\x12\x13\n\x0b\x64\x65stination\x18\x02 \x01(\x0c\x12\x18\n\x10short_channel_id\x18\x03 \x01(\t\x12\x11\n\tdirection\x18\x10 \x01(\r\x12\x0e\n\x06public\x18\x04 \x01(\x08\x12 \n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.Amount\x12\x15\n\rmessage_flags\x18\x06 \x01(\r\x12\x15\n\rchannel_flags\x18\x07 \x01(\r\x12\x0e\n\x06\x61\x63tive\x18\x08 \x01(\x08\x12\x13\n\x0blast_update\x18\t \x01(\r\x12\x1d\n\x15\x62\x61se_fee_millisatoshi\x18\n \x01(\r\x12\x19\n\x11\x66\x65\x65_per_millionth\x18\x0b \x01(\r\x12\r\n\x05\x64\x65lay\x18\x0c \x01(\r\x12&\n\x11htlc_minimum_msat\x18\r \x01(\x0b\x32\x0b.cln.Amount\x12+\n\x11htlc_maximum_msat\x18\x0e \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x10\n\x08\x66\x65\x61tures\x18\x0f \x01(\x0c\x42\x14\n\x12_htlc_maximum_msat\"#\n\x10\x41\x64\x64gossipRequest\x12\x0f\n\x07message\x18\x01 \x01(\x0c\"\x13\n\x11\x41\x64\x64gossipResponse\"o\n\x17\x41utocleaninvoiceRequest\x12\x17\n\nexpired_by\x18\x01 \x01(\x04H\x00\x88\x01\x01\x12\x1a\n\rcycle_seconds\x18\x02 \x01(\x04H\x01\x88\x01\x01\x42\r\n\x0b_expired_byB\x10\n\x0e_cycle_seconds\"\x81\x01\n\x18\x41utocleaninvoiceResponse\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\x12\x17\n\nexpired_by\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x1a\n\rcycle_seconds\x18\x03 \x01(\x04H\x01\x88\x01\x01\x42\r\n\x0b_expired_byB\x10\n\x0e_cycle_seconds\"U\n\x13\x43heckmessageRequest\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\r\n\x05zbase\x18\x02 \x01(\t\x12\x13\n\x06pubkey\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x42\t\n\x07_pubkey\"8\n\x14\x43heckmessageResponse\x12\x10\n\x08verified\x18\x01 \x01(\x08\x12\x0e\n\x06pubkey\x18\x02 \x01(\x0c\"\xcb\x02\n\x0c\x43loseRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\x1e\n\x11unilateraltimeout\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x03 \x01(\tH\x01\x88\x01\x01\x12!\n\x14\x66\x65\x65_negotiation_step\x18\x04 \x01(\tH\x02\x88\x01\x01\x12)\n\rwrong_funding\x18\x05 \x01(\x0b\x32\r.cln.OutpointH\x03\x88\x01\x01\x12\x1f\n\x12\x66orce_lease_closed\x18\x06 \x01(\x08H\x04\x88\x01\x01\x12\x1e\n\x08\x66\x65\x65range\x18\x07 \x03(\x0b\x32\x0c.cln.FeerateB\x14\n\x12_unilateraltimeoutB\x0e\n\x0c_destinationB\x17\n\x15_fee_negotiation_stepB\x10\n\x0e_wrong_fundingB\x15\n\x13_force_lease_closed\"\xab\x01\n\rCloseResponse\x12/\n\titem_type\x18\x01 \x01(\x0e\x32\x1c.cln.CloseResponse.CloseType\x12\x0f\n\x02tx\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x11\n\x04txid\x18\x03 \x01(\x0cH\x01\x88\x01\x01\"5\n\tCloseType\x12\n\n\x06MUTUAL\x10\x00\x12\x0e\n\nUNILATERAL\x10\x01\x12\x0c\n\x08UNOPENED\x10\x02\x42\x05\n\x03_txB\x07\n\x05_txid\"T\n\x0e\x43onnectRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\x11\n\x04host\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x11\n\x04port\x18\x03 \x01(\rH\x01\x88\x01\x01\x42\x07\n\x05_hostB\x07\n\x05_port\"\xb4\x01\n\x0f\x43onnectResponse\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x10\n\x08\x66\x65\x61tures\x18\x02 \x01(\x0c\x12\x38\n\tdirection\x18\x03 \x01(\x0e\x32%.cln.ConnectResponse.ConnectDirection\x12$\n\x07\x61\x64\x64ress\x18\x04 \x01(\x0b\x32\x13.cln.ConnectAddress\"#\n\x10\x43onnectDirection\x12\x06\n\x02IN\x10\x00\x12\x07\n\x03OUT\x10\x01\"\xfb\x01\n\x0e\x43onnectAddress\x12\x39\n\titem_type\x18\x01 \x01(\x0e\x32&.cln.ConnectAddress.ConnectAddressType\x12\x13\n\x06socket\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x11\n\x04port\x18\x04 \x01(\rH\x02\x88\x01\x01\"P\n\x12\x43onnectAddressType\x12\x10\n\x0cLOCAL_SOCKET\x10\x00\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x42\t\n\x07_socketB\n\n\x08_addressB\x07\n\x05_port\"J\n\x14\x43reateinvoiceRequest\x12\x11\n\tinvstring\x18\x01 \x01(\t\x12\r\n\x05label\x18\x02 \x01(\t\x12\x10\n\x08preimage\x18\x03 \x01(\x0c\"\x81\x05\n\x15\x43reateinvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x06\x62olt11\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x04 \x01(\x0c\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12>\n\x06status\x18\x06 \x01(\x0e\x32..cln.CreateinvoiceResponse.CreateinvoiceStatus\x12\x13\n\x0b\x64\x65scription\x18\x07 \x01(\t\x12\x12\n\nexpires_at\x18\x08 \x01(\x04\x12\x16\n\tpay_index\x18\t \x01(\x04H\x03\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12\x14\n\x07paid_at\x18\x0b \x01(\x04H\x05\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\x06\x88\x01\x01\x12\x1b\n\x0elocal_offer_id\x18\r \x01(\x0cH\x07\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x0f \x01(\tH\x08\x88\x01\x01\"8\n\x13\x43reateinvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x12\n\n\x06UNPAID\x10\x02\x42\t\n\x07_bolt11B\t\n\x07_bolt12B\x0e\n\x0c_amount_msatB\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x13\n\x11_payment_preimageB\x11\n\x0f_local_offer_idB\x14\n\x12_invreq_payer_note\"\xb4\x02\n\x10\x44\x61tastoreRequest\x12\x0b\n\x03key\x18\x05 \x03(\t\x12\x13\n\x06string\x18\x06 \x01(\tH\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12\x36\n\x04mode\x18\x03 \x01(\x0e\x32#.cln.DatastoreRequest.DatastoreModeH\x02\x88\x01\x01\x12\x17\n\ngeneration\x18\x04 \x01(\x04H\x03\x88\x01\x01\"p\n\rDatastoreMode\x12\x0f\n\x0bMUST_CREATE\x10\x00\x12\x10\n\x0cMUST_REPLACE\x10\x01\x12\x15\n\x11\x43REATE_OR_REPLACE\x10\x02\x12\x0f\n\x0bMUST_APPEND\x10\x03\x12\x14\n\x10\x43REATE_OR_APPEND\x10\x04\x42\t\n\x07_stringB\x06\n\x04_hexB\x07\n\x05_modeB\r\n\x0b_generation\"\x82\x01\n\x11\x44\x61tastoreResponse\x12\x0b\n\x03key\x18\x05 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x06string\x18\x04 \x01(\tH\x02\x88\x01\x01\x42\r\n\x0b_generationB\x06\n\x04_hexB\t\n\x07_string\"\x9d\x01\n\x12\x43reateonionRequest\x12\"\n\x04hops\x18\x01 \x03(\x0b\x32\x14.cln.CreateonionHops\x12\x11\n\tassocdata\x18\x02 \x01(\x0c\x12\x18\n\x0bsession_key\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x12\x17\n\nonion_size\x18\x04 \x01(\rH\x01\x88\x01\x01\x42\x0e\n\x0c_session_keyB\r\n\x0b_onion_size\"<\n\x13\x43reateonionResponse\x12\r\n\x05onion\x18\x01 \x01(\x0c\x12\x16\n\x0eshared_secrets\x18\x02 \x03(\x0c\"2\n\x0f\x43reateonionHops\x12\x0e\n\x06pubkey\x18\x01 \x01(\x0c\x12\x0f\n\x07payload\x18\x02 \x01(\x0c\"J\n\x13\x44\x65ldatastoreRequest\x12\x0b\n\x03key\x18\x03 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\r\n\x0b_generation\"\x85\x01\n\x14\x44\x65ldatastoreResponse\x12\x0b\n\x03key\x18\x05 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x06string\x18\x04 \x01(\tH\x02\x88\x01\x01\x42\r\n\x0b_generationB\x06\n\x04_hexB\t\n\x07_string\"H\n\x18\x44\x65lexpiredinvoiceRequest\x12\x1a\n\rmaxexpirytime\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\x10\n\x0e_maxexpirytime\"\x1b\n\x19\x44\x65lexpiredinvoiceResponse\"\xb6\x01\n\x11\x44\x65linvoiceRequest\x12\r\n\x05label\x18\x01 \x01(\t\x12\x37\n\x06status\x18\x02 \x01(\x0e\x32\'.cln.DelinvoiceRequest.DelinvoiceStatus\x12\x15\n\x08\x64\x65sconly\x18\x03 \x01(\x08H\x00\x88\x01\x01\"5\n\x10\x44\x65linvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x12\n\n\x06UNPAID\x10\x02\x42\x0b\n\t_desconly\"\xc5\x03\n\x12\x44\x65linvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x06\x62olt11\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x03 \x01(\tH\x01\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x05 \x01(\tH\x03\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x06 \x01(\x0c\x12\x38\n\x06status\x18\x07 \x01(\x0e\x32(.cln.DelinvoiceResponse.DelinvoiceStatus\x12\x12\n\nexpires_at\x18\x08 \x01(\x04\x12\x1b\n\x0elocal_offer_id\x18\t \x01(\x0cH\x04\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x0b \x01(\tH\x05\x88\x01\x01\"5\n\x10\x44\x65linvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x12\n\n\x06UNPAID\x10\x02\x42\t\n\x07_bolt11B\t\n\x07_bolt12B\x0e\n\x0c_amount_msatB\x0e\n\x0c_descriptionB\x11\n\x0f_local_offer_idB\x14\n\x12_invreq_payer_note\"\xfa\x01\n\x0eInvoiceRequest\x12%\n\x0b\x61mount_msat\x18\n \x01(\x0b\x32\x10.cln.AmountOrAny\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\r\n\x05label\x18\x03 \x01(\t\x12\x13\n\x06\x65xpiry\x18\x07 \x01(\x04H\x00\x88\x01\x01\x12\x11\n\tfallbacks\x18\x04 \x03(\t\x12\x15\n\x08preimage\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\x11\n\x04\x63ltv\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x19\n\x0c\x64\x65schashonly\x18\t \x01(\x08H\x03\x88\x01\x01\x42\t\n\x07_expiryB\x0b\n\t_preimageB\x07\n\x05_cltvB\x0f\n\r_deschashonly\"\xe7\x02\n\x0fInvoiceResponse\x12\x0e\n\x06\x62olt11\x18\x01 \x01(\t\x12\x14\n\x0cpayment_hash\x18\x02 \x01(\x0c\x12\x16\n\x0epayment_secret\x18\x03 \x01(\x0c\x12\x12\n\nexpires_at\x18\x04 \x01(\x04\x12\x1d\n\x10warning_capacity\x18\x05 \x01(\tH\x00\x88\x01\x01\x12\x1c\n\x0fwarning_offline\x18\x06 \x01(\tH\x01\x88\x01\x01\x12\x1d\n\x10warning_deadends\x18\x07 \x01(\tH\x02\x88\x01\x01\x12#\n\x16warning_private_unused\x18\x08 \x01(\tH\x03\x88\x01\x01\x12\x18\n\x0bwarning_mpp\x18\t \x01(\tH\x04\x88\x01\x01\x42\x13\n\x11_warning_capacityB\x12\n\x10_warning_offlineB\x13\n\x11_warning_deadendsB\x19\n\x17_warning_private_unusedB\x0e\n\x0c_warning_mpp\"#\n\x14ListdatastoreRequest\x12\x0b\n\x03key\x18\x02 \x03(\t\"G\n\x15ListdatastoreResponse\x12.\n\tdatastore\x18\x01 \x03(\x0b\x32\x1b.cln.ListdatastoreDatastore\"\x87\x01\n\x16ListdatastoreDatastore\x12\x0b\n\x03key\x18\x01 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x06string\x18\x04 \x01(\tH\x02\x88\x01\x01\x42\r\n\x0b_generationB\x06\n\x04_hexB\t\n\x07_string\"\xa9\x01\n\x13ListinvoicesRequest\x12\x12\n\x05label\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tinvstring\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x03 \x01(\x0cH\x02\x88\x01\x01\x12\x15\n\x08offer_id\x18\x04 \x01(\tH\x03\x88\x01\x01\x42\x08\n\x06_labelB\x0c\n\n_invstringB\x0f\n\r_payment_hashB\x0b\n\t_offer_id\"C\n\x14ListinvoicesResponse\x12+\n\x08invoices\x18\x01 \x03(\x0b\x32\x19.cln.ListinvoicesInvoices\"\xa2\x05\n\x14ListinvoicesInvoices\x12\r\n\x05label\x18\x01 \x01(\t\x12\x18\n\x0b\x64\x65scription\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x44\n\x06status\x18\x04 \x01(\x0e\x32\x34.cln.ListinvoicesInvoices.ListinvoicesInvoicesStatus\x12\x12\n\nexpires_at\x18\x05 \x01(\x04\x12%\n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x02\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x08 \x01(\tH\x03\x88\x01\x01\x12\x1b\n\x0elocal_offer_id\x18\t \x01(\x0cH\x04\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x0f \x01(\tH\x05\x88\x01\x01\x12\x16\n\tpay_index\x18\x0b \x01(\x04H\x06\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\x0c \x01(\x0b\x32\x0b.cln.AmountH\x07\x88\x01\x01\x12\x14\n\x07paid_at\x18\r \x01(\x04H\x08\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0e \x01(\x0cH\t\x88\x01\x01\"?\n\x1aListinvoicesInvoicesStatus\x12\n\n\x06UNPAID\x10\x00\x12\x08\n\x04PAID\x10\x01\x12\x0b\n\x07\x45XPIRED\x10\x02\x42\x0e\n\x0c_descriptionB\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\t\n\x07_bolt12B\x11\n\x0f_local_offer_idB\x14\n\x12_invreq_payer_noteB\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x13\n\x11_payment_preimage\"\x8a\x03\n\x10SendonionRequest\x12\r\n\x05onion\x18\x01 \x01(\x0c\x12*\n\tfirst_hop\x18\x02 \x01(\x0b\x32\x17.cln.SendonionFirst_hop\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x12\n\x05label\x18\x04 \x01(\tH\x00\x88\x01\x01\x12\x16\n\x0eshared_secrets\x18\x05 \x03(\x0c\x12\x13\n\x06partid\x18\x06 \x01(\rH\x01\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x02\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x0c \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\t \x01(\x0cH\x04\x88\x01\x01\x12\x1a\n\rlocalinvreqid\x18\r \x01(\x0cH\x05\x88\x01\x01\x12\x14\n\x07groupid\x18\x0b \x01(\x04H\x06\x88\x01\x01\x42\x08\n\x06_labelB\t\n\x07_partidB\t\n\x07_bolt11B\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x10\n\x0e_localinvreqidB\n\n\x08_groupid\"\x8b\x04\n\x11SendonionResponse\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x14\n\x0cpayment_hash\x18\x02 \x01(\x0c\x12\x36\n\x06status\x18\x03 \x01(\x0e\x32&.cln.SendonionResponse.SendonionStatus\x12%\n\x0b\x61mount_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\x12\n\ncreated_at\x18\x06 \x01(\x04\x12%\n\x10\x61mount_sent_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\x08 \x01(\tH\x02\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\t \x01(\tH\x03\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\n \x01(\tH\x04\x88\x01\x01\x12\x13\n\x06partid\x18\r \x01(\x04H\x05\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0b \x01(\x0cH\x06\x88\x01\x01\x12\x14\n\x07message\x18\x0c \x01(\tH\x07\x88\x01\x01\",\n\x0fSendonionStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x42\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x08\n\x06_labelB\t\n\x07_bolt11B\t\n\x07_bolt12B\t\n\x07_partidB\x13\n\x11_payment_preimageB\n\n\x08_message\"Q\n\x12SendonionFirst_hop\x12\n\n\x02id\x18\x01 \x01(\x0c\x12 \n\x0b\x61mount_msat\x18\x02 \x01(\x0b\x32\x0b.cln.Amount\x12\r\n\x05\x64\x65lay\x18\x03 \x01(\r\"\xeb\x01\n\x13ListsendpaysRequest\x12\x13\n\x06\x62olt11\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12@\n\x06status\x18\x03 \x01(\x0e\x32+.cln.ListsendpaysRequest.ListsendpaysStatusH\x02\x88\x01\x01\";\n\x12ListsendpaysStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x42\t\n\x07_bolt11B\x0f\n\r_payment_hashB\t\n\x07_status\"C\n\x14ListsendpaysResponse\x12+\n\x08payments\x18\x01 \x03(\x0b\x32\x19.cln.ListsendpaysPayments\"\xf4\x04\n\x14ListsendpaysPayments\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x0f\n\x07groupid\x18\x02 \x01(\x04\x12\x13\n\x06partid\x18\x0f \x01(\x04H\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x44\n\x06status\x18\x04 \x01(\x0e\x32\x34.cln.ListsendpaysPayments.ListsendpaysPaymentsStatus\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x06 \x01(\x0cH\x02\x88\x01\x01\x12\x12\n\ncreated_at\x18\x07 \x01(\x04\x12%\n\x10\x61mount_sent_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\t \x01(\tH\x03\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\n \x01(\tH\x04\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x0e \x01(\tH\x05\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x0b \x01(\tH\x06\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\x07\x88\x01\x01\x12\x17\n\nerroronion\x18\r \x01(\x0cH\x08\x88\x01\x01\"C\n\x1aListsendpaysPaymentsStatus\x12\x0b\n\x07PENDING\x10\x00\x12\n\n\x06\x46\x41ILED\x10\x01\x12\x0c\n\x08\x43OMPLETE\x10\x02\x42\t\n\x07_partidB\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x08\n\x06_labelB\t\n\x07_bolt11B\x0e\n\x0c_descriptionB\t\n\x07_bolt12B\x13\n\x11_payment_preimageB\r\n\x0b_erroronion\"\x19\n\x17ListtransactionsRequest\"S\n\x18ListtransactionsResponse\x12\x37\n\x0ctransactions\x18\x01 \x03(\x0b\x32!.cln.ListtransactionsTransactions\"\xf8\x01\n\x1cListtransactionsTransactions\x12\x0c\n\x04hash\x18\x01 \x01(\x0c\x12\r\n\x05rawtx\x18\x02 \x01(\x0c\x12\x13\n\x0b\x62lockheight\x18\x03 \x01(\r\x12\x0f\n\x07txindex\x18\x04 \x01(\r\x12\x10\n\x08locktime\x18\x07 \x01(\r\x12\x0f\n\x07version\x18\x08 \x01(\r\x12\x37\n\x06inputs\x18\t \x03(\x0b\x32\'.cln.ListtransactionsTransactionsInputs\x12\x39\n\x07outputs\x18\n \x03(\x0b\x32(.cln.ListtransactionsTransactionsOutputs\"S\n\"ListtransactionsTransactionsInputs\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\r\n\x05index\x18\x02 \x01(\r\x12\x10\n\x08sequence\x18\x03 \x01(\r\"l\n#ListtransactionsTransactionsOutputs\x12\r\n\x05index\x18\x01 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12\x14\n\x0cscriptPubKey\x18\x03 \x01(\x0c\"\xda\x03\n\nPayRequest\x12\x0e\n\x06\x62olt11\x18\x01 \x01(\t\x12%\n\x0b\x61mount_msat\x18\r \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x12\n\x05label\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x17\n\nriskfactor\x18\x08 \x01(\x01H\x02\x88\x01\x01\x12\x1a\n\rmaxfeepercent\x18\x04 \x01(\x01H\x03\x88\x01\x01\x12\x16\n\tretry_for\x18\x05 \x01(\rH\x04\x88\x01\x01\x12\x15\n\x08maxdelay\x18\x06 \x01(\rH\x05\x88\x01\x01\x12#\n\texemptfee\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\x1a\n\rlocalinvreqid\x18\x0e \x01(\x0cH\x07\x88\x01\x01\x12\x0f\n\x07\x65xclude\x18\n \x03(\t\x12 \n\x06maxfee\x18\x0b \x01(\x0b\x32\x0b.cln.AmountH\x08\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x0c \x01(\tH\t\x88\x01\x01\x42\x0e\n\x0c_amount_msatB\x08\n\x06_labelB\r\n\x0b_riskfactorB\x10\n\x0e_maxfeepercentB\x0c\n\n_retry_forB\x0b\n\t_maxdelayB\x0c\n\n_exemptfeeB\x10\n\x0e_localinvreqidB\t\n\x07_maxfeeB\x0e\n\x0c_description\"\xfb\x02\n\x0bPayResponse\x12\x18\n\x10payment_preimage\x18\x01 \x01(\x0c\x12\x18\n\x0b\x64\x65stination\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x12\n\ncreated_at\x18\x04 \x01(\x01\x12\r\n\x05parts\x18\x05 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10\x61mount_sent_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\'\n\x1awarning_partial_completion\x18\x08 \x01(\tH\x01\x88\x01\x01\x12*\n\x06status\x18\t \x01(\x0e\x32\x1a.cln.PayResponse.PayStatus\"2\n\tPayStatus\x12\x0c\n\x08\x43OMPLETE\x10\x00\x12\x0b\n\x07PENDING\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x42\x0e\n\x0c_destinationB\x1d\n\x1b_warning_partial_completion\"*\n\x10ListnodesRequest\x12\x0f\n\x02id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x05\n\x03_id\"7\n\x11ListnodesResponse\x12\"\n\x05nodes\x18\x01 \x03(\x0b\x32\x13.cln.ListnodesNodes\"\xe1\x01\n\x0eListnodesNodes\x12\x0e\n\x06nodeid\x18\x01 \x01(\x0c\x12\x1b\n\x0elast_timestamp\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x12\n\x05\x61lias\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x12\n\x05\x63olor\x18\x04 \x01(\x0cH\x02\x88\x01\x01\x12\x15\n\x08\x66\x65\x61tures\x18\x05 \x01(\x0cH\x03\x88\x01\x01\x12/\n\taddresses\x18\x06 \x03(\x0b\x32\x1c.cln.ListnodesNodesAddressesB\x11\n\x0f_last_timestampB\x08\n\x06_aliasB\x08\n\x06_colorB\x0b\n\t_features\"\xe8\x01\n\x17ListnodesNodesAddresses\x12K\n\titem_type\x18\x01 \x01(\x0e\x32\x38.cln.ListnodesNodesAddresses.ListnodesNodesAddressesType\x12\x0c\n\x04port\x18\x02 \x01(\r\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x00\x88\x01\x01\"P\n\x1bListnodesNodesAddressesType\x12\x07\n\x03\x44NS\x10\x00\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x42\n\n\x08_address\"g\n\x15WaitanyinvoiceRequest\x12\x1a\n\rlastpay_index\x18\x01 \x01(\x04H\x00\x88\x01\x01\x12\x14\n\x07timeout\x18\x02 \x01(\x04H\x01\x88\x01\x01\x42\x10\n\x0e_lastpay_indexB\n\n\x08_timeout\"\x93\x04\n\x16WaitanyinvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12@\n\x06status\x18\x04 \x01(\x0e\x32\x30.cln.WaitanyinvoiceResponse.WaitanyinvoiceStatus\x12\x12\n\nexpires_at\x18\x05 \x01(\x04\x12%\n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x08 \x01(\tH\x02\x88\x01\x01\x12\x16\n\tpay_index\x18\t \x01(\x04H\x03\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12\x14\n\x07paid_at\x18\x0b \x01(\x04H\x05\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\x06\x88\x01\x01\"-\n\x14WaitanyinvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x42\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\t\n\x07_bolt12B\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x13\n\x11_payment_preimage\"#\n\x12WaitinvoiceRequest\x12\r\n\x05label\x18\x01 \x01(\t\"\x87\x04\n\x13WaitinvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12:\n\x06status\x18\x04 \x01(\x0e\x32*.cln.WaitinvoiceResponse.WaitinvoiceStatus\x12\x12\n\nexpires_at\x18\x05 \x01(\x04\x12%\n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x08 \x01(\tH\x02\x88\x01\x01\x12\x16\n\tpay_index\x18\t \x01(\x04H\x03\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12\x14\n\x07paid_at\x18\x0b \x01(\x04H\x05\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\x06\x88\x01\x01\"*\n\x11WaitinvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x42\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\t\n\x07_bolt12B\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x13\n\x11_payment_preimage\"\x8e\x01\n\x12WaitsendpayRequest\x12\x14\n\x0cpayment_hash\x18\x01 \x01(\x0c\x12\x14\n\x07timeout\x18\x03 \x01(\rH\x00\x88\x01\x01\x12\x13\n\x06partid\x18\x02 \x01(\x04H\x01\x88\x01\x01\x12\x14\n\x07groupid\x18\x04 \x01(\x04H\x02\x88\x01\x01\x42\n\n\x08_timeoutB\t\n\x07_partidB\n\n\x08_groupid\"\xb2\x04\n\x13WaitsendpayResponse\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x14\n\x07groupid\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12:\n\x06status\x18\x04 \x01(\x0e\x32*.cln.WaitsendpayResponse.WaitsendpayStatus\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x06 \x01(\x0cH\x02\x88\x01\x01\x12\x12\n\ncreated_at\x18\x07 \x01(\x04\x12\x19\n\x0c\x63ompleted_at\x18\x0e \x01(\x01H\x03\x88\x01\x01\x12%\n\x10\x61mount_sent_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\t \x01(\tH\x04\x88\x01\x01\x12\x13\n\x06partid\x18\n \x01(\x04H\x05\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x0b \x01(\tH\x06\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x0c \x01(\tH\x07\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\r \x01(\x0cH\x08\x88\x01\x01\"!\n\x11WaitsendpayStatus\x12\x0c\n\x08\x43OMPLETE\x10\x00\x42\n\n\x08_groupidB\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x0f\n\r_completed_atB\x08\n\x06_labelB\t\n\x07_partidB\t\n\x07_bolt11B\t\n\x07_bolt12B\x13\n\x11_payment_preimage\"\x8d\x01\n\x0eNewaddrRequest\x12@\n\x0b\x61\x64\x64resstype\x18\x01 \x01(\x0e\x32&.cln.NewaddrRequest.NewaddrAddresstypeH\x00\x88\x01\x01\")\n\x12NewaddrAddresstype\x12\n\n\x06\x42\x45\x43H32\x10\x00\x12\x07\n\x03\x41LL\x10\x02\x42\x0e\n\x0c_addresstype\"[\n\x0fNewaddrResponse\x12\x13\n\x06\x62\x65\x63h32\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0bp2sh_segwit\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\t\n\x07_bech32B\x0e\n\x0c_p2sh_segwit\"\xca\x01\n\x0fWithdrawRequest\x12\x13\n\x0b\x64\x65stination\x18\x01 \x01(\t\x12&\n\x07satoshi\x18\x02 \x01(\x0b\x32\x10.cln.AmountOrAllH\x00\x88\x01\x01\x12\"\n\x07\x66\x65\x65rate\x18\x05 \x01(\x0b\x32\x0c.cln.FeerateH\x01\x88\x01\x01\x12\x14\n\x07minconf\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\x1c\n\x05utxos\x18\x04 \x03(\x0b\x32\r.cln.OutpointB\n\n\x08_satoshiB\n\n\x08_feerateB\n\n\x08_minconf\":\n\x10WithdrawResponse\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\x12\x0c\n\x04psbt\x18\x03 \x01(\t\"\x82\x03\n\x0eKeysendRequest\x12\x13\n\x0b\x64\x65stination\x18\x01 \x01(\x0c\x12 \n\x0b\x61mount_msat\x18\n \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x1a\n\rmaxfeepercent\x18\x04 \x01(\x01H\x01\x88\x01\x01\x12\x16\n\tretry_for\x18\x05 \x01(\rH\x02\x88\x01\x01\x12\x15\n\x08maxdelay\x18\x06 \x01(\rH\x03\x88\x01\x01\x12#\n\texemptfee\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12+\n\nroutehints\x18\x08 \x01(\x0b\x32\x12.cln.RoutehintListH\x05\x88\x01\x01\x12&\n\textratlvs\x18\t \x01(\x0b\x32\x0e.cln.TlvStreamH\x06\x88\x01\x01\x42\x08\n\x06_labelB\x10\n\x0e_maxfeepercentB\x0c\n\n_retry_forB\x0b\n\t_maxdelayB\x0c\n\n_exemptfeeB\r\n\x0b_routehintsB\x0c\n\n_extratlvs\"\xf2\x02\n\x0fKeysendResponse\x12\x18\n\x10payment_preimage\x18\x01 \x01(\x0c\x12\x18\n\x0b\x64\x65stination\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x12\n\ncreated_at\x18\x04 \x01(\x01\x12\r\n\x05parts\x18\x05 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10\x61mount_sent_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\'\n\x1awarning_partial_completion\x18\x08 \x01(\tH\x01\x88\x01\x01\x12\x32\n\x06status\x18\t \x01(\x0e\x32\".cln.KeysendResponse.KeysendStatus\"\x1d\n\rKeysendStatus\x12\x0c\n\x08\x43OMPLETE\x10\x00\x42\x0e\n\x0c_destinationB\x1d\n\x1b_warning_partial_completion\"\xbc\x02\n\x0f\x46undpsbtRequest\x12!\n\x07satoshi\x18\x01 \x01(\x0b\x32\x10.cln.AmountOrAll\x12\x1d\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.Feerate\x12\x13\n\x0bstartweight\x18\x03 \x01(\r\x12\x14\n\x07minconf\x18\x04 \x01(\rH\x00\x88\x01\x01\x12\x14\n\x07reserve\x18\x05 \x01(\rH\x01\x88\x01\x01\x12\x15\n\x08locktime\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x1f\n\x12min_witness_weight\x18\x07 \x01(\rH\x03\x88\x01\x01\x12\x1d\n\x10\x65xcess_as_change\x18\x08 \x01(\x08H\x04\x88\x01\x01\x42\n\n\x08_minconfB\n\n\x08_reserveB\x0b\n\t_locktimeB\x15\n\x13_min_witness_weightB\x13\n\x11_excess_as_change\"\xd9\x01\n\x10\x46undpsbtResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x16\n\x0e\x66\x65\x65rate_per_kw\x18\x02 \x01(\r\x12\x1e\n\x16\x65stimated_final_weight\x18\x03 \x01(\r\x12 \n\x0b\x65xcess_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12\x1a\n\rchange_outnum\x18\x05 \x01(\rH\x00\x88\x01\x01\x12/\n\x0creservations\x18\x06 \x03(\x0b\x32\x19.cln.FundpsbtReservationsB\x10\n\x0e_change_outnum\"u\n\x14\x46undpsbtReservations\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\x0c\n\x04vout\x18\x02 \x01(\r\x12\x14\n\x0cwas_reserved\x18\x03 \x01(\x08\x12\x10\n\x08reserved\x18\x04 \x01(\x08\x12\x19\n\x11reserved_to_block\x18\x05 \x01(\r\"A\n\x0fSendpsbtRequest\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x14\n\x07reserve\x18\x02 \x01(\x08H\x00\x88\x01\x01\x42\n\n\x08_reserve\",\n\x10SendpsbtResponse\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\"1\n\x0fSignpsbtRequest\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x10\n\x08signonly\x18\x02 \x03(\r\"\'\n\x10SignpsbtResponse\x12\x13\n\x0bsigned_psbt\x18\x01 \x01(\t\"\xdb\x02\n\x0fUtxopsbtRequest\x12\x1c\n\x07satoshi\x18\x01 \x01(\x0b\x32\x0b.cln.Amount\x12\x1d\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.Feerate\x12\x13\n\x0bstartweight\x18\x03 \x01(\r\x12\x1c\n\x05utxos\x18\x04 \x03(\x0b\x32\r.cln.Outpoint\x12\x14\n\x07reserve\x18\x05 \x01(\rH\x00\x88\x01\x01\x12\x17\n\nreservedok\x18\x08 \x01(\x08H\x01\x88\x01\x01\x12\x15\n\x08locktime\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x1f\n\x12min_witness_weight\x18\x07 \x01(\rH\x03\x88\x01\x01\x12\x1d\n\x10\x65xcess_as_change\x18\t \x01(\x08H\x04\x88\x01\x01\x42\n\n\x08_reserveB\r\n\x0b_reservedokB\x0b\n\t_locktimeB\x15\n\x13_min_witness_weightB\x13\n\x11_excess_as_change\"\xd9\x01\n\x10UtxopsbtResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x16\n\x0e\x66\x65\x65rate_per_kw\x18\x02 \x01(\r\x12\x1e\n\x16\x65stimated_final_weight\x18\x03 \x01(\r\x12 \n\x0b\x65xcess_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12\x1a\n\rchange_outnum\x18\x05 \x01(\rH\x00\x88\x01\x01\x12/\n\x0creservations\x18\x06 \x03(\x0b\x32\x19.cln.UtxopsbtReservationsB\x10\n\x0e_change_outnum\"u\n\x14UtxopsbtReservations\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\x0c\n\x04vout\x18\x02 \x01(\r\x12\x14\n\x0cwas_reserved\x18\x03 \x01(\x08\x12\x10\n\x08reserved\x18\x04 \x01(\x08\x12\x19\n\x11reserved_to_block\x18\x05 \x01(\r\" \n\x10TxdiscardRequest\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\"6\n\x11TxdiscardResponse\x12\x13\n\x0bunsigned_tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\"\xa4\x01\n\x10TxprepareRequest\x12 \n\x07outputs\x18\x05 \x03(\x0b\x32\x0f.cln.OutputDesc\x12\"\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.FeerateH\x00\x88\x01\x01\x12\x14\n\x07minconf\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x1c\n\x05utxos\x18\x04 \x03(\x0b\x32\r.cln.OutpointB\n\n\x08_feerateB\n\n\x08_minconf\"D\n\x11TxprepareResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x13\n\x0bunsigned_tx\x18\x02 \x01(\x0c\x12\x0c\n\x04txid\x18\x03 \x01(\x0c\"\x1d\n\rTxsendRequest\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\"8\n\x0eTxsendResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\n\n\x02tx\x18\x02 \x01(\x0c\x12\x0c\n\x04txid\x18\x03 \x01(\x0c\"1\n\x17ListpeerchannelsRequest\x12\x0f\n\x02id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x05\n\x03_id\"K\n\x18ListpeerchannelsResponse\x12/\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x1d.cln.ListpeerchannelsChannels\"\xc7\x18\n\x18ListpeerchannelsChannels\x12\x14\n\x07peer_id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x1b\n\x0epeer_connected\x18\x02 \x01(\x08H\x01\x88\x01\x01\x12O\n\x05state\x18\x03 \x01(\x0e\x32;.cln.ListpeerchannelsChannels.ListpeerchannelsChannelsStateH\x02\x88\x01\x01\x12\x19\n\x0cscratch_txid\x18\x04 \x01(\x0cH\x03\x88\x01\x01\x12:\n\x07\x66\x65\x65rate\x18\x06 \x01(\x0b\x32$.cln.ListpeerchannelsChannelsFeerateH\x04\x88\x01\x01\x12\x12\n\x05owner\x18\x07 \x01(\tH\x05\x88\x01\x01\x12\x1d\n\x10short_channel_id\x18\x08 \x01(\tH\x06\x88\x01\x01\x12\x17\n\nchannel_id\x18\t \x01(\x0cH\x07\x88\x01\x01\x12\x19\n\x0c\x66unding_txid\x18\n \x01(\x0cH\x08\x88\x01\x01\x12\x1b\n\x0e\x66unding_outnum\x18\x0b \x01(\rH\t\x88\x01\x01\x12\x1c\n\x0finitial_feerate\x18\x0c \x01(\tH\n\x88\x01\x01\x12\x19\n\x0clast_feerate\x18\r \x01(\tH\x0b\x88\x01\x01\x12\x19\n\x0cnext_feerate\x18\x0e \x01(\tH\x0c\x88\x01\x01\x12\x1a\n\rnext_fee_step\x18\x0f \x01(\rH\r\x88\x01\x01\x12\x37\n\x08inflight\x18\x10 \x03(\x0b\x32%.cln.ListpeerchannelsChannelsInflight\x12\x15\n\x08\x63lose_to\x18\x11 \x01(\x0cH\x0e\x88\x01\x01\x12\x14\n\x07private\x18\x12 \x01(\x08H\x0f\x88\x01\x01\x12%\n\x06opener\x18\x13 \x01(\x0e\x32\x10.cln.ChannelSideH\x10\x88\x01\x01\x12%\n\x06\x63loser\x18\x14 \x01(\x0e\x32\x10.cln.ChannelSideH\x11\x88\x01\x01\x12:\n\x07\x66unding\x18\x16 \x01(\x0b\x32$.cln.ListpeerchannelsChannelsFundingH\x12\x88\x01\x01\x12$\n\nto_us_msat\x18\x17 \x01(\x0b\x32\x0b.cln.AmountH\x13\x88\x01\x01\x12(\n\x0emin_to_us_msat\x18\x18 \x01(\x0b\x32\x0b.cln.AmountH\x14\x88\x01\x01\x12(\n\x0emax_to_us_msat\x18\x19 \x01(\x0b\x32\x0b.cln.AmountH\x15\x88\x01\x01\x12$\n\ntotal_msat\x18\x1a \x01(\x0b\x32\x0b.cln.AmountH\x16\x88\x01\x01\x12\'\n\rfee_base_msat\x18\x1b \x01(\x0b\x32\x0b.cln.AmountH\x17\x88\x01\x01\x12(\n\x1b\x66\x65\x65_proportional_millionths\x18\x1c \x01(\rH\x18\x88\x01\x01\x12)\n\x0f\x64ust_limit_msat\x18\x1d \x01(\x0b\x32\x0b.cln.AmountH\x19\x88\x01\x01\x12\x30\n\x16max_total_htlc_in_msat\x18\x1e \x01(\x0b\x32\x0b.cln.AmountH\x1a\x88\x01\x01\x12,\n\x12their_reserve_msat\x18\x1f \x01(\x0b\x32\x0b.cln.AmountH\x1b\x88\x01\x01\x12*\n\x10our_reserve_msat\x18 \x01(\x0b\x32\x0b.cln.AmountH\x1c\x88\x01\x01\x12(\n\x0espendable_msat\x18! \x01(\x0b\x32\x0b.cln.AmountH\x1d\x88\x01\x01\x12)\n\x0freceivable_msat\x18\" \x01(\x0b\x32\x0b.cln.AmountH\x1e\x88\x01\x01\x12.\n\x14minimum_htlc_in_msat\x18# \x01(\x0b\x32\x0b.cln.AmountH\x1f\x88\x01\x01\x12/\n\x15minimum_htlc_out_msat\x18$ \x01(\x0b\x32\x0b.cln.AmountH \x88\x01\x01\x12/\n\x15maximum_htlc_out_msat\x18% \x01(\x0b\x32\x0b.cln.AmountH!\x88\x01\x01\x12 \n\x13their_to_self_delay\x18& \x01(\rH\"\x88\x01\x01\x12\x1e\n\x11our_to_self_delay\x18\' \x01(\rH#\x88\x01\x01\x12\x1f\n\x12max_accepted_htlcs\x18( \x01(\rH$\x88\x01\x01\x12\x36\n\x05\x61lias\x18) \x01(\x0b\x32\".cln.ListpeerchannelsChannelsAliasH%\x88\x01\x01\x12\x0e\n\x06status\x18+ \x03(\t\x12 \n\x13in_payments_offered\x18, \x01(\x04H&\x88\x01\x01\x12)\n\x0fin_offered_msat\x18- \x01(\x0b\x32\x0b.cln.AmountH\'\x88\x01\x01\x12\"\n\x15in_payments_fulfilled\x18. \x01(\x04H(\x88\x01\x01\x12+\n\x11in_fulfilled_msat\x18/ \x01(\x0b\x32\x0b.cln.AmountH)\x88\x01\x01\x12!\n\x14out_payments_offered\x18\x30 \x01(\x04H*\x88\x01\x01\x12*\n\x10out_offered_msat\x18\x31 \x01(\x0b\x32\x0b.cln.AmountH+\x88\x01\x01\x12#\n\x16out_payments_fulfilled\x18\x32 \x01(\x04H,\x88\x01\x01\x12,\n\x12out_fulfilled_msat\x18\x33 \x01(\x0b\x32\x0b.cln.AmountH-\x88\x01\x01\x12\x31\n\x05htlcs\x18\x34 \x03(\x0b\x32\".cln.ListpeerchannelsChannelsHtlcs\x12\x1a\n\rclose_to_addr\x18\x35 \x01(\tH.\x88\x01\x01\"\xa3\x02\n\x1dListpeerchannelsChannelsState\x12\x0c\n\x08OPENINGD\x10\x00\x12\x1c\n\x18\x43HANNELD_AWAITING_LOCKIN\x10\x01\x12\x13\n\x0f\x43HANNELD_NORMAL\x10\x02\x12\x1a\n\x16\x43HANNELD_SHUTTING_DOWN\x10\x03\x12\x18\n\x14\x43LOSINGD_SIGEXCHANGE\x10\x04\x12\x15\n\x11\x43LOSINGD_COMPLETE\x10\x05\x12\x17\n\x13\x41WAITING_UNILATERAL\x10\x06\x12\x16\n\x12\x46UNDING_SPEND_SEEN\x10\x07\x12\x0b\n\x07ONCHAIN\x10\x08\x12\x17\n\x13\x44UALOPEND_OPEN_INIT\x10\t\x12\x1d\n\x19\x44UALOPEND_AWAITING_LOCKIN\x10\nB\n\n\x08_peer_idB\x11\n\x0f_peer_connectedB\x08\n\x06_stateB\x0f\n\r_scratch_txidB\n\n\x08_feerateB\x08\n\x06_ownerB\x13\n\x11_short_channel_idB\r\n\x0b_channel_idB\x0f\n\r_funding_txidB\x11\n\x0f_funding_outnumB\x12\n\x10_initial_feerateB\x0f\n\r_last_feerateB\x0f\n\r_next_feerateB\x10\n\x0e_next_fee_stepB\x0b\n\t_close_toB\n\n\x08_privateB\t\n\x07_openerB\t\n\x07_closerB\n\n\x08_fundingB\r\n\x0b_to_us_msatB\x11\n\x0f_min_to_us_msatB\x11\n\x0f_max_to_us_msatB\r\n\x0b_total_msatB\x10\n\x0e_fee_base_msatB\x1e\n\x1c_fee_proportional_millionthsB\x12\n\x10_dust_limit_msatB\x19\n\x17_max_total_htlc_in_msatB\x15\n\x13_their_reserve_msatB\x13\n\x11_our_reserve_msatB\x11\n\x0f_spendable_msatB\x12\n\x10_receivable_msatB\x17\n\x15_minimum_htlc_in_msatB\x18\n\x16_minimum_htlc_out_msatB\x18\n\x16_maximum_htlc_out_msatB\x16\n\x14_their_to_self_delayB\x14\n\x12_our_to_self_delayB\x15\n\x13_max_accepted_htlcsB\x08\n\x06_aliasB\x16\n\x14_in_payments_offeredB\x12\n\x10_in_offered_msatB\x18\n\x16_in_payments_fulfilledB\x14\n\x12_in_fulfilled_msatB\x17\n\x15_out_payments_offeredB\x13\n\x11_out_offered_msatB\x19\n\x17_out_payments_fulfilledB\x15\n\x13_out_fulfilled_msatB\x10\n\x0e_close_to_addr\"]\n\x1fListpeerchannelsChannelsFeerate\x12\x12\n\x05perkw\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x12\n\x05perkb\x18\x02 \x01(\rH\x01\x88\x01\x01\x42\x08\n\x06_perkwB\x08\n\x06_perkb\"\xd2\x02\n ListpeerchannelsChannelsInflight\x12\x19\n\x0c\x66unding_txid\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x1b\n\x0e\x66unding_outnum\x18\x02 \x01(\rH\x01\x88\x01\x01\x12\x14\n\x07\x66\x65\x65rate\x18\x03 \x01(\tH\x02\x88\x01\x01\x12,\n\x12total_funding_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12*\n\x10our_funding_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12\x19\n\x0cscratch_txid\x18\x06 \x01(\x0cH\x05\x88\x01\x01\x42\x0f\n\r_funding_txidB\x11\n\x0f_funding_outnumB\n\n\x08_feerateB\x15\n\x13_total_funding_msatB\x13\n\x11_our_funding_msatB\x0f\n\r_scratch_txid\"\xd2\x02\n\x1fListpeerchannelsChannelsFunding\x12%\n\x0bpushed_msat\x18\x01 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12*\n\x10local_funds_msat\x18\x02 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12+\n\x11remote_funds_msat\x18\x03 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12\'\n\rfee_paid_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\'\n\rfee_rcvd_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x42\x0e\n\x0c_pushed_msatB\x13\n\x11_local_funds_msatB\x14\n\x12_remote_funds_msatB\x10\n\x0e_fee_paid_msatB\x10\n\x0e_fee_rcvd_msat\"]\n\x1dListpeerchannelsChannelsAlias\x12\x12\n\x05local\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06remote\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_localB\t\n\x07_remote\"\xe2\x03\n\x1dListpeerchannelsChannelsHtlcs\x12\x61\n\tdirection\x18\x01 \x01(\x0e\x32I.cln.ListpeerchannelsChannelsHtlcs.ListpeerchannelsChannelsHtlcsDirectionH\x00\x88\x01\x01\x12\x0f\n\x02id\x18\x02 \x01(\x04H\x01\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12\x13\n\x06\x65xpiry\x18\x04 \x01(\rH\x03\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x05 \x01(\x0cH\x04\x88\x01\x01\x12\x1a\n\rlocal_trimmed\x18\x06 \x01(\x08H\x05\x88\x01\x01\x12\x13\n\x06status\x18\x07 \x01(\tH\x06\x88\x01\x01\x12\"\n\x05state\x18\x08 \x01(\x0e\x32\x0e.cln.HtlcStateH\x07\x88\x01\x01\"9\n&ListpeerchannelsChannelsHtlcsDirection\x12\x06\n\x02IN\x10\x00\x12\x07\n\x03OUT\x10\x01\x42\x0c\n\n_directionB\x05\n\x03_idB\x0e\n\x0c_amount_msatB\t\n\x07_expiryB\x0f\n\r_payment_hashB\x10\n\x0e_local_trimmedB\t\n\x07_statusB\x08\n\x06_state\"3\n\x19ListclosedchannelsRequest\x12\x0f\n\x02id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x05\n\x03_id\"[\n\x1aListclosedchannelsResponse\x12=\n\x0e\x63losedchannels\x18\x01 \x03(\x0b\x32%.cln.ListclosedchannelsClosedchannels\"\xb2\t\n ListclosedchannelsClosedchannels\x12\x14\n\x07peer_id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x12\n\nchannel_id\x18\x02 \x01(\x0c\x12\x1d\n\x10short_channel_id\x18\x03 \x01(\tH\x01\x88\x01\x01\x12>\n\x05\x61lias\x18\x04 \x01(\x0b\x32*.cln.ListclosedchannelsClosedchannelsAliasH\x02\x88\x01\x01\x12 \n\x06opener\x18\x05 \x01(\x0e\x32\x10.cln.ChannelSide\x12%\n\x06\x63loser\x18\x06 \x01(\x0e\x32\x10.cln.ChannelSideH\x03\x88\x01\x01\x12\x0f\n\x07private\x18\x07 \x01(\x08\x12\x1f\n\x17total_local_commitments\x18\t \x01(\x04\x12 \n\x18total_remote_commitments\x18\n \x01(\x04\x12\x18\n\x10total_htlcs_sent\x18\x0b \x01(\x04\x12\x14\n\x0c\x66unding_txid\x18\x0c \x01(\x0c\x12\x16\n\x0e\x66unding_outnum\x18\r \x01(\r\x12\x0e\n\x06leased\x18\x0e \x01(\x08\x12/\n\x15\x66unding_fee_paid_msat\x18\x0f \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12/\n\x15\x66unding_fee_rcvd_msat\x18\x10 \x01(\x0b\x32\x0b.cln.AmountH\x05\x88\x01\x01\x12-\n\x13\x66unding_pushed_msat\x18\x11 \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\x1f\n\ntotal_msat\x18\x12 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10\x66inal_to_us_msat\x18\x13 \x01(\x0b\x32\x0b.cln.Amount\x12#\n\x0emin_to_us_msat\x18\x14 \x01(\x0b\x32\x0b.cln.Amount\x12#\n\x0emax_to_us_msat\x18\x15 \x01(\x0b\x32\x0b.cln.Amount\x12!\n\x14last_commitment_txid\x18\x16 \x01(\x0cH\x07\x88\x01\x01\x12\x32\n\x18last_commitment_fee_msat\x18\x17 \x01(\x0b\x32\x0b.cln.AmountH\x08\x88\x01\x01\x12\x66\n\x0b\x63lose_cause\x18\x18 \x01(\x0e\x32Q.cln.ListclosedchannelsClosedchannels.ListclosedchannelsClosedchannelsClose_cause\"v\n+ListclosedchannelsClosedchannelsClose_cause\x12\x0b\n\x07UNKNOWN\x10\x00\x12\t\n\x05LOCAL\x10\x01\x12\x08\n\x04USER\x10\x02\x12\n\n\x06REMOTE\x10\x03\x12\x0c\n\x08PROTOCOL\x10\x04\x12\x0b\n\x07ONCHAIN\x10\x05\x42\n\n\x08_peer_idB\x13\n\x11_short_channel_idB\x08\n\x06_aliasB\t\n\x07_closerB\x18\n\x16_funding_fee_paid_msatB\x18\n\x16_funding_fee_rcvd_msatB\x16\n\x14_funding_pushed_msatB\x17\n\x15_last_commitment_txidB\x1b\n\x19_last_commitment_fee_msat\"e\n%ListclosedchannelsClosedchannelsAlias\x12\x12\n\x05local\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06remote\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_localB\t\n\x07_remote\"L\n\x10\x44\x65\x63odepayRequest\x12\x0e\n\x06\x62olt11\x18\x01 \x01(\t\x12\x18\n\x0b\x64\x65scription\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_description\"\x8d\x04\n\x11\x44\x65\x63odepayResponse\x12\x10\n\x08\x63urrency\x18\x01 \x01(\t\x12\x12\n\ncreated_at\x18\x02 \x01(\x04\x12\x0e\n\x06\x65xpiry\x18\x03 \x01(\x04\x12\r\n\x05payee\x18\x04 \x01(\x0c\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x06 \x01(\x0c\x12\x11\n\tsignature\x18\x07 \x01(\t\x12\x18\n\x0b\x64\x65scription\x18\x08 \x01(\tH\x01\x88\x01\x01\x12\x1d\n\x10\x64\x65scription_hash\x18\t \x01(\x0cH\x02\x88\x01\x01\x12\x1d\n\x15min_final_cltv_expiry\x18\n \x01(\r\x12\x1b\n\x0epayment_secret\x18\x0b \x01(\x0cH\x03\x88\x01\x01\x12\x15\n\x08\x66\x65\x61tures\x18\x0c \x01(\x0cH\x04\x88\x01\x01\x12\x1d\n\x10payment_metadata\x18\r \x01(\x0cH\x05\x88\x01\x01\x12*\n\tfallbacks\x18\x0e \x03(\x0b\x32\x17.cln.DecodepayFallbacks\x12\"\n\x05\x65xtra\x18\x10 \x03(\x0b\x32\x13.cln.DecodepayExtraB\x0e\n\x0c_amount_msatB\x0e\n\x0c_descriptionB\x13\n\x11_description_hashB\x11\n\x0f_payment_secretB\x0b\n\t_featuresB\x13\n\x11_payment_metadata\"\xc6\x01\n\x12\x44\x65\x63odepayFallbacks\x12\x41\n\titem_type\x18\x01 \x01(\x0e\x32..cln.DecodepayFallbacks.DecodepayFallbacksType\x12\x11\n\x04\x61\x64\x64r\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x0b\n\x03hex\x18\x03 \x01(\x0c\"D\n\x16\x44\x65\x63odepayFallbacksType\x12\t\n\x05P2PKH\x10\x00\x12\x08\n\x04P2SH\x10\x01\x12\n\n\x06P2WPKH\x10\x02\x12\t\n\x05P2WSH\x10\x03\x42\x07\n\x05_addr\"+\n\x0e\x44\x65\x63odepayExtra\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\"\x1f\n\rDecodeRequest\x12\x0e\n\x06string\x18\x01 \x01(\t\"\xaa!\n\x0e\x44\x65\x63odeResponse\x12\x31\n\titem_type\x18\x01 \x01(\x0e\x32\x1e.cln.DecodeResponse.DecodeType\x12\r\n\x05valid\x18\x02 \x01(\x08\x12\x15\n\x08offer_id\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x12\x14\n\x0coffer_chains\x18\x04 \x03(\x0c\x12\x1b\n\x0eoffer_metadata\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\x1b\n\x0eoffer_currency\x18\x06 \x01(\tH\x02\x88\x01\x01\x12+\n\x1ewarning_unknown_offer_currency\x18\x07 \x01(\tH\x03\x88\x01\x01\x12 \n\x13\x63urrency_minor_unit\x18\x08 \x01(\rH\x04\x88\x01\x01\x12\x19\n\x0coffer_amount\x18\t \x01(\x04H\x05\x88\x01\x01\x12+\n\x11offer_amount_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\x1e\n\x11offer_description\x18\x0b \x01(\tH\x07\x88\x01\x01\x12\x19\n\x0coffer_issuer\x18\x0c \x01(\tH\x08\x88\x01\x01\x12\x1b\n\x0eoffer_features\x18\r \x01(\x0cH\t\x88\x01\x01\x12\"\n\x15offer_absolute_expiry\x18\x0e \x01(\x04H\n\x88\x01\x01\x12\x1f\n\x12offer_quantity_max\x18\x0f \x01(\x04H\x0b\x88\x01\x01\x12+\n\x0boffer_paths\x18\x10 \x03(\x0b\x32\x16.cln.DecodeOffer_paths\x12\x1a\n\roffer_node_id\x18\x11 \x01(\x0cH\x0c\x88\x01\x01\x12*\n\x1dwarning_missing_offer_node_id\x18\x14 \x01(\tH\r\x88\x01\x01\x12.\n!warning_invalid_offer_description\x18\x15 \x01(\tH\x0e\x88\x01\x01\x12.\n!warning_missing_offer_description\x18\x16 \x01(\tH\x0f\x88\x01\x01\x12+\n\x1ewarning_invalid_offer_currency\x18\x17 \x01(\tH\x10\x88\x01\x01\x12)\n\x1cwarning_invalid_offer_issuer\x18\x18 \x01(\tH\x11\x88\x01\x01\x12\x1c\n\x0finvreq_metadata\x18\x19 \x01(\x0cH\x12\x88\x01\x01\x12\x1c\n\x0finvreq_payer_id\x18\x1a \x01(\x0cH\x13\x88\x01\x01\x12\x19\n\x0cinvreq_chain\x18\x1b \x01(\x0cH\x14\x88\x01\x01\x12,\n\x12invreq_amount_msat\x18\x1c \x01(\x0b\x32\x0b.cln.AmountH\x15\x88\x01\x01\x12\x1c\n\x0finvreq_features\x18\x1d \x01(\x0cH\x16\x88\x01\x01\x12\x1c\n\x0finvreq_quantity\x18\x1e \x01(\x04H\x17\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x1f \x01(\tH\x18\x88\x01\x01\x12&\n\x19invreq_recurrence_counter\x18 \x01(\rH\x19\x88\x01\x01\x12$\n\x17invreq_recurrence_start\x18! \x01(\rH\x1a\x88\x01\x01\x12,\n\x1fwarning_missing_invreq_metadata\x18# \x01(\tH\x1b\x88\x01\x01\x12,\n\x1fwarning_missing_invreq_payer_id\x18$ \x01(\tH\x1c\x88\x01\x01\x12.\n!warning_invalid_invreq_payer_note\x18% \x01(\tH\x1d\x88\x01\x01\x12\x36\n)warning_missing_invoice_request_signature\x18& \x01(\tH\x1e\x88\x01\x01\x12\x36\n)warning_invalid_invoice_request_signature\x18\' \x01(\tH\x1f\x88\x01\x01\x12\x1f\n\x12invoice_created_at\x18) \x01(\x04H \x88\x01\x01\x12$\n\x17invoice_relative_expiry\x18* \x01(\rH!\x88\x01\x01\x12!\n\x14invoice_payment_hash\x18+ \x01(\x0cH\"\x88\x01\x01\x12-\n\x13invoice_amount_msat\x18, \x01(\x0b\x32\x0b.cln.AmountH#\x88\x01\x01\x12\x37\n\x11invoice_fallbacks\x18- \x03(\x0b\x32\x1c.cln.DecodeInvoice_fallbacks\x12\x1d\n\x10invoice_features\x18. \x01(\x0cH$\x88\x01\x01\x12\x1c\n\x0finvoice_node_id\x18/ \x01(\x0cH%\x88\x01\x01\x12(\n\x1binvoice_recurrence_basetime\x18\x30 \x01(\x04H&\x88\x01\x01\x12*\n\x1dwarning_missing_invoice_paths\x18\x32 \x01(\tH\'\x88\x01\x01\x12/\n\"warning_missing_invoice_blindedpay\x18\x33 \x01(\tH(\x88\x01\x01\x12/\n\"warning_missing_invoice_created_at\x18\x34 \x01(\tH)\x88\x01\x01\x12\x31\n$warning_missing_invoice_payment_hash\x18\x35 \x01(\tH*\x88\x01\x01\x12+\n\x1ewarning_missing_invoice_amount\x18\x36 \x01(\tH+\x88\x01\x01\x12\x38\n+warning_missing_invoice_recurrence_basetime\x18\x37 \x01(\tH,\x88\x01\x01\x12,\n\x1fwarning_missing_invoice_node_id\x18\x38 \x01(\tH-\x88\x01\x01\x12.\n!warning_missing_invoice_signature\x18\x39 \x01(\tH.\x88\x01\x01\x12.\n!warning_invalid_invoice_signature\x18: \x01(\tH/\x88\x01\x01\x12\'\n\tfallbacks\x18; \x03(\x0b\x32\x14.cln.DecodeFallbacks\x12\x17\n\ncreated_at\x18< \x01(\x04H0\x88\x01\x01\x12\x13\n\x06\x65xpiry\x18= \x01(\x04H1\x88\x01\x01\x12\x12\n\x05payee\x18> \x01(\x0cH2\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18? \x01(\x0cH3\x88\x01\x01\x12\x1d\n\x10\x64\x65scription_hash\x18@ \x01(\x0cH4\x88\x01\x01\x12\"\n\x15min_final_cltv_expiry\x18\x41 \x01(\rH5\x88\x01\x01\x12\x1b\n\x0epayment_secret\x18\x42 \x01(\x0cH6\x88\x01\x01\x12\x1d\n\x10payment_metadata\x18\x43 \x01(\x0cH7\x88\x01\x01\x12\x1f\n\x05\x65xtra\x18\x45 \x03(\x0b\x32\x10.cln.DecodeExtra\x12\x16\n\tunique_id\x18\x46 \x01(\tH8\x88\x01\x01\x12\x14\n\x07version\x18G \x01(\tH9\x88\x01\x01\x12\x13\n\x06string\x18H \x01(\tH:\x88\x01\x01\x12-\n\x0crestrictions\x18I \x03(\x0b\x32\x17.cln.DecodeRestrictions\x12&\n\x19warning_rune_invalid_utf8\x18J \x01(\tH;\x88\x01\x01\x12\x10\n\x03hex\x18K \x01(\x0cH<\x88\x01\x01\"l\n\nDecodeType\x12\x10\n\x0c\x42OLT12_OFFER\x10\x00\x12\x12\n\x0e\x42OLT12_INVOICE\x10\x01\x12\x1a\n\x16\x42OLT12_INVOICE_REQUEST\x10\x02\x12\x12\n\x0e\x42OLT11_INVOICE\x10\x03\x12\x08\n\x04RUNE\x10\x04\x42\x0b\n\t_offer_idB\x11\n\x0f_offer_metadataB\x11\n\x0f_offer_currencyB!\n\x1f_warning_unknown_offer_currencyB\x16\n\x14_currency_minor_unitB\x0f\n\r_offer_amountB\x14\n\x12_offer_amount_msatB\x14\n\x12_offer_descriptionB\x0f\n\r_offer_issuerB\x11\n\x0f_offer_featuresB\x18\n\x16_offer_absolute_expiryB\x15\n\x13_offer_quantity_maxB\x10\n\x0e_offer_node_idB \n\x1e_warning_missing_offer_node_idB$\n\"_warning_invalid_offer_descriptionB$\n\"_warning_missing_offer_descriptionB!\n\x1f_warning_invalid_offer_currencyB\x1f\n\x1d_warning_invalid_offer_issuerB\x12\n\x10_invreq_metadataB\x12\n\x10_invreq_payer_idB\x0f\n\r_invreq_chainB\x15\n\x13_invreq_amount_msatB\x12\n\x10_invreq_featuresB\x12\n\x10_invreq_quantityB\x14\n\x12_invreq_payer_noteB\x1c\n\x1a_invreq_recurrence_counterB\x1a\n\x18_invreq_recurrence_startB\"\n _warning_missing_invreq_metadataB\"\n _warning_missing_invreq_payer_idB$\n\"_warning_invalid_invreq_payer_noteB,\n*_warning_missing_invoice_request_signatureB,\n*_warning_invalid_invoice_request_signatureB\x15\n\x13_invoice_created_atB\x1a\n\x18_invoice_relative_expiryB\x17\n\x15_invoice_payment_hashB\x16\n\x14_invoice_amount_msatB\x13\n\x11_invoice_featuresB\x12\n\x10_invoice_node_idB\x1e\n\x1c_invoice_recurrence_basetimeB \n\x1e_warning_missing_invoice_pathsB%\n#_warning_missing_invoice_blindedpayB%\n#_warning_missing_invoice_created_atB\'\n%_warning_missing_invoice_payment_hashB!\n\x1f_warning_missing_invoice_amountB.\n,_warning_missing_invoice_recurrence_basetimeB\"\n _warning_missing_invoice_node_idB$\n\"_warning_missing_invoice_signatureB$\n\"_warning_invalid_invoice_signatureB\r\n\x0b_created_atB\t\n\x07_expiryB\x08\n\x06_payeeB\x0f\n\r_payment_hashB\x13\n\x11_description_hashB\x18\n\x16_min_final_cltv_expiryB\x11\n\x0f_payment_secretB\x13\n\x11_payment_metadataB\x0c\n\n_unique_idB\n\n\x08_versionB\t\n\x07_stringB\x1c\n\x1a_warning_rune_invalid_utf8B\x06\n\x04_hex\"<\n\x11\x44\x65\x63odeOffer_paths\x12\x15\n\rfirst_node_id\x18\x01 \x01(\x0c\x12\x10\n\x08\x62linding\x18\x02 \x01(\x0c\"\x8a\x01\n\x1f\x44\x65\x63odeOffer_recurrencePaywindow\x12\x16\n\x0eseconds_before\x18\x01 \x01(\r\x12\x15\n\rseconds_after\x18\x02 \x01(\r\x12 \n\x13proportional_amount\x18\x03 \x01(\x08H\x00\x88\x01\x01\x42\x16\n\x14_proportional_amount\"T\n\x17\x44\x65\x63odeInvoice_pathsPath\x12\x17\n\x0f\x62linded_node_id\x18\x01 \x01(\x0c\x12 \n\x18\x65ncrypted_recipient_data\x18\x02 \x01(\x0c\"Y\n\x17\x44\x65\x63odeInvoice_fallbacks\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x0b\n\x03hex\x18\x02 \x01(\x0c\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\n\n\x08_address\"w\n\x0f\x44\x65\x63odeFallbacks\x12\x36\n)warning_invoice_fallbacks_version_invalid\x18\x01 \x01(\tH\x00\x88\x01\x01\x42,\n*_warning_invoice_fallbacks_version_invalid\"(\n\x0b\x44\x65\x63odeExtra\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\";\n\x12\x44\x65\x63odeRestrictions\x12\x14\n\x0c\x61lternatives\x18\x01 \x03(\t\x12\x0f\n\x07summary\x18\x02 \x01(\t\"=\n\x11\x44isconnectRequest\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x12\n\x05\x66orce\x18\x02 \x01(\x08H\x00\x88\x01\x01\x42\x08\n\x06_force\"\x14\n\x12\x44isconnectResponse\"k\n\x0f\x46\x65\x65ratesRequest\x12\x31\n\x05style\x18\x01 \x01(\x0e\x32\".cln.FeeratesRequest.FeeratesStyle\"%\n\rFeeratesStyle\x12\t\n\x05PERKB\x10\x00\x12\t\n\x05PERKW\x10\x01\"\x9c\x02\n\x10\x46\x65\x65ratesResponse\x12%\n\x18warning_missing_feerates\x18\x01 \x01(\tH\x00\x88\x01\x01\x12&\n\x05perkb\x18\x02 \x01(\x0b\x32\x12.cln.FeeratesPerkbH\x01\x88\x01\x01\x12&\n\x05perkw\x18\x03 \x01(\x0b\x32\x12.cln.FeeratesPerkwH\x02\x88\x01\x01\x12\x46\n\x15onchain_fee_estimates\x18\x04 \x01(\x0b\x32\".cln.FeeratesOnchain_fee_estimatesH\x03\x88\x01\x01\x42\x1b\n\x19_warning_missing_feeratesB\x08\n\x06_perkbB\x08\n\x06_perkwB\x18\n\x16_onchain_fee_estimates\"\x91\x03\n\rFeeratesPerkb\x12\x16\n\x0emin_acceptable\x18\x01 \x01(\r\x12\x16\n\x0emax_acceptable\x18\x02 \x01(\r\x12\x12\n\x05\x66loor\x18\n \x01(\rH\x00\x88\x01\x01\x12.\n\testimates\x18\t \x03(\x0b\x32\x1b.cln.FeeratesPerkbEstimates\x12\x14\n\x07opening\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x19\n\x0cmutual_close\x18\x04 \x01(\rH\x02\x88\x01\x01\x12\x1d\n\x10unilateral_close\x18\x05 \x01(\rH\x03\x88\x01\x01\x12\x1a\n\rdelayed_to_us\x18\x06 \x01(\rH\x04\x88\x01\x01\x12\x1c\n\x0fhtlc_resolution\x18\x07 \x01(\rH\x05\x88\x01\x01\x12\x14\n\x07penalty\x18\x08 \x01(\rH\x06\x88\x01\x01\x42\x08\n\x06_floorB\n\n\x08_openingB\x0f\n\r_mutual_closeB\x13\n\x11_unilateral_closeB\x10\n\x0e_delayed_to_usB\x12\n\x10_htlc_resolutionB\n\n\x08_penalty\"\x96\x01\n\x16\x46\x65\x65ratesPerkbEstimates\x12\x17\n\nblockcount\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x14\n\x07\x66\x65\x65rate\x18\x02 \x01(\rH\x01\x88\x01\x01\x12\x1d\n\x10smoothed_feerate\x18\x03 \x01(\rH\x02\x88\x01\x01\x42\r\n\x0b_blockcountB\n\n\x08_feerateB\x13\n\x11_smoothed_feerate\"\x91\x03\n\rFeeratesPerkw\x12\x16\n\x0emin_acceptable\x18\x01 \x01(\r\x12\x16\n\x0emax_acceptable\x18\x02 \x01(\r\x12\x12\n\x05\x66loor\x18\n \x01(\rH\x00\x88\x01\x01\x12.\n\testimates\x18\t \x03(\x0b\x32\x1b.cln.FeeratesPerkwEstimates\x12\x14\n\x07opening\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x19\n\x0cmutual_close\x18\x04 \x01(\rH\x02\x88\x01\x01\x12\x1d\n\x10unilateral_close\x18\x05 \x01(\rH\x03\x88\x01\x01\x12\x1a\n\rdelayed_to_us\x18\x06 \x01(\rH\x04\x88\x01\x01\x12\x1c\n\x0fhtlc_resolution\x18\x07 \x01(\rH\x05\x88\x01\x01\x12\x14\n\x07penalty\x18\x08 \x01(\rH\x06\x88\x01\x01\x42\x08\n\x06_floorB\n\n\x08_openingB\x0f\n\r_mutual_closeB\x13\n\x11_unilateral_closeB\x10\n\x0e_delayed_to_usB\x12\n\x10_htlc_resolutionB\n\n\x08_penalty\"\x96\x01\n\x16\x46\x65\x65ratesPerkwEstimates\x12\x17\n\nblockcount\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x14\n\x07\x66\x65\x65rate\x18\x02 \x01(\rH\x01\x88\x01\x01\x12\x1d\n\x10smoothed_feerate\x18\x03 \x01(\rH\x02\x88\x01\x01\x42\r\n\x0b_blockcountB\n\n\x08_feerateB\x13\n\x11_smoothed_feerate\"\xc1\x01\n\x1d\x46\x65\x65ratesOnchain_fee_estimates\x12 \n\x18opening_channel_satoshis\x18\x01 \x01(\x04\x12\x1d\n\x15mutual_close_satoshis\x18\x02 \x01(\x04\x12!\n\x19unilateral_close_satoshis\x18\x03 \x01(\x04\x12\x1d\n\x15htlc_timeout_satoshis\x18\x04 \x01(\x04\x12\x1d\n\x15htlc_success_satoshis\x18\x05 \x01(\x04\"\xe5\x03\n\x12\x46undchannelRequest\x12\n\n\x02id\x18\t \x01(\x0c\x12 \n\x06\x61mount\x18\x01 \x01(\x0b\x32\x10.cln.AmountOrAll\x12\"\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.FeerateH\x00\x88\x01\x01\x12\x15\n\x08\x61nnounce\x18\x03 \x01(\x08H\x01\x88\x01\x01\x12\x14\n\x07minconf\x18\n \x01(\rH\x02\x88\x01\x01\x12#\n\tpush_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x15\n\x08\x63lose_to\x18\x06 \x01(\tH\x04\x88\x01\x01\x12%\n\x0brequest_amt\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x05\x88\x01\x01\x12\x1a\n\rcompact_lease\x18\x08 \x01(\tH\x06\x88\x01\x01\x12\x1c\n\x05utxos\x18\x0b \x03(\x0b\x32\r.cln.Outpoint\x12\x15\n\x08mindepth\x18\x0c \x01(\rH\x07\x88\x01\x01\x12!\n\x07reserve\x18\r \x01(\x0b\x32\x0b.cln.AmountH\x08\x88\x01\x01\x42\n\n\x08_feerateB\x0b\n\t_announceB\n\n\x08_minconfB\x0c\n\n_push_msatB\x0b\n\t_close_toB\x0e\n\x0c_request_amtB\x10\n\x0e_compact_leaseB\x0b\n\t_mindepthB\n\n\x08_reserve\"\x9b\x01\n\x13\x46undchannelResponse\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\x12\x0e\n\x06outnum\x18\x03 \x01(\r\x12\x12\n\nchannel_id\x18\x04 \x01(\x0c\x12\x15\n\x08\x63lose_to\x18\x05 \x01(\x0cH\x00\x88\x01\x01\x12\x15\n\x08mindepth\x18\x06 \x01(\rH\x01\x88\x01\x01\x42\x0b\n\t_close_toB\x0b\n\t_mindepth\"\xec\x01\n\x0fGetrouteRequest\x12\n\n\x02id\x18\x01 \x01(\x0c\x12 \n\x0b\x61mount_msat\x18\t \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\nriskfactor\x18\x03 \x01(\x04\x12\x11\n\x04\x63ltv\x18\x04 \x01(\x01H\x00\x88\x01\x01\x12\x13\n\x06\x66romid\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\x18\n\x0b\x66uzzpercent\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x0f\n\x07\x65xclude\x18\x07 \x03(\t\x12\x14\n\x07maxhops\x18\x08 \x01(\rH\x03\x88\x01\x01\x42\x07\n\x05_cltvB\t\n\x07_fromidB\x0e\n\x0c_fuzzpercentB\n\n\x08_maxhops\"5\n\x10GetrouteResponse\x12!\n\x05route\x18\x01 \x03(\x0b\x32\x12.cln.GetrouteRoute\"\xc5\x01\n\rGetrouteRoute\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x0f\n\x07\x63hannel\x18\x02 \x01(\t\x12\x11\n\tdirection\x18\x03 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12\r\n\x05\x64\x65lay\x18\x05 \x01(\r\x12\x34\n\x05style\x18\x06 \x01(\x0e\x32%.cln.GetrouteRoute.GetrouteRouteStyle\"\x1d\n\x12GetrouteRouteStyle\x12\x07\n\x03TLV\x10\x00\"\x82\x02\n\x13ListforwardsRequest\x12@\n\x06status\x18\x01 \x01(\x0e\x32+.cln.ListforwardsRequest.ListforwardsStatusH\x00\x88\x01\x01\x12\x17\n\nin_channel\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0bout_channel\x18\x03 \x01(\tH\x02\x88\x01\x01\"L\n\x12ListforwardsStatus\x12\x0b\n\x07OFFERED\x10\x00\x12\x0b\n\x07SETTLED\x10\x01\x12\x10\n\x0cLOCAL_FAILED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\x42\t\n\x07_statusB\r\n\x0b_in_channelB\x0e\n\x0c_out_channel\"C\n\x14ListforwardsResponse\x12+\n\x08\x66orwards\x18\x01 \x03(\x0b\x32\x19.cln.ListforwardsForwards\"\xde\x04\n\x14ListforwardsForwards\x12\x12\n\nin_channel\x18\x01 \x01(\t\x12\x17\n\nin_htlc_id\x18\n \x01(\x04H\x00\x88\x01\x01\x12\x1c\n\x07in_msat\x18\x02 \x01(\x0b\x32\x0b.cln.Amount\x12\x44\n\x06status\x18\x03 \x01(\x0e\x32\x34.cln.ListforwardsForwards.ListforwardsForwardsStatus\x12\x15\n\rreceived_time\x18\x04 \x01(\x01\x12\x18\n\x0bout_channel\x18\x05 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0bout_htlc_id\x18\x0b \x01(\x04H\x02\x88\x01\x01\x12G\n\x05style\x18\t \x01(\x0e\x32\x33.cln.ListforwardsForwards.ListforwardsForwardsStyleH\x03\x88\x01\x01\x12\"\n\x08\x66\x65\x65_msat\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12\"\n\x08out_msat\x18\x08 \x01(\x0b\x32\x0b.cln.AmountH\x05\x88\x01\x01\"T\n\x1aListforwardsForwardsStatus\x12\x0b\n\x07OFFERED\x10\x00\x12\x0b\n\x07SETTLED\x10\x01\x12\x10\n\x0cLOCAL_FAILED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\"0\n\x19ListforwardsForwardsStyle\x12\n\n\x06LEGACY\x10\x00\x12\x07\n\x03TLV\x10\x01\x42\r\n\x0b_in_htlc_idB\x0e\n\x0c_out_channelB\x0e\n\x0c_out_htlc_idB\x08\n\x06_styleB\x0b\n\t_fee_msatB\x0b\n\t_out_msat\"\xdb\x01\n\x0fListpaysRequest\x12\x13\n\x06\x62olt11\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12\x38\n\x06status\x18\x03 \x01(\x0e\x32#.cln.ListpaysRequest.ListpaysStatusH\x02\x88\x01\x01\"7\n\x0eListpaysStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x42\t\n\x07_bolt11B\x0f\n\r_payment_hashB\t\n\x07_status\"3\n\x10ListpaysResponse\x12\x1f\n\x04pays\x18\x01 \x03(\x0b\x32\x11.cln.ListpaysPays\"\x87\x04\n\x0cListpaysPays\x12\x14\n\x0cpayment_hash\x18\x01 \x01(\x0c\x12\x34\n\x06status\x18\x02 \x01(\x0e\x32$.cln.ListpaysPays.ListpaysPaysStatus\x12\x18\n\x0b\x64\x65stination\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x12\x12\n\ncreated_at\x18\x04 \x01(\x04\x12\x19\n\x0c\x63ompleted_at\x18\x0c \x01(\x04H\x01\x88\x01\x01\x12\x12\n\x05label\x18\x05 \x01(\tH\x02\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x06 \x01(\tH\x03\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x0b \x01(\tH\x04\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x07 \x01(\tH\x05\x88\x01\x01\x12\x15\n\x08preimage\x18\r \x01(\x0cH\x06\x88\x01\x01\x12\x1c\n\x0fnumber_of_parts\x18\x0e \x01(\x04H\x07\x88\x01\x01\x12\x17\n\nerroronion\x18\n \x01(\x0cH\x08\x88\x01\x01\";\n\x12ListpaysPaysStatus\x12\x0b\n\x07PENDING\x10\x00\x12\n\n\x06\x46\x41ILED\x10\x01\x12\x0c\n\x08\x43OMPLETE\x10\x02\x42\x0e\n\x0c_destinationB\x0f\n\r_completed_atB\x08\n\x06_labelB\t\n\x07_bolt11B\x0e\n\x0c_descriptionB\t\n\x07_bolt12B\x0b\n\t_preimageB\x12\n\x10_number_of_partsB\r\n\x0b_erroronion\"Y\n\x0bPingRequest\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x10\n\x03len\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x16\n\tpongbytes\x18\x03 \x01(\rH\x01\x88\x01\x01\x42\x06\n\x04_lenB\x0c\n\n_pongbytes\"\x1e\n\x0cPingResponse\x12\x0e\n\x06totlen\x18\x01 \x01(\r\"4\n\x14SendcustommsgRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x0b\n\x03msg\x18\x02 \x01(\x0c\"\'\n\x15SendcustommsgResponse\x12\x0e\n\x06status\x18\x01 \x01(\t\"\xf8\x01\n\x11SetchannelRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12!\n\x07\x66\x65\x65\x62\x61se\x18\x02 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x13\n\x06\x66\x65\x65ppm\x18\x03 \x01(\rH\x01\x88\x01\x01\x12!\n\x07htlcmin\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12!\n\x07htlcmax\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x19\n\x0c\x65nforcedelay\x18\x06 \x01(\rH\x04\x88\x01\x01\x42\n\n\x08_feebaseB\t\n\x07_feeppmB\n\n\x08_htlcminB\n\n\x08_htlcmaxB\x0f\n\r_enforcedelay\"?\n\x12SetchannelResponse\x12)\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x17.cln.SetchannelChannels\"\x94\x03\n\x12SetchannelChannels\x12\x0f\n\x07peer_id\x18\x01 \x01(\x0c\x12\x12\n\nchannel_id\x18\x02 \x01(\x0c\x12\x1d\n\x10short_channel_id\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\"\n\rfee_base_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12#\n\x1b\x66\x65\x65_proportional_millionths\x18\x05 \x01(\r\x12*\n\x15minimum_htlc_out_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12$\n\x17warning_htlcmin_too_low\x18\x07 \x01(\tH\x01\x88\x01\x01\x12*\n\x15maximum_htlc_out_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x18warning_htlcmax_too_high\x18\t \x01(\tH\x02\x88\x01\x01\x42\x13\n\x11_short_channel_idB\x1a\n\x18_warning_htlcmin_too_lowB\x1b\n\x19_warning_htlcmax_too_high\"\'\n\x12SigninvoiceRequest\x12\x11\n\tinvstring\x18\x01 \x01(\t\"%\n\x13SigninvoiceResponse\x12\x0e\n\x06\x62olt11\x18\x01 \x01(\t\"%\n\x12SignmessageRequest\x12\x0f\n\x07message\x18\x01 \x01(\t\"F\n\x13SignmessageResponse\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12\r\n\x05recid\x18\x02 \x01(\x0c\x12\r\n\x05zbase\x18\x03 \x01(\t\"\r\n\x0bStopRequest\"\x0e\n\x0cStopResponse\"\xa7\x01\n\x18PreapprovekeysendRequest\x12\x18\n\x0b\x64\x65stination\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x42\x0e\n\x0c_destinationB\x0f\n\r_payment_hashB\x0e\n\x0c_amount_msat\"\x1b\n\x19PreapprovekeysendResponse\":\n\x18PreapproveinvoiceRequest\x12\x13\n\x06\x62olt11\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\t\n\x07_bolt11\"\x1b\n\x19PreapproveinvoiceResponse2\x8a\x1c\n\x04Node\x12\x36\n\x07Getinfo\x12\x13.cln.GetinfoRequest\x1a\x14.cln.GetinfoResponse\"\x00\x12<\n\tListPeers\x12\x15.cln.ListpeersRequest\x1a\x16.cln.ListpeersResponse\"\x00\x12<\n\tListFunds\x12\x15.cln.ListfundsRequest\x1a\x16.cln.ListfundsResponse\"\x00\x12\x36\n\x07SendPay\x12\x13.cln.SendpayRequest\x1a\x14.cln.SendpayResponse\"\x00\x12\x45\n\x0cListChannels\x12\x18.cln.ListchannelsRequest\x1a\x19.cln.ListchannelsResponse\"\x00\x12<\n\tAddGossip\x12\x15.cln.AddgossipRequest\x1a\x16.cln.AddgossipResponse\"\x00\x12Q\n\x10\x41utoCleanInvoice\x12\x1c.cln.AutocleaninvoiceRequest\x1a\x1d.cln.AutocleaninvoiceResponse\"\x00\x12\x45\n\x0c\x43heckMessage\x12\x18.cln.CheckmessageRequest\x1a\x19.cln.CheckmessageResponse\"\x00\x12\x30\n\x05\x43lose\x12\x11.cln.CloseRequest\x1a\x12.cln.CloseResponse\"\x00\x12:\n\x0b\x43onnectPeer\x12\x13.cln.ConnectRequest\x1a\x14.cln.ConnectResponse\"\x00\x12H\n\rCreateInvoice\x12\x19.cln.CreateinvoiceRequest\x1a\x1a.cln.CreateinvoiceResponse\"\x00\x12<\n\tDatastore\x12\x15.cln.DatastoreRequest\x1a\x16.cln.DatastoreResponse\"\x00\x12\x42\n\x0b\x43reateOnion\x12\x17.cln.CreateonionRequest\x1a\x18.cln.CreateonionResponse\"\x00\x12\x45\n\x0c\x44\x65lDatastore\x12\x18.cln.DeldatastoreRequest\x1a\x19.cln.DeldatastoreResponse\"\x00\x12T\n\x11\x44\x65lExpiredInvoice\x12\x1d.cln.DelexpiredinvoiceRequest\x1a\x1e.cln.DelexpiredinvoiceResponse\"\x00\x12?\n\nDelInvoice\x12\x16.cln.DelinvoiceRequest\x1a\x17.cln.DelinvoiceResponse\"\x00\x12\x36\n\x07Invoice\x12\x13.cln.InvoiceRequest\x1a\x14.cln.InvoiceResponse\"\x00\x12H\n\rListDatastore\x12\x19.cln.ListdatastoreRequest\x1a\x1a.cln.ListdatastoreResponse\"\x00\x12\x45\n\x0cListInvoices\x12\x18.cln.ListinvoicesRequest\x1a\x19.cln.ListinvoicesResponse\"\x00\x12<\n\tSendOnion\x12\x15.cln.SendonionRequest\x1a\x16.cln.SendonionResponse\"\x00\x12\x45\n\x0cListSendPays\x12\x18.cln.ListsendpaysRequest\x1a\x19.cln.ListsendpaysResponse\"\x00\x12Q\n\x10ListTransactions\x12\x1c.cln.ListtransactionsRequest\x1a\x1d.cln.ListtransactionsResponse\"\x00\x12*\n\x03Pay\x12\x0f.cln.PayRequest\x1a\x10.cln.PayResponse\"\x00\x12<\n\tListNodes\x12\x15.cln.ListnodesRequest\x1a\x16.cln.ListnodesResponse\"\x00\x12K\n\x0eWaitAnyInvoice\x12\x1a.cln.WaitanyinvoiceRequest\x1a\x1b.cln.WaitanyinvoiceResponse\"\x00\x12\x42\n\x0bWaitInvoice\x12\x17.cln.WaitinvoiceRequest\x1a\x18.cln.WaitinvoiceResponse\"\x00\x12\x42\n\x0bWaitSendPay\x12\x17.cln.WaitsendpayRequest\x1a\x18.cln.WaitsendpayResponse\"\x00\x12\x36\n\x07NewAddr\x12\x13.cln.NewaddrRequest\x1a\x14.cln.NewaddrResponse\"\x00\x12\x39\n\x08Withdraw\x12\x14.cln.WithdrawRequest\x1a\x15.cln.WithdrawResponse\"\x00\x12\x36\n\x07KeySend\x12\x13.cln.KeysendRequest\x1a\x14.cln.KeysendResponse\"\x00\x12\x39\n\x08\x46undPsbt\x12\x14.cln.FundpsbtRequest\x1a\x15.cln.FundpsbtResponse\"\x00\x12\x39\n\x08SendPsbt\x12\x14.cln.SendpsbtRequest\x1a\x15.cln.SendpsbtResponse\"\x00\x12\x39\n\x08SignPsbt\x12\x14.cln.SignpsbtRequest\x1a\x15.cln.SignpsbtResponse\"\x00\x12\x39\n\x08UtxoPsbt\x12\x14.cln.UtxopsbtRequest\x1a\x15.cln.UtxopsbtResponse\"\x00\x12<\n\tTxDiscard\x12\x15.cln.TxdiscardRequest\x1a\x16.cln.TxdiscardResponse\"\x00\x12<\n\tTxPrepare\x12\x15.cln.TxprepareRequest\x1a\x16.cln.TxprepareResponse\"\x00\x12\x33\n\x06TxSend\x12\x12.cln.TxsendRequest\x1a\x13.cln.TxsendResponse\"\x00\x12Q\n\x10ListPeerChannels\x12\x1c.cln.ListpeerchannelsRequest\x1a\x1d.cln.ListpeerchannelsResponse\"\x00\x12W\n\x12ListClosedChannels\x12\x1e.cln.ListclosedchannelsRequest\x1a\x1f.cln.ListclosedchannelsResponse\"\x00\x12<\n\tDecodePay\x12\x15.cln.DecodepayRequest\x1a\x16.cln.DecodepayResponse\"\x00\x12\x33\n\x06\x44\x65\x63ode\x12\x12.cln.DecodeRequest\x1a\x13.cln.DecodeResponse\"\x00\x12?\n\nDisconnect\x12\x16.cln.DisconnectRequest\x1a\x17.cln.DisconnectResponse\"\x00\x12\x39\n\x08\x46\x65\x65rates\x12\x14.cln.FeeratesRequest\x1a\x15.cln.FeeratesResponse\"\x00\x12\x42\n\x0b\x46undChannel\x12\x17.cln.FundchannelRequest\x1a\x18.cln.FundchannelResponse\"\x00\x12\x39\n\x08GetRoute\x12\x14.cln.GetrouteRequest\x1a\x15.cln.GetrouteResponse\"\x00\x12\x45\n\x0cListForwards\x12\x18.cln.ListforwardsRequest\x1a\x19.cln.ListforwardsResponse\"\x00\x12\x39\n\x08ListPays\x12\x14.cln.ListpaysRequest\x1a\x15.cln.ListpaysResponse\"\x00\x12-\n\x04Ping\x12\x10.cln.PingRequest\x1a\x11.cln.PingResponse\"\x00\x12H\n\rSendCustomMsg\x12\x19.cln.SendcustommsgRequest\x1a\x1a.cln.SendcustommsgResponse\"\x00\x12?\n\nSetChannel\x12\x16.cln.SetchannelRequest\x1a\x17.cln.SetchannelResponse\"\x00\x12\x42\n\x0bSignInvoice\x12\x17.cln.SigninvoiceRequest\x1a\x18.cln.SigninvoiceResponse\"\x00\x12\x42\n\x0bSignMessage\x12\x17.cln.SignmessageRequest\x1a\x18.cln.SignmessageResponse\"\x00\x12-\n\x04Stop\x12\x10.cln.StopRequest\x1a\x11.cln.StopResponse\"\x00\x12T\n\x11PreApproveKeysend\x12\x1d.cln.PreapprovekeysendRequest\x1a\x1e.cln.PreapprovekeysendResponse\"\x00\x12T\n\x11PreApproveInvoice\x12\x1d.cln.PreapproveinvoiceRequest\x1a\x1e.cln.PreapproveinvoiceResponse\"\x00\x62\x06proto3') @@ -121,12 +121,39 @@ _TXPREPARERESPONSE = DESCRIPTOR.message_types_by_name['TxprepareResponse'] _TXSENDREQUEST = DESCRIPTOR.message_types_by_name['TxsendRequest'] _TXSENDRESPONSE = DESCRIPTOR.message_types_by_name['TxsendResponse'] +_LISTPEERCHANNELSREQUEST = DESCRIPTOR.message_types_by_name['ListpeerchannelsRequest'] +_LISTPEERCHANNELSRESPONSE = DESCRIPTOR.message_types_by_name['ListpeerchannelsResponse'] +_LISTPEERCHANNELSCHANNELS = DESCRIPTOR.message_types_by_name['ListpeerchannelsChannels'] +_LISTPEERCHANNELSCHANNELSFEERATE = DESCRIPTOR.message_types_by_name['ListpeerchannelsChannelsFeerate'] +_LISTPEERCHANNELSCHANNELSINFLIGHT = DESCRIPTOR.message_types_by_name['ListpeerchannelsChannelsInflight'] +_LISTPEERCHANNELSCHANNELSFUNDING = DESCRIPTOR.message_types_by_name['ListpeerchannelsChannelsFunding'] +_LISTPEERCHANNELSCHANNELSALIAS = DESCRIPTOR.message_types_by_name['ListpeerchannelsChannelsAlias'] +_LISTPEERCHANNELSCHANNELSHTLCS = DESCRIPTOR.message_types_by_name['ListpeerchannelsChannelsHtlcs'] +_LISTCLOSEDCHANNELSREQUEST = DESCRIPTOR.message_types_by_name['ListclosedchannelsRequest'] +_LISTCLOSEDCHANNELSRESPONSE = DESCRIPTOR.message_types_by_name['ListclosedchannelsResponse'] +_LISTCLOSEDCHANNELSCLOSEDCHANNELS = DESCRIPTOR.message_types_by_name['ListclosedchannelsClosedchannels'] +_LISTCLOSEDCHANNELSCLOSEDCHANNELSALIAS = DESCRIPTOR.message_types_by_name['ListclosedchannelsClosedchannelsAlias'] +_DECODEPAYREQUEST = DESCRIPTOR.message_types_by_name['DecodepayRequest'] +_DECODEPAYRESPONSE = DESCRIPTOR.message_types_by_name['DecodepayResponse'] +_DECODEPAYFALLBACKS = DESCRIPTOR.message_types_by_name['DecodepayFallbacks'] +_DECODEPAYEXTRA = DESCRIPTOR.message_types_by_name['DecodepayExtra'] +_DECODEREQUEST = DESCRIPTOR.message_types_by_name['DecodeRequest'] +_DECODERESPONSE = DESCRIPTOR.message_types_by_name['DecodeResponse'] +_DECODEOFFER_PATHS = DESCRIPTOR.message_types_by_name['DecodeOffer_paths'] +_DECODEOFFER_RECURRENCEPAYWINDOW = DESCRIPTOR.message_types_by_name['DecodeOffer_recurrencePaywindow'] +_DECODEINVOICE_PATHSPATH = DESCRIPTOR.message_types_by_name['DecodeInvoice_pathsPath'] +_DECODEINVOICE_FALLBACKS = DESCRIPTOR.message_types_by_name['DecodeInvoice_fallbacks'] +_DECODEFALLBACKS = DESCRIPTOR.message_types_by_name['DecodeFallbacks'] +_DECODEEXTRA = DESCRIPTOR.message_types_by_name['DecodeExtra'] +_DECODERESTRICTIONS = DESCRIPTOR.message_types_by_name['DecodeRestrictions'] _DISCONNECTREQUEST = DESCRIPTOR.message_types_by_name['DisconnectRequest'] _DISCONNECTRESPONSE = DESCRIPTOR.message_types_by_name['DisconnectResponse'] _FEERATESREQUEST = DESCRIPTOR.message_types_by_name['FeeratesRequest'] _FEERATESRESPONSE = DESCRIPTOR.message_types_by_name['FeeratesResponse'] _FEERATESPERKB = DESCRIPTOR.message_types_by_name['FeeratesPerkb'] +_FEERATESPERKBESTIMATES = DESCRIPTOR.message_types_by_name['FeeratesPerkbEstimates'] _FEERATESPERKW = DESCRIPTOR.message_types_by_name['FeeratesPerkw'] +_FEERATESPERKWESTIMATES = DESCRIPTOR.message_types_by_name['FeeratesPerkwEstimates'] _FEERATESONCHAIN_FEE_ESTIMATES = DESCRIPTOR.message_types_by_name['FeeratesOnchain_fee_estimates'] _FUNDCHANNELREQUEST = DESCRIPTOR.message_types_by_name['FundchannelRequest'] _FUNDCHANNELRESPONSE = DESCRIPTOR.message_types_by_name['FundchannelResponse'] @@ -141,13 +168,21 @@ _LISTPAYSPAYS = DESCRIPTOR.message_types_by_name['ListpaysPays'] _PINGREQUEST = DESCRIPTOR.message_types_by_name['PingRequest'] _PINGRESPONSE = DESCRIPTOR.message_types_by_name['PingResponse'] +_SENDCUSTOMMSGREQUEST = DESCRIPTOR.message_types_by_name['SendcustommsgRequest'] +_SENDCUSTOMMSGRESPONSE = DESCRIPTOR.message_types_by_name['SendcustommsgResponse'] _SETCHANNELREQUEST = DESCRIPTOR.message_types_by_name['SetchannelRequest'] _SETCHANNELRESPONSE = DESCRIPTOR.message_types_by_name['SetchannelResponse'] _SETCHANNELCHANNELS = DESCRIPTOR.message_types_by_name['SetchannelChannels'] +_SIGNINVOICEREQUEST = DESCRIPTOR.message_types_by_name['SigninvoiceRequest'] +_SIGNINVOICERESPONSE = DESCRIPTOR.message_types_by_name['SigninvoiceResponse'] _SIGNMESSAGEREQUEST = DESCRIPTOR.message_types_by_name['SignmessageRequest'] _SIGNMESSAGERESPONSE = DESCRIPTOR.message_types_by_name['SignmessageResponse'] _STOPREQUEST = DESCRIPTOR.message_types_by_name['StopRequest'] _STOPRESPONSE = DESCRIPTOR.message_types_by_name['StopResponse'] +_PREAPPROVEKEYSENDREQUEST = DESCRIPTOR.message_types_by_name['PreapprovekeysendRequest'] +_PREAPPROVEKEYSENDRESPONSE = DESCRIPTOR.message_types_by_name['PreapprovekeysendResponse'] +_PREAPPROVEINVOICEREQUEST = DESCRIPTOR.message_types_by_name['PreapproveinvoiceRequest'] +_PREAPPROVEINVOICERESPONSE = DESCRIPTOR.message_types_by_name['PreapproveinvoiceResponse'] _GETINFOADDRESS_GETINFOADDRESSTYPE = _GETINFOADDRESS.enum_types_by_name['GetinfoAddressType'] _GETINFOBINDING_GETINFOBINDINGTYPE = _GETINFOBINDING.enum_types_by_name['GetinfoBindingType'] _LISTPEERSPEERSLOG_LISTPEERSPEERSLOGTYPE = _LISTPEERSPEERSLOG.enum_types_by_name['ListpeersPeersLogType'] @@ -166,8 +201,6 @@ _SENDONIONRESPONSE_SENDONIONSTATUS = _SENDONIONRESPONSE.enum_types_by_name['SendonionStatus'] _LISTSENDPAYSREQUEST_LISTSENDPAYSSTATUS = _LISTSENDPAYSREQUEST.enum_types_by_name['ListsendpaysStatus'] _LISTSENDPAYSPAYMENTS_LISTSENDPAYSPAYMENTSSTATUS = _LISTSENDPAYSPAYMENTS.enum_types_by_name['ListsendpaysPaymentsStatus'] -_LISTTRANSACTIONSTRANSACTIONSINPUTS_LISTTRANSACTIONSTRANSACTIONSINPUTSTYPE = _LISTTRANSACTIONSTRANSACTIONSINPUTS.enum_types_by_name['ListtransactionsTransactionsInputsType'] -_LISTTRANSACTIONSTRANSACTIONSOUTPUTS_LISTTRANSACTIONSTRANSACTIONSOUTPUTSTYPE = _LISTTRANSACTIONSTRANSACTIONSOUTPUTS.enum_types_by_name['ListtransactionsTransactionsOutputsType'] _PAYRESPONSE_PAYSTATUS = _PAYRESPONSE.enum_types_by_name['PayStatus'] _LISTNODESNODESADDRESSES_LISTNODESNODESADDRESSESTYPE = _LISTNODESNODESADDRESSES.enum_types_by_name['ListnodesNodesAddressesType'] _WAITANYINVOICERESPONSE_WAITANYINVOICESTATUS = _WAITANYINVOICERESPONSE.enum_types_by_name['WaitanyinvoiceStatus'] @@ -175,6 +208,11 @@ _WAITSENDPAYRESPONSE_WAITSENDPAYSTATUS = _WAITSENDPAYRESPONSE.enum_types_by_name['WaitsendpayStatus'] _NEWADDRREQUEST_NEWADDRADDRESSTYPE = _NEWADDRREQUEST.enum_types_by_name['NewaddrAddresstype'] _KEYSENDRESPONSE_KEYSENDSTATUS = _KEYSENDRESPONSE.enum_types_by_name['KeysendStatus'] +_LISTPEERCHANNELSCHANNELS_LISTPEERCHANNELSCHANNELSSTATE = _LISTPEERCHANNELSCHANNELS.enum_types_by_name['ListpeerchannelsChannelsState'] +_LISTPEERCHANNELSCHANNELSHTLCS_LISTPEERCHANNELSCHANNELSHTLCSDIRECTION = _LISTPEERCHANNELSCHANNELSHTLCS.enum_types_by_name['ListpeerchannelsChannelsHtlcsDirection'] +_LISTCLOSEDCHANNELSCLOSEDCHANNELS_LISTCLOSEDCHANNELSCLOSEDCHANNELSCLOSE_CAUSE = _LISTCLOSEDCHANNELSCLOSEDCHANNELS.enum_types_by_name['ListclosedchannelsClosedchannelsClose_cause'] +_DECODEPAYFALLBACKS_DECODEPAYFALLBACKSTYPE = _DECODEPAYFALLBACKS.enum_types_by_name['DecodepayFallbacksType'] +_DECODERESPONSE_DECODETYPE = _DECODERESPONSE.enum_types_by_name['DecodeType'] _FEERATESREQUEST_FEERATESSTYLE = _FEERATESREQUEST.enum_types_by_name['FeeratesStyle'] _GETROUTEROUTE_GETROUTEROUTESTYLE = _GETROUTEROUTE.enum_types_by_name['GetrouteRouteStyle'] _LISTFORWARDSREQUEST_LISTFORWARDSSTATUS = _LISTFORWARDSREQUEST.enum_types_by_name['ListforwardsStatus'] @@ -896,6 +934,181 @@ }) _sym_db.RegisterMessage(TxsendResponse) +ListpeerchannelsRequest = _reflection.GeneratedProtocolMessageType('ListpeerchannelsRequest', (_message.Message,), { + 'DESCRIPTOR' : _LISTPEERCHANNELSREQUEST, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.ListpeerchannelsRequest) + }) +_sym_db.RegisterMessage(ListpeerchannelsRequest) + +ListpeerchannelsResponse = _reflection.GeneratedProtocolMessageType('ListpeerchannelsResponse', (_message.Message,), { + 'DESCRIPTOR' : _LISTPEERCHANNELSRESPONSE, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.ListpeerchannelsResponse) + }) +_sym_db.RegisterMessage(ListpeerchannelsResponse) + +ListpeerchannelsChannels = _reflection.GeneratedProtocolMessageType('ListpeerchannelsChannels', (_message.Message,), { + 'DESCRIPTOR' : _LISTPEERCHANNELSCHANNELS, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.ListpeerchannelsChannels) + }) +_sym_db.RegisterMessage(ListpeerchannelsChannels) + +ListpeerchannelsChannelsFeerate = _reflection.GeneratedProtocolMessageType('ListpeerchannelsChannelsFeerate', (_message.Message,), { + 'DESCRIPTOR' : _LISTPEERCHANNELSCHANNELSFEERATE, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.ListpeerchannelsChannelsFeerate) + }) +_sym_db.RegisterMessage(ListpeerchannelsChannelsFeerate) + +ListpeerchannelsChannelsInflight = _reflection.GeneratedProtocolMessageType('ListpeerchannelsChannelsInflight', (_message.Message,), { + 'DESCRIPTOR' : _LISTPEERCHANNELSCHANNELSINFLIGHT, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.ListpeerchannelsChannelsInflight) + }) +_sym_db.RegisterMessage(ListpeerchannelsChannelsInflight) + +ListpeerchannelsChannelsFunding = _reflection.GeneratedProtocolMessageType('ListpeerchannelsChannelsFunding', (_message.Message,), { + 'DESCRIPTOR' : _LISTPEERCHANNELSCHANNELSFUNDING, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.ListpeerchannelsChannelsFunding) + }) +_sym_db.RegisterMessage(ListpeerchannelsChannelsFunding) + +ListpeerchannelsChannelsAlias = _reflection.GeneratedProtocolMessageType('ListpeerchannelsChannelsAlias', (_message.Message,), { + 'DESCRIPTOR' : _LISTPEERCHANNELSCHANNELSALIAS, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.ListpeerchannelsChannelsAlias) + }) +_sym_db.RegisterMessage(ListpeerchannelsChannelsAlias) + +ListpeerchannelsChannelsHtlcs = _reflection.GeneratedProtocolMessageType('ListpeerchannelsChannelsHtlcs', (_message.Message,), { + 'DESCRIPTOR' : _LISTPEERCHANNELSCHANNELSHTLCS, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.ListpeerchannelsChannelsHtlcs) + }) +_sym_db.RegisterMessage(ListpeerchannelsChannelsHtlcs) + +ListclosedchannelsRequest = _reflection.GeneratedProtocolMessageType('ListclosedchannelsRequest', (_message.Message,), { + 'DESCRIPTOR' : _LISTCLOSEDCHANNELSREQUEST, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.ListclosedchannelsRequest) + }) +_sym_db.RegisterMessage(ListclosedchannelsRequest) + +ListclosedchannelsResponse = _reflection.GeneratedProtocolMessageType('ListclosedchannelsResponse', (_message.Message,), { + 'DESCRIPTOR' : _LISTCLOSEDCHANNELSRESPONSE, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.ListclosedchannelsResponse) + }) +_sym_db.RegisterMessage(ListclosedchannelsResponse) + +ListclosedchannelsClosedchannels = _reflection.GeneratedProtocolMessageType('ListclosedchannelsClosedchannels', (_message.Message,), { + 'DESCRIPTOR' : _LISTCLOSEDCHANNELSCLOSEDCHANNELS, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.ListclosedchannelsClosedchannels) + }) +_sym_db.RegisterMessage(ListclosedchannelsClosedchannels) + +ListclosedchannelsClosedchannelsAlias = _reflection.GeneratedProtocolMessageType('ListclosedchannelsClosedchannelsAlias', (_message.Message,), { + 'DESCRIPTOR' : _LISTCLOSEDCHANNELSCLOSEDCHANNELSALIAS, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.ListclosedchannelsClosedchannelsAlias) + }) +_sym_db.RegisterMessage(ListclosedchannelsClosedchannelsAlias) + +DecodepayRequest = _reflection.GeneratedProtocolMessageType('DecodepayRequest', (_message.Message,), { + 'DESCRIPTOR' : _DECODEPAYREQUEST, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.DecodepayRequest) + }) +_sym_db.RegisterMessage(DecodepayRequest) + +DecodepayResponse = _reflection.GeneratedProtocolMessageType('DecodepayResponse', (_message.Message,), { + 'DESCRIPTOR' : _DECODEPAYRESPONSE, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.DecodepayResponse) + }) +_sym_db.RegisterMessage(DecodepayResponse) + +DecodepayFallbacks = _reflection.GeneratedProtocolMessageType('DecodepayFallbacks', (_message.Message,), { + 'DESCRIPTOR' : _DECODEPAYFALLBACKS, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.DecodepayFallbacks) + }) +_sym_db.RegisterMessage(DecodepayFallbacks) + +DecodepayExtra = _reflection.GeneratedProtocolMessageType('DecodepayExtra', (_message.Message,), { + 'DESCRIPTOR' : _DECODEPAYEXTRA, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.DecodepayExtra) + }) +_sym_db.RegisterMessage(DecodepayExtra) + +DecodeRequest = _reflection.GeneratedProtocolMessageType('DecodeRequest', (_message.Message,), { + 'DESCRIPTOR' : _DECODEREQUEST, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.DecodeRequest) + }) +_sym_db.RegisterMessage(DecodeRequest) + +DecodeResponse = _reflection.GeneratedProtocolMessageType('DecodeResponse', (_message.Message,), { + 'DESCRIPTOR' : _DECODERESPONSE, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.DecodeResponse) + }) +_sym_db.RegisterMessage(DecodeResponse) + +DecodeOffer_paths = _reflection.GeneratedProtocolMessageType('DecodeOffer_paths', (_message.Message,), { + 'DESCRIPTOR' : _DECODEOFFER_PATHS, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.DecodeOffer_paths) + }) +_sym_db.RegisterMessage(DecodeOffer_paths) + +DecodeOffer_recurrencePaywindow = _reflection.GeneratedProtocolMessageType('DecodeOffer_recurrencePaywindow', (_message.Message,), { + 'DESCRIPTOR' : _DECODEOFFER_RECURRENCEPAYWINDOW, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.DecodeOffer_recurrencePaywindow) + }) +_sym_db.RegisterMessage(DecodeOffer_recurrencePaywindow) + +DecodeInvoice_pathsPath = _reflection.GeneratedProtocolMessageType('DecodeInvoice_pathsPath', (_message.Message,), { + 'DESCRIPTOR' : _DECODEINVOICE_PATHSPATH, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.DecodeInvoice_pathsPath) + }) +_sym_db.RegisterMessage(DecodeInvoice_pathsPath) + +DecodeInvoice_fallbacks = _reflection.GeneratedProtocolMessageType('DecodeInvoice_fallbacks', (_message.Message,), { + 'DESCRIPTOR' : _DECODEINVOICE_FALLBACKS, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.DecodeInvoice_fallbacks) + }) +_sym_db.RegisterMessage(DecodeInvoice_fallbacks) + +DecodeFallbacks = _reflection.GeneratedProtocolMessageType('DecodeFallbacks', (_message.Message,), { + 'DESCRIPTOR' : _DECODEFALLBACKS, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.DecodeFallbacks) + }) +_sym_db.RegisterMessage(DecodeFallbacks) + +DecodeExtra = _reflection.GeneratedProtocolMessageType('DecodeExtra', (_message.Message,), { + 'DESCRIPTOR' : _DECODEEXTRA, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.DecodeExtra) + }) +_sym_db.RegisterMessage(DecodeExtra) + +DecodeRestrictions = _reflection.GeneratedProtocolMessageType('DecodeRestrictions', (_message.Message,), { + 'DESCRIPTOR' : _DECODERESTRICTIONS, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.DecodeRestrictions) + }) +_sym_db.RegisterMessage(DecodeRestrictions) + DisconnectRequest = _reflection.GeneratedProtocolMessageType('DisconnectRequest', (_message.Message,), { 'DESCRIPTOR' : _DISCONNECTREQUEST, '__module__' : 'node_pb2' @@ -931,6 +1144,13 @@ }) _sym_db.RegisterMessage(FeeratesPerkb) +FeeratesPerkbEstimates = _reflection.GeneratedProtocolMessageType('FeeratesPerkbEstimates', (_message.Message,), { + 'DESCRIPTOR' : _FEERATESPERKBESTIMATES, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.FeeratesPerkbEstimates) + }) +_sym_db.RegisterMessage(FeeratesPerkbEstimates) + FeeratesPerkw = _reflection.GeneratedProtocolMessageType('FeeratesPerkw', (_message.Message,), { 'DESCRIPTOR' : _FEERATESPERKW, '__module__' : 'node_pb2' @@ -938,6 +1158,13 @@ }) _sym_db.RegisterMessage(FeeratesPerkw) +FeeratesPerkwEstimates = _reflection.GeneratedProtocolMessageType('FeeratesPerkwEstimates', (_message.Message,), { + 'DESCRIPTOR' : _FEERATESPERKWESTIMATES, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.FeeratesPerkwEstimates) + }) +_sym_db.RegisterMessage(FeeratesPerkwEstimates) + FeeratesOnchain_fee_estimates = _reflection.GeneratedProtocolMessageType('FeeratesOnchain_fee_estimates', (_message.Message,), { 'DESCRIPTOR' : _FEERATESONCHAIN_FEE_ESTIMATES, '__module__' : 'node_pb2' @@ -1036,6 +1263,20 @@ }) _sym_db.RegisterMessage(PingResponse) +SendcustommsgRequest = _reflection.GeneratedProtocolMessageType('SendcustommsgRequest', (_message.Message,), { + 'DESCRIPTOR' : _SENDCUSTOMMSGREQUEST, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.SendcustommsgRequest) + }) +_sym_db.RegisterMessage(SendcustommsgRequest) + +SendcustommsgResponse = _reflection.GeneratedProtocolMessageType('SendcustommsgResponse', (_message.Message,), { + 'DESCRIPTOR' : _SENDCUSTOMMSGRESPONSE, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.SendcustommsgResponse) + }) +_sym_db.RegisterMessage(SendcustommsgResponse) + SetchannelRequest = _reflection.GeneratedProtocolMessageType('SetchannelRequest', (_message.Message,), { 'DESCRIPTOR' : _SETCHANNELREQUEST, '__module__' : 'node_pb2' @@ -1057,6 +1298,20 @@ }) _sym_db.RegisterMessage(SetchannelChannels) +SigninvoiceRequest = _reflection.GeneratedProtocolMessageType('SigninvoiceRequest', (_message.Message,), { + 'DESCRIPTOR' : _SIGNINVOICEREQUEST, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.SigninvoiceRequest) + }) +_sym_db.RegisterMessage(SigninvoiceRequest) + +SigninvoiceResponse = _reflection.GeneratedProtocolMessageType('SigninvoiceResponse', (_message.Message,), { + 'DESCRIPTOR' : _SIGNINVOICERESPONSE, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.SigninvoiceResponse) + }) +_sym_db.RegisterMessage(SigninvoiceResponse) + SignmessageRequest = _reflection.GeneratedProtocolMessageType('SignmessageRequest', (_message.Message,), { 'DESCRIPTOR' : _SIGNMESSAGEREQUEST, '__module__' : 'node_pb2' @@ -1085,6 +1340,34 @@ }) _sym_db.RegisterMessage(StopResponse) +PreapprovekeysendRequest = _reflection.GeneratedProtocolMessageType('PreapprovekeysendRequest', (_message.Message,), { + 'DESCRIPTOR' : _PREAPPROVEKEYSENDREQUEST, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.PreapprovekeysendRequest) + }) +_sym_db.RegisterMessage(PreapprovekeysendRequest) + +PreapprovekeysendResponse = _reflection.GeneratedProtocolMessageType('PreapprovekeysendResponse', (_message.Message,), { + 'DESCRIPTOR' : _PREAPPROVEKEYSENDRESPONSE, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.PreapprovekeysendResponse) + }) +_sym_db.RegisterMessage(PreapprovekeysendResponse) + +PreapproveinvoiceRequest = _reflection.GeneratedProtocolMessageType('PreapproveinvoiceRequest', (_message.Message,), { + 'DESCRIPTOR' : _PREAPPROVEINVOICEREQUEST, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.PreapproveinvoiceRequest) + }) +_sym_db.RegisterMessage(PreapproveinvoiceRequest) + +PreapproveinvoiceResponse = _reflection.GeneratedProtocolMessageType('PreapproveinvoiceResponse', (_message.Message,), { + 'DESCRIPTOR' : _PREAPPROVEINVOICERESPONSE, + '__module__' : 'node_pb2' + # @@protoc_insertion_point(class_scope:cln.PreapproveinvoiceResponse) + }) +_sym_db.RegisterMessage(PreapproveinvoiceResponse) + _NODE = DESCRIPTOR.services_by_name['Node'] if _descriptor._USE_C_DESCRIPTORS == False: @@ -1092,329 +1375,405 @@ _GETINFOREQUEST._serialized_start=37 _GETINFOREQUEST._serialized_end=53 _GETINFORESPONSE._serialized_start=56 - _GETINFORESPONSE._serialized_end=684 - _GETINFOOUR_FEATURES._serialized_start=686 - _GETINFOOUR_FEATURES._serialized_end=769 - _GETINFOADDRESS._serialized_start=772 - _GETINFOADDRESS._serialized_end=983 - _GETINFOADDRESS_GETINFOADDRESSTYPE._serialized_start=885 - _GETINFOADDRESS_GETINFOADDRESSTYPE._serialized_end=971 - _GETINFOBINDING._serialized_start=986 - _GETINFOBINDING._serialized_end=1237 - _GETINFOBINDING_GETINFOBINDINGTYPE._serialized_start=1125 - _GETINFOBINDING_GETINFOBINDINGTYPE._serialized_end=1205 - _LISTPEERSREQUEST._serialized_start=1239 - _LISTPEERSREQUEST._serialized_end=1311 - _LISTPEERSRESPONSE._serialized_start=1313 - _LISTPEERSRESPONSE._serialized_end=1368 - _LISTPEERSPEERS._serialized_start=1371 - _LISTPEERSPEERS._serialized_end=1597 - _LISTPEERSPEERSLOG._serialized_start=1600 - _LISTPEERSPEERSLOG._serialized_end=1981 - _LISTPEERSPEERSLOG_LISTPEERSPEERSLOGTYPE._serialized_start=1811 - _LISTPEERSPEERSLOG_LISTPEERSPEERSLOGTYPE._serialized_end=1916 - _LISTPEERSPEERSCHANNELS._serialized_start=1984 - _LISTPEERSPEERSCHANNELS._serialized_end=5014 - _LISTPEERSPEERSCHANNELS_LISTPEERSPEERSCHANNELSSTATE._serialized_start=3884 - _LISTPEERSPEERSCHANNELS_LISTPEERSPEERSCHANNELSSTATE._serialized_end=4173 - _LISTPEERSPEERSCHANNELSFEERATE._serialized_start=5016 - _LISTPEERSPEERSCHANNELSFEERATE._serialized_end=5077 - _LISTPEERSPEERSCHANNELSINFLIGHT._serialized_start=5080 - _LISTPEERSPEERSCHANNELSINFLIGHT._serialized_end=5277 - _LISTPEERSPEERSCHANNELSFUNDING._serialized_start=5280 - _LISTPEERSPEERSCHANNELSFUNDING._serialized_end=5671 - _LISTPEERSPEERSCHANNELSALIAS._serialized_start=5673 - _LISTPEERSPEERSCHANNELSALIAS._serialized_end=5764 - _LISTPEERSPEERSCHANNELSHTLCS._serialized_start=5767 - _LISTPEERSPEERSCHANNELSHTLCS._serialized_end=6105 - _LISTPEERSPEERSCHANNELSHTLCS_LISTPEERSPEERSCHANNELSHTLCSDIRECTION._serialized_start=6021 - _LISTPEERSPEERSCHANNELSHTLCS_LISTPEERSPEERSCHANNELSHTLCSDIRECTION._serialized_end=6076 - _LISTFUNDSREQUEST._serialized_start=6107 - _LISTFUNDSREQUEST._serialized_end=6155 - _LISTFUNDSRESPONSE._serialized_start=6157 - _LISTFUNDSRESPONSE._serialized_end=6258 - _LISTFUNDSOUTPUTS._serialized_start=6261 - _LISTFUNDSOUTPUTS._serialized_end=6648 - _LISTFUNDSOUTPUTS_LISTFUNDSOUTPUTSSTATUS._serialized_start=6522 - _LISTFUNDSOUTPUTS_LISTFUNDSOUTPUTSSTATUS._serialized_end=6603 - _LISTFUNDSCHANNELS._serialized_start=6651 - _LISTFUNDSCHANNELS._serialized_end=6910 - _SENDPAYREQUEST._serialized_start=6913 - _SENDPAYREQUEST._serialized_end=7262 - _SENDPAYRESPONSE._serialized_start=7265 - _SENDPAYRESPONSE._serialized_end=7858 - _SENDPAYRESPONSE_SENDPAYSTATUS._serialized_start=7679 - _SENDPAYRESPONSE_SENDPAYSTATUS._serialized_end=7721 - _SENDPAYROUTE._serialized_start=7860 - _SENDPAYROUTE._serialized_end=7952 - _LISTCHANNELSREQUEST._serialized_start=7955 - _LISTCHANNELSREQUEST._serialized_end=8102 - _LISTCHANNELSRESPONSE._serialized_start=8104 - _LISTCHANNELSRESPONSE._serialized_end=8171 - _LISTCHANNELSCHANNELS._serialized_start=8174 - _LISTCHANNELSCHANNELS._serialized_end=8590 - _ADDGOSSIPREQUEST._serialized_start=8592 - _ADDGOSSIPREQUEST._serialized_end=8627 - _ADDGOSSIPRESPONSE._serialized_start=8629 - _ADDGOSSIPRESPONSE._serialized_end=8648 - _AUTOCLEANINVOICEREQUEST._serialized_start=8650 - _AUTOCLEANINVOICEREQUEST._serialized_end=8761 - _AUTOCLEANINVOICERESPONSE._serialized_start=8764 - _AUTOCLEANINVOICERESPONSE._serialized_end=8893 - _CHECKMESSAGEREQUEST._serialized_start=8895 - _CHECKMESSAGEREQUEST._serialized_end=8980 - _CHECKMESSAGERESPONSE._serialized_start=8982 - _CHECKMESSAGERESPONSE._serialized_end=9038 - _CLOSEREQUEST._serialized_start=9041 - _CLOSEREQUEST._serialized_end=9372 - _CLOSERESPONSE._serialized_start=9375 - _CLOSERESPONSE._serialized_end=9546 - _CLOSERESPONSE_CLOSETYPE._serialized_start=9477 - _CLOSERESPONSE_CLOSETYPE._serialized_end=9530 - _CONNECTREQUEST._serialized_start=9548 - _CONNECTREQUEST._serialized_end=9632 - _CONNECTRESPONSE._serialized_start=9635 - _CONNECTRESPONSE._serialized_end=9815 - _CONNECTRESPONSE_CONNECTDIRECTION._serialized_start=9780 - _CONNECTRESPONSE_CONNECTDIRECTION._serialized_end=9815 - _CONNECTADDRESS._serialized_start=9818 - _CONNECTADDRESS._serialized_end=10069 - _CONNECTADDRESS_CONNECTADDRESSTYPE._serialized_start=9957 - _CONNECTADDRESS_CONNECTADDRESSTYPE._serialized_end=10037 - _CREATEINVOICEREQUEST._serialized_start=10071 - _CREATEINVOICEREQUEST._serialized_end=10145 - _CREATEINVOICERESPONSE._serialized_start=10148 - _CREATEINVOICERESPONSE._serialized_end=10789 - _CREATEINVOICERESPONSE_CREATEINVOICESTATUS._serialized_start=10582 - _CREATEINVOICERESPONSE_CREATEINVOICESTATUS._serialized_end=10638 - _DATASTOREREQUEST._serialized_start=10792 - _DATASTOREREQUEST._serialized_end=11100 - _DATASTOREREQUEST_DATASTOREMODE._serialized_start=10945 - _DATASTOREREQUEST_DATASTOREMODE._serialized_end=11057 - _DATASTORERESPONSE._serialized_start=11103 - _DATASTORERESPONSE._serialized_end=11233 - _CREATEONIONREQUEST._serialized_start=11236 - _CREATEONIONREQUEST._serialized_end=11393 - _CREATEONIONRESPONSE._serialized_start=11395 - _CREATEONIONRESPONSE._serialized_end=11455 - _CREATEONIONHOPS._serialized_start=11457 - _CREATEONIONHOPS._serialized_end=11507 - _DELDATASTOREREQUEST._serialized_start=11509 - _DELDATASTOREREQUEST._serialized_end=11583 - _DELDATASTORERESPONSE._serialized_start=11586 - _DELDATASTORERESPONSE._serialized_end=11719 - _DELEXPIREDINVOICEREQUEST._serialized_start=11721 - _DELEXPIREDINVOICEREQUEST._serialized_end=11793 - _DELEXPIREDINVOICERESPONSE._serialized_start=11795 - _DELEXPIREDINVOICERESPONSE._serialized_end=11822 - _DELINVOICEREQUEST._serialized_start=11825 - _DELINVOICEREQUEST._serialized_end=12007 - _DELINVOICEREQUEST_DELINVOICESTATUS._serialized_start=11941 - _DELINVOICEREQUEST_DELINVOICESTATUS._serialized_end=11994 - _DELINVOICERESPONSE._serialized_start=12010 - _DELINVOICERESPONSE._serialized_end=12463 - _DELINVOICERESPONSE_DELINVOICESTATUS._serialized_start=11941 - _DELINVOICERESPONSE_DELINVOICESTATUS._serialized_end=11994 - _INVOICEREQUEST._serialized_start=12466 - _INVOICEREQUEST._serialized_end=12778 - _INVOICERESPONSE._serialized_start=12781 - _INVOICERESPONSE._serialized_end=13140 - _LISTDATASTOREREQUEST._serialized_start=13142 - _LISTDATASTOREREQUEST._serialized_end=13177 - _LISTDATASTORERESPONSE._serialized_start=13179 - _LISTDATASTORERESPONSE._serialized_end=13250 - _LISTDATASTOREDATASTORE._serialized_start=13253 - _LISTDATASTOREDATASTORE._serialized_end=13388 - _LISTINVOICESREQUEST._serialized_start=13391 - _LISTINVOICESREQUEST._serialized_end=13560 - _LISTINVOICESRESPONSE._serialized_start=13562 - _LISTINVOICESRESPONSE._serialized_end=13629 - _LISTINVOICESINVOICES._serialized_start=13632 - _LISTINVOICESINVOICES._serialized_end=14306 - _LISTINVOICESINVOICES_LISTINVOICESINVOICESSTATUS._serialized_start=14076 - _LISTINVOICESINVOICES_LISTINVOICESINVOICESSTATUS._serialized_end=14139 - _SENDONIONREQUEST._serialized_start=14309 - _SENDONIONREQUEST._serialized_end=14703 - _SENDONIONRESPONSE._serialized_start=14706 - _SENDONIONRESPONSE._serialized_end=15229 - _SENDONIONRESPONSE_SENDONIONSTATUS._serialized_start=15077 - _SENDONIONRESPONSE_SENDONIONSTATUS._serialized_end=15121 - _SENDONIONFIRST_HOP._serialized_start=15231 - _SENDONIONFIRST_HOP._serialized_end=15312 - _LISTSENDPAYSREQUEST._serialized_start=15315 - _LISTSENDPAYSREQUEST._serialized_end=15550 - _LISTSENDPAYSREQUEST_LISTSENDPAYSSTATUS._serialized_start=15452 - _LISTSENDPAYSREQUEST_LISTSENDPAYSSTATUS._serialized_end=15511 - _LISTSENDPAYSRESPONSE._serialized_start=15552 - _LISTSENDPAYSRESPONSE._serialized_end=15619 - _LISTSENDPAYSPAYMENTS._serialized_start=15622 - _LISTSENDPAYSPAYMENTS._serialized_end=16218 - _LISTSENDPAYSPAYMENTS_LISTSENDPAYSPAYMENTSSTATUS._serialized_start=16035 - _LISTSENDPAYSPAYMENTS_LISTSENDPAYSPAYMENTSSTATUS._serialized_end=16102 - _LISTTRANSACTIONSREQUEST._serialized_start=16220 - _LISTTRANSACTIONSREQUEST._serialized_end=16245 - _LISTTRANSACTIONSRESPONSE._serialized_start=16247 - _LISTTRANSACTIONSRESPONSE._serialized_end=16330 - _LISTTRANSACTIONSTRANSACTIONS._serialized_start=16333 - _LISTTRANSACTIONSTRANSACTIONS._serialized_end=16615 - _LISTTRANSACTIONSTRANSACTIONSINPUTS._serialized_start=16618 - _LISTTRANSACTIONSTRANSACTIONSINPUTS._serialized_end=17134 - _LISTTRANSACTIONSTRANSACTIONSINPUTS_LISTTRANSACTIONSTRANSACTIONSINPUTSTYPE._serialized_start=16830 - _LISTTRANSACTIONSTRANSACTIONSINPUTS_LISTTRANSACTIONSTRANSACTIONSINPUTSTYPE._serialized_end=17108 - _LISTTRANSACTIONSTRANSACTIONSOUTPUTS._serialized_start=17137 - _LISTTRANSACTIONSTRANSACTIONSOUTPUTS._serialized_end=17681 - _LISTTRANSACTIONSTRANSACTIONSOUTPUTS_LISTTRANSACTIONSTRANSACTIONSOUTPUTSTYPE._serialized_start=17376 - _LISTTRANSACTIONSTRANSACTIONSOUTPUTS_LISTTRANSACTIONSTRANSACTIONSOUTPUTSTYPE._serialized_end=17655 - _PAYREQUEST._serialized_start=17684 - _PAYREQUEST._serialized_end=18158 - _PAYRESPONSE._serialized_start=18161 - _PAYRESPONSE._serialized_end=18540 - _PAYRESPONSE_PAYSTATUS._serialized_start=18443 - _PAYRESPONSE_PAYSTATUS._serialized_end=18493 - _LISTNODESREQUEST._serialized_start=18542 - _LISTNODESREQUEST._serialized_end=18584 - _LISTNODESRESPONSE._serialized_start=18586 - _LISTNODESRESPONSE._serialized_end=18641 - _LISTNODESNODES._serialized_start=18644 - _LISTNODESNODES._serialized_end=18869 - _LISTNODESNODESADDRESSES._serialized_start=18872 - _LISTNODESNODESADDRESSES._serialized_end=19119 - _LISTNODESNODESADDRESSES_LISTNODESNODESADDRESSESTYPE._serialized_start=19012 - _LISTNODESNODESADDRESSES_LISTNODESNODESADDRESSESTYPE._serialized_end=19107 - _WAITANYINVOICEREQUEST._serialized_start=19121 - _WAITANYINVOICEREQUEST._serialized_end=19224 - _WAITANYINVOICERESPONSE._serialized_start=19227 - _WAITANYINVOICERESPONSE._serialized_end=19758 - _WAITANYINVOICERESPONSE_WAITANYINVOICESTATUS._serialized_start=19603 - _WAITANYINVOICERESPONSE_WAITANYINVOICESTATUS._serialized_end=19648 - _WAITINVOICEREQUEST._serialized_start=19760 - _WAITINVOICEREQUEST._serialized_end=19795 - _WAITINVOICERESPONSE._serialized_start=19798 - _WAITINVOICERESPONSE._serialized_end=20317 - _WAITINVOICERESPONSE_WAITINVOICESTATUS._serialized_start=20165 - _WAITINVOICERESPONSE_WAITINVOICESTATUS._serialized_end=20207 - _WAITSENDPAYREQUEST._serialized_start=20320 - _WAITSENDPAYREQUEST._serialized_end=20462 - _WAITSENDPAYRESPONSE._serialized_start=20465 - _WAITSENDPAYRESPONSE._serialized_end=21027 - _WAITSENDPAYRESPONSE_WAITSENDPAYSTATUS._serialized_start=20869 - _WAITSENDPAYRESPONSE_WAITSENDPAYSTATUS._serialized_end=20902 - _NEWADDRREQUEST._serialized_start=21030 - _NEWADDRREQUEST._serialized_end=21171 - _NEWADDRREQUEST_NEWADDRADDRESSTYPE._serialized_start=21114 - _NEWADDRREQUEST_NEWADDRADDRESSTYPE._serialized_end=21155 - _NEWADDRRESPONSE._serialized_start=21173 - _NEWADDRRESPONSE._serialized_end=21264 - _WITHDRAWREQUEST._serialized_start=21267 - _WITHDRAWREQUEST._serialized_end=21469 - _WITHDRAWRESPONSE._serialized_start=21471 - _WITHDRAWRESPONSE._serialized_end=21529 - _KEYSENDREQUEST._serialized_start=21532 - _KEYSENDREQUEST._serialized_end=21918 - _KEYSENDRESPONSE._serialized_start=21921 - _KEYSENDRESPONSE._serialized_end=22291 - _KEYSENDRESPONSE_KEYSENDSTATUS._serialized_start=22215 - _KEYSENDRESPONSE_KEYSENDSTATUS._serialized_end=22244 - _FUNDPSBTREQUEST._serialized_start=22294 - _FUNDPSBTREQUEST._serialized_end=22610 - _FUNDPSBTRESPONSE._serialized_start=22613 - _FUNDPSBTRESPONSE._serialized_end=22830 - _FUNDPSBTRESERVATIONS._serialized_start=22832 - _FUNDPSBTRESERVATIONS._serialized_end=22949 - _SENDPSBTREQUEST._serialized_start=22951 - _SENDPSBTREQUEST._serialized_end=23016 - _SENDPSBTRESPONSE._serialized_start=23018 - _SENDPSBTRESPONSE._serialized_end=23062 - _SIGNPSBTREQUEST._serialized_start=23064 - _SIGNPSBTREQUEST._serialized_end=23113 - _SIGNPSBTRESPONSE._serialized_start=23115 - _SIGNPSBTRESPONSE._serialized_end=23154 - _UTXOPSBTREQUEST._serialized_start=23157 - _UTXOPSBTREQUEST._serialized_end=23504 - _UTXOPSBTRESPONSE._serialized_start=23507 - _UTXOPSBTRESPONSE._serialized_end=23724 - _UTXOPSBTRESERVATIONS._serialized_start=23726 - _UTXOPSBTRESERVATIONS._serialized_end=23843 - _TXDISCARDREQUEST._serialized_start=23845 - _TXDISCARDREQUEST._serialized_end=23877 - _TXDISCARDRESPONSE._serialized_start=23879 - _TXDISCARDRESPONSE._serialized_end=23933 - _TXPREPAREREQUEST._serialized_start=23936 - _TXPREPAREREQUEST._serialized_end=24100 - _TXPREPARERESPONSE._serialized_start=24102 - _TXPREPARERESPONSE._serialized_end=24170 - _TXSENDREQUEST._serialized_start=24172 - _TXSENDREQUEST._serialized_end=24201 - _TXSENDRESPONSE._serialized_start=24203 - _TXSENDRESPONSE._serialized_end=24259 - _DISCONNECTREQUEST._serialized_start=24261 - _DISCONNECTREQUEST._serialized_end=24322 - _DISCONNECTRESPONSE._serialized_start=24324 - _DISCONNECTRESPONSE._serialized_end=24344 - _FEERATESREQUEST._serialized_start=24346 - _FEERATESREQUEST._serialized_end=24453 - _FEERATESREQUEST_FEERATESSTYLE._serialized_start=24416 - _FEERATESREQUEST_FEERATESSTYLE._serialized_end=24453 - _FEERATESRESPONSE._serialized_start=24456 - _FEERATESRESPONSE._serialized_end=24740 - _FEERATESPERKB._serialized_start=24743 - _FEERATESPERKB._serialized_end=25066 - _FEERATESPERKW._serialized_start=25069 - _FEERATESPERKW._serialized_end=25392 - _FEERATESONCHAIN_FEE_ESTIMATES._serialized_start=25395 - _FEERATESONCHAIN_FEE_ESTIMATES._serialized_end=25588 - _FUNDCHANNELREQUEST._serialized_start=25591 - _FUNDCHANNELREQUEST._serialized_end=26076 - _FUNDCHANNELRESPONSE._serialized_start=26079 - _FUNDCHANNELRESPONSE._serialized_end=26234 - _GETROUTEREQUEST._serialized_start=26237 - _GETROUTEREQUEST._serialized_end=26473 - _GETROUTERESPONSE._serialized_start=26475 - _GETROUTERESPONSE._serialized_end=26528 - _GETROUTEROUTE._serialized_start=26531 - _GETROUTEROUTE._serialized_end=26764 - _GETROUTEROUTE_GETROUTEROUTESTYLE._serialized_start=26722 - _GETROUTEROUTE_GETROUTEROUTESTYLE._serialized_end=26751 - _LISTFORWARDSREQUEST._serialized_start=26767 - _LISTFORWARDSREQUEST._serialized_end=27025 - _LISTFORWARDSREQUEST_LISTFORWARDSSTATUS._serialized_start=26907 - _LISTFORWARDSREQUEST_LISTFORWARDSSTATUS._serialized_end=26983 - _LISTFORWARDSRESPONSE._serialized_start=27027 - _LISTFORWARDSRESPONSE._serialized_end=27094 - _LISTFORWARDSFORWARDS._serialized_start=27097 - _LISTFORWARDSFORWARDS._serialized_end=27703 - _LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTATUS._serialized_start=27486 - _LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTATUS._serialized_end=27570 - _LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTYLE._serialized_start=27572 - _LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTYLE._serialized_end=27620 - _LISTPAYSREQUEST._serialized_start=27706 - _LISTPAYSREQUEST._serialized_end=27925 - _LISTPAYSREQUEST_LISTPAYSSTATUS._serialized_start=27831 - _LISTPAYSREQUEST_LISTPAYSSTATUS._serialized_end=27886 - _LISTPAYSRESPONSE._serialized_start=27927 - _LISTPAYSRESPONSE._serialized_end=27978 - _LISTPAYSPAYS._serialized_start=27981 - _LISTPAYSPAYS._serialized_end=28500 - _LISTPAYSPAYS_LISTPAYSPAYSSTATUS._serialized_start=28312 - _LISTPAYSPAYS_LISTPAYSPAYSSTATUS._serialized_end=28371 - _PINGREQUEST._serialized_start=28502 - _PINGREQUEST._serialized_end=28591 - _PINGRESPONSE._serialized_start=28593 - _PINGRESPONSE._serialized_end=28623 - _SETCHANNELREQUEST._serialized_start=28626 - _SETCHANNELREQUEST._serialized_end=28874 - _SETCHANNELRESPONSE._serialized_start=28876 - _SETCHANNELRESPONSE._serialized_end=28939 - _SETCHANNELCHANNELS._serialized_start=28942 - _SETCHANNELCHANNELS._serialized_end=29346 - _SIGNMESSAGEREQUEST._serialized_start=29348 - _SIGNMESSAGEREQUEST._serialized_end=29385 - _SIGNMESSAGERESPONSE._serialized_start=29387 - _SIGNMESSAGERESPONSE._serialized_end=29457 - _STOPREQUEST._serialized_start=29459 - _STOPREQUEST._serialized_end=29472 - _STOPRESPONSE._serialized_start=29474 - _STOPRESPONSE._serialized_end=29488 - _NODE._serialized_start=29491 - _NODE._serialized_end=32484 + _GETINFORESPONSE._serialized_end=633 + _GETINFOOUR_FEATURES._serialized_start=635 + _GETINFOOUR_FEATURES._serialized_end=718 + _GETINFOADDRESS._serialized_start=721 + _GETINFOADDRESS._serialized_end=917 + _GETINFOADDRESS_GETINFOADDRESSTYPE._serialized_start=834 + _GETINFOADDRESS_GETINFOADDRESSTYPE._serialized_end=905 + _GETINFOBINDING._serialized_start=920 + _GETINFOBINDING._serialized_end=1186 + _GETINFOBINDING_GETINFOBINDINGTYPE._serialized_start=1059 + _GETINFOBINDING_GETINFOBINDINGTYPE._serialized_end=1154 + _LISTPEERSREQUEST._serialized_start=1188 + _LISTPEERSREQUEST._serialized_end=1260 + _LISTPEERSRESPONSE._serialized_start=1262 + _LISTPEERSRESPONSE._serialized_end=1317 + _LISTPEERSPEERS._serialized_start=1320 + _LISTPEERSPEERS._serialized_end=1590 + _LISTPEERSPEERSLOG._serialized_start=1593 + _LISTPEERSPEERSLOG._serialized_end=1974 + _LISTPEERSPEERSLOG_LISTPEERSPEERSLOGTYPE._serialized_start=1804 + _LISTPEERSPEERSLOG_LISTPEERSPEERSLOGTYPE._serialized_end=1909 + _LISTPEERSPEERSCHANNELS._serialized_start=1977 + _LISTPEERSPEERSCHANNELS._serialized_end=5007 + _LISTPEERSPEERSCHANNELS_LISTPEERSPEERSCHANNELSSTATE._serialized_start=3877 + _LISTPEERSPEERSCHANNELS_LISTPEERSPEERSCHANNELSSTATE._serialized_end=4166 + _LISTPEERSPEERSCHANNELSFEERATE._serialized_start=5009 + _LISTPEERSPEERSCHANNELSFEERATE._serialized_end=5070 + _LISTPEERSPEERSCHANNELSINFLIGHT._serialized_start=5073 + _LISTPEERSPEERSCHANNELSINFLIGHT._serialized_end=5270 + _LISTPEERSPEERSCHANNELSFUNDING._serialized_start=5273 + _LISTPEERSPEERSCHANNELSFUNDING._serialized_end=5556 + _LISTPEERSPEERSCHANNELSALIAS._serialized_start=5558 + _LISTPEERSPEERSCHANNELSALIAS._serialized_end=5649 + _LISTPEERSPEERSCHANNELSHTLCS._serialized_start=5652 + _LISTPEERSPEERSCHANNELSHTLCS._serialized_end=6021 + _LISTPEERSPEERSCHANNELSHTLCS_LISTPEERSPEERSCHANNELSHTLCSDIRECTION._serialized_start=5937 + _LISTPEERSPEERSCHANNELSHTLCS_LISTPEERSPEERSCHANNELSHTLCSDIRECTION._serialized_end=5992 + _LISTFUNDSREQUEST._serialized_start=6023 + _LISTFUNDSREQUEST._serialized_end=6071 + _LISTFUNDSRESPONSE._serialized_start=6073 + _LISTFUNDSRESPONSE._serialized_end=6174 + _LISTFUNDSOUTPUTS._serialized_start=6177 + _LISTFUNDSOUTPUTS._serialized_end=6564 + _LISTFUNDSOUTPUTS_LISTFUNDSOUTPUTSSTATUS._serialized_start=6438 + _LISTFUNDSOUTPUTS_LISTFUNDSOUTPUTSSTATUS._serialized_end=6519 + _LISTFUNDSCHANNELS._serialized_start=6567 + _LISTFUNDSCHANNELS._serialized_end=6866 + _SENDPAYREQUEST._serialized_start=6869 + _SENDPAYREQUEST._serialized_end=7218 + _SENDPAYRESPONSE._serialized_start=7221 + _SENDPAYRESPONSE._serialized_end=7814 + _SENDPAYRESPONSE_SENDPAYSTATUS._serialized_start=7635 + _SENDPAYRESPONSE_SENDPAYSTATUS._serialized_end=7677 + _SENDPAYROUTE._serialized_start=7816 + _SENDPAYROUTE._serialized_end=7908 + _LISTCHANNELSREQUEST._serialized_start=7911 + _LISTCHANNELSREQUEST._serialized_end=8058 + _LISTCHANNELSRESPONSE._serialized_start=8060 + _LISTCHANNELSRESPONSE._serialized_end=8127 + _LISTCHANNELSCHANNELS._serialized_start=8130 + _LISTCHANNELSCHANNELS._serialized_end=8565 + _ADDGOSSIPREQUEST._serialized_start=8567 + _ADDGOSSIPREQUEST._serialized_end=8602 + _ADDGOSSIPRESPONSE._serialized_start=8604 + _ADDGOSSIPRESPONSE._serialized_end=8623 + _AUTOCLEANINVOICEREQUEST._serialized_start=8625 + _AUTOCLEANINVOICEREQUEST._serialized_end=8736 + _AUTOCLEANINVOICERESPONSE._serialized_start=8739 + _AUTOCLEANINVOICERESPONSE._serialized_end=8868 + _CHECKMESSAGEREQUEST._serialized_start=8870 + _CHECKMESSAGEREQUEST._serialized_end=8955 + _CHECKMESSAGERESPONSE._serialized_start=8957 + _CHECKMESSAGERESPONSE._serialized_end=9013 + _CLOSEREQUEST._serialized_start=9016 + _CLOSEREQUEST._serialized_end=9347 + _CLOSERESPONSE._serialized_start=9350 + _CLOSERESPONSE._serialized_end=9521 + _CLOSERESPONSE_CLOSETYPE._serialized_start=9452 + _CLOSERESPONSE_CLOSETYPE._serialized_end=9505 + _CONNECTREQUEST._serialized_start=9523 + _CONNECTREQUEST._serialized_end=9607 + _CONNECTRESPONSE._serialized_start=9610 + _CONNECTRESPONSE._serialized_end=9790 + _CONNECTRESPONSE_CONNECTDIRECTION._serialized_start=9755 + _CONNECTRESPONSE_CONNECTDIRECTION._serialized_end=9790 + _CONNECTADDRESS._serialized_start=9793 + _CONNECTADDRESS._serialized_end=10044 + _CONNECTADDRESS_CONNECTADDRESSTYPE._serialized_start=9932 + _CONNECTADDRESS_CONNECTADDRESSTYPE._serialized_end=10012 + _CREATEINVOICEREQUEST._serialized_start=10046 + _CREATEINVOICEREQUEST._serialized_end=10120 + _CREATEINVOICERESPONSE._serialized_start=10123 + _CREATEINVOICERESPONSE._serialized_end=10764 + _CREATEINVOICERESPONSE_CREATEINVOICESTATUS._serialized_start=10557 + _CREATEINVOICERESPONSE_CREATEINVOICESTATUS._serialized_end=10613 + _DATASTOREREQUEST._serialized_start=10767 + _DATASTOREREQUEST._serialized_end=11075 + _DATASTOREREQUEST_DATASTOREMODE._serialized_start=10920 + _DATASTOREREQUEST_DATASTOREMODE._serialized_end=11032 + _DATASTORERESPONSE._serialized_start=11078 + _DATASTORERESPONSE._serialized_end=11208 + _CREATEONIONREQUEST._serialized_start=11211 + _CREATEONIONREQUEST._serialized_end=11368 + _CREATEONIONRESPONSE._serialized_start=11370 + _CREATEONIONRESPONSE._serialized_end=11430 + _CREATEONIONHOPS._serialized_start=11432 + _CREATEONIONHOPS._serialized_end=11482 + _DELDATASTOREREQUEST._serialized_start=11484 + _DELDATASTOREREQUEST._serialized_end=11558 + _DELDATASTORERESPONSE._serialized_start=11561 + _DELDATASTORERESPONSE._serialized_end=11694 + _DELEXPIREDINVOICEREQUEST._serialized_start=11696 + _DELEXPIREDINVOICEREQUEST._serialized_end=11768 + _DELEXPIREDINVOICERESPONSE._serialized_start=11770 + _DELEXPIREDINVOICERESPONSE._serialized_end=11797 + _DELINVOICEREQUEST._serialized_start=11800 + _DELINVOICEREQUEST._serialized_end=11982 + _DELINVOICEREQUEST_DELINVOICESTATUS._serialized_start=11916 + _DELINVOICEREQUEST_DELINVOICESTATUS._serialized_end=11969 + _DELINVOICERESPONSE._serialized_start=11985 + _DELINVOICERESPONSE._serialized_end=12438 + _DELINVOICERESPONSE_DELINVOICESTATUS._serialized_start=11916 + _DELINVOICERESPONSE_DELINVOICESTATUS._serialized_end=11969 + _INVOICEREQUEST._serialized_start=12441 + _INVOICEREQUEST._serialized_end=12691 + _INVOICERESPONSE._serialized_start=12694 + _INVOICERESPONSE._serialized_end=13053 + _LISTDATASTOREREQUEST._serialized_start=13055 + _LISTDATASTOREREQUEST._serialized_end=13090 + _LISTDATASTORERESPONSE._serialized_start=13092 + _LISTDATASTORERESPONSE._serialized_end=13163 + _LISTDATASTOREDATASTORE._serialized_start=13166 + _LISTDATASTOREDATASTORE._serialized_end=13301 + _LISTINVOICESREQUEST._serialized_start=13304 + _LISTINVOICESREQUEST._serialized_end=13473 + _LISTINVOICESRESPONSE._serialized_start=13475 + _LISTINVOICESRESPONSE._serialized_end=13542 + _LISTINVOICESINVOICES._serialized_start=13545 + _LISTINVOICESINVOICES._serialized_end=14219 + _LISTINVOICESINVOICES_LISTINVOICESINVOICESSTATUS._serialized_start=13989 + _LISTINVOICESINVOICES_LISTINVOICESINVOICESSTATUS._serialized_end=14052 + _SENDONIONREQUEST._serialized_start=14222 + _SENDONIONREQUEST._serialized_end=14616 + _SENDONIONRESPONSE._serialized_start=14619 + _SENDONIONRESPONSE._serialized_end=15142 + _SENDONIONRESPONSE_SENDONIONSTATUS._serialized_start=14990 + _SENDONIONRESPONSE_SENDONIONSTATUS._serialized_end=15034 + _SENDONIONFIRST_HOP._serialized_start=15144 + _SENDONIONFIRST_HOP._serialized_end=15225 + _LISTSENDPAYSREQUEST._serialized_start=15228 + _LISTSENDPAYSREQUEST._serialized_end=15463 + _LISTSENDPAYSREQUEST_LISTSENDPAYSSTATUS._serialized_start=15365 + _LISTSENDPAYSREQUEST_LISTSENDPAYSSTATUS._serialized_end=15424 + _LISTSENDPAYSRESPONSE._serialized_start=15465 + _LISTSENDPAYSRESPONSE._serialized_end=15532 + _LISTSENDPAYSPAYMENTS._serialized_start=15535 + _LISTSENDPAYSPAYMENTS._serialized_end=16163 + _LISTSENDPAYSPAYMENTS_LISTSENDPAYSPAYMENTSSTATUS._serialized_start=15969 + _LISTSENDPAYSPAYMENTS_LISTSENDPAYSPAYMENTSSTATUS._serialized_end=16036 + _LISTTRANSACTIONSREQUEST._serialized_start=16165 + _LISTTRANSACTIONSREQUEST._serialized_end=16190 + _LISTTRANSACTIONSRESPONSE._serialized_start=16192 + _LISTTRANSACTIONSRESPONSE._serialized_end=16275 + _LISTTRANSACTIONSTRANSACTIONS._serialized_start=16278 + _LISTTRANSACTIONSTRANSACTIONS._serialized_end=16526 + _LISTTRANSACTIONSTRANSACTIONSINPUTS._serialized_start=16528 + _LISTTRANSACTIONSTRANSACTIONSINPUTS._serialized_end=16611 + _LISTTRANSACTIONSTRANSACTIONSOUTPUTS._serialized_start=16613 + _LISTTRANSACTIONSTRANSACTIONSOUTPUTS._serialized_end=16721 + _PAYREQUEST._serialized_start=16724 + _PAYREQUEST._serialized_end=17198 + _PAYRESPONSE._serialized_start=17201 + _PAYRESPONSE._serialized_end=17580 + _PAYRESPONSE_PAYSTATUS._serialized_start=17483 + _PAYRESPONSE_PAYSTATUS._serialized_end=17533 + _LISTNODESREQUEST._serialized_start=17582 + _LISTNODESREQUEST._serialized_end=17624 + _LISTNODESRESPONSE._serialized_start=17626 + _LISTNODESRESPONSE._serialized_end=17681 + _LISTNODESNODES._serialized_start=17684 + _LISTNODESNODES._serialized_end=17909 + _LISTNODESNODESADDRESSES._serialized_start=17912 + _LISTNODESNODESADDRESSES._serialized_end=18144 + _LISTNODESNODESADDRESSES_LISTNODESNODESADDRESSESTYPE._serialized_start=18052 + _LISTNODESNODESADDRESSES_LISTNODESNODESADDRESSESTYPE._serialized_end=18132 + _WAITANYINVOICEREQUEST._serialized_start=18146 + _WAITANYINVOICEREQUEST._serialized_end=18249 + _WAITANYINVOICERESPONSE._serialized_start=18252 + _WAITANYINVOICERESPONSE._serialized_end=18783 + _WAITANYINVOICERESPONSE_WAITANYINVOICESTATUS._serialized_start=18628 + _WAITANYINVOICERESPONSE_WAITANYINVOICESTATUS._serialized_end=18673 + _WAITINVOICEREQUEST._serialized_start=18785 + _WAITINVOICEREQUEST._serialized_end=18820 + _WAITINVOICERESPONSE._serialized_start=18823 + _WAITINVOICERESPONSE._serialized_end=19342 + _WAITINVOICERESPONSE_WAITINVOICESTATUS._serialized_start=19190 + _WAITINVOICERESPONSE_WAITINVOICESTATUS._serialized_end=19232 + _WAITSENDPAYREQUEST._serialized_start=19345 + _WAITSENDPAYREQUEST._serialized_end=19487 + _WAITSENDPAYRESPONSE._serialized_start=19490 + _WAITSENDPAYRESPONSE._serialized_end=20052 + _WAITSENDPAYRESPONSE_WAITSENDPAYSTATUS._serialized_start=19894 + _WAITSENDPAYRESPONSE_WAITSENDPAYSTATUS._serialized_end=19927 + _NEWADDRREQUEST._serialized_start=20055 + _NEWADDRREQUEST._serialized_end=20196 + _NEWADDRREQUEST_NEWADDRADDRESSTYPE._serialized_start=20139 + _NEWADDRREQUEST_NEWADDRADDRESSTYPE._serialized_end=20180 + _NEWADDRRESPONSE._serialized_start=20198 + _NEWADDRRESPONSE._serialized_end=20289 + _WITHDRAWREQUEST._serialized_start=20292 + _WITHDRAWREQUEST._serialized_end=20494 + _WITHDRAWRESPONSE._serialized_start=20496 + _WITHDRAWRESPONSE._serialized_end=20554 + _KEYSENDREQUEST._serialized_start=20557 + _KEYSENDREQUEST._serialized_end=20943 + _KEYSENDRESPONSE._serialized_start=20946 + _KEYSENDRESPONSE._serialized_end=21316 + _KEYSENDRESPONSE_KEYSENDSTATUS._serialized_start=21240 + _KEYSENDRESPONSE_KEYSENDSTATUS._serialized_end=21269 + _FUNDPSBTREQUEST._serialized_start=21319 + _FUNDPSBTREQUEST._serialized_end=21635 + _FUNDPSBTRESPONSE._serialized_start=21638 + _FUNDPSBTRESPONSE._serialized_end=21855 + _FUNDPSBTRESERVATIONS._serialized_start=21857 + _FUNDPSBTRESERVATIONS._serialized_end=21974 + _SENDPSBTREQUEST._serialized_start=21976 + _SENDPSBTREQUEST._serialized_end=22041 + _SENDPSBTRESPONSE._serialized_start=22043 + _SENDPSBTRESPONSE._serialized_end=22087 + _SIGNPSBTREQUEST._serialized_start=22089 + _SIGNPSBTREQUEST._serialized_end=22138 + _SIGNPSBTRESPONSE._serialized_start=22140 + _SIGNPSBTRESPONSE._serialized_end=22179 + _UTXOPSBTREQUEST._serialized_start=22182 + _UTXOPSBTREQUEST._serialized_end=22529 + _UTXOPSBTRESPONSE._serialized_start=22532 + _UTXOPSBTRESPONSE._serialized_end=22749 + _UTXOPSBTRESERVATIONS._serialized_start=22751 + _UTXOPSBTRESERVATIONS._serialized_end=22868 + _TXDISCARDREQUEST._serialized_start=22870 + _TXDISCARDREQUEST._serialized_end=22902 + _TXDISCARDRESPONSE._serialized_start=22904 + _TXDISCARDRESPONSE._serialized_end=22958 + _TXPREPAREREQUEST._serialized_start=22961 + _TXPREPAREREQUEST._serialized_end=23125 + _TXPREPARERESPONSE._serialized_start=23127 + _TXPREPARERESPONSE._serialized_end=23195 + _TXSENDREQUEST._serialized_start=23197 + _TXSENDREQUEST._serialized_end=23226 + _TXSENDRESPONSE._serialized_start=23228 + _TXSENDRESPONSE._serialized_end=23284 + _LISTPEERCHANNELSREQUEST._serialized_start=23286 + _LISTPEERCHANNELSREQUEST._serialized_end=23335 + _LISTPEERCHANNELSRESPONSE._serialized_start=23337 + _LISTPEERCHANNELSRESPONSE._serialized_end=23412 + _LISTPEERCHANNELSCHANNELS._serialized_start=23415 + _LISTPEERCHANNELSCHANNELS._serialized_end=26558 + _LISTPEERCHANNELSCHANNELS_LISTPEERCHANNELSCHANNELSSTATE._serialized_start=25374 + _LISTPEERCHANNELSCHANNELS_LISTPEERCHANNELSCHANNELSSTATE._serialized_end=25665 + _LISTPEERCHANNELSCHANNELSFEERATE._serialized_start=26560 + _LISTPEERCHANNELSCHANNELSFEERATE._serialized_end=26653 + _LISTPEERCHANNELSCHANNELSINFLIGHT._serialized_start=26656 + _LISTPEERCHANNELSCHANNELSINFLIGHT._serialized_end=26994 + _LISTPEERCHANNELSCHANNELSFUNDING._serialized_start=26997 + _LISTPEERCHANNELSCHANNELSFUNDING._serialized_end=27335 + _LISTPEERCHANNELSCHANNELSALIAS._serialized_start=27337 + _LISTPEERCHANNELSCHANNELSALIAS._serialized_end=27430 + _LISTPEERCHANNELSCHANNELSHTLCS._serialized_start=27433 + _LISTPEERCHANNELSCHANNELSHTLCS._serialized_end=27915 + _LISTPEERCHANNELSCHANNELSHTLCS_LISTPEERCHANNELSCHANNELSHTLCSDIRECTION._serialized_start=27754 + _LISTPEERCHANNELSCHANNELSHTLCS_LISTPEERCHANNELSCHANNELSHTLCSDIRECTION._serialized_end=27811 + _LISTCLOSEDCHANNELSREQUEST._serialized_start=27917 + _LISTCLOSEDCHANNELSREQUEST._serialized_end=27968 + _LISTCLOSEDCHANNELSRESPONSE._serialized_start=27970 + _LISTCLOSEDCHANNELSRESPONSE._serialized_end=28061 + _LISTCLOSEDCHANNELSCLOSEDCHANNELS._serialized_start=28064 + _LISTCLOSEDCHANNELSCLOSEDCHANNELS._serialized_end=29266 + _LISTCLOSEDCHANNELSCLOSEDCHANNELS_LISTCLOSEDCHANNELSCLOSEDCHANNELSCLOSE_CAUSE._serialized_start=28964 + _LISTCLOSEDCHANNELSCLOSEDCHANNELS_LISTCLOSEDCHANNELSCLOSEDCHANNELSCLOSE_CAUSE._serialized_end=29082 + _LISTCLOSEDCHANNELSCLOSEDCHANNELSALIAS._serialized_start=29268 + _LISTCLOSEDCHANNELSCLOSEDCHANNELSALIAS._serialized_end=29369 + _DECODEPAYREQUEST._serialized_start=29371 + _DECODEPAYREQUEST._serialized_end=29447 + _DECODEPAYRESPONSE._serialized_start=29450 + _DECODEPAYRESPONSE._serialized_end=29975 + _DECODEPAYFALLBACKS._serialized_start=29978 + _DECODEPAYFALLBACKS._serialized_end=30176 + _DECODEPAYFALLBACKS_DECODEPAYFALLBACKSTYPE._serialized_start=30099 + _DECODEPAYFALLBACKS_DECODEPAYFALLBACKSTYPE._serialized_end=30167 + _DECODEPAYEXTRA._serialized_start=30178 + _DECODEPAYEXTRA._serialized_end=30221 + _DECODEREQUEST._serialized_start=30223 + _DECODEREQUEST._serialized_end=30254 + _DECODERESPONSE._serialized_start=30257 + _DECODERESPONSE._serialized_end=34523 + _DECODERESPONSE_DECODETYPE._serialized_start=32825 + _DECODERESPONSE_DECODETYPE._serialized_end=32933 + _DECODEOFFER_PATHS._serialized_start=34525 + _DECODEOFFER_PATHS._serialized_end=34585 + _DECODEOFFER_RECURRENCEPAYWINDOW._serialized_start=34588 + _DECODEOFFER_RECURRENCEPAYWINDOW._serialized_end=34726 + _DECODEINVOICE_PATHSPATH._serialized_start=34728 + _DECODEINVOICE_PATHSPATH._serialized_end=34812 + _DECODEINVOICE_FALLBACKS._serialized_start=34814 + _DECODEINVOICE_FALLBACKS._serialized_end=34903 + _DECODEFALLBACKS._serialized_start=34905 + _DECODEFALLBACKS._serialized_end=35024 + _DECODEEXTRA._serialized_start=35026 + _DECODEEXTRA._serialized_end=35066 + _DECODERESTRICTIONS._serialized_start=35068 + _DECODERESTRICTIONS._serialized_end=35127 + _DISCONNECTREQUEST._serialized_start=35129 + _DISCONNECTREQUEST._serialized_end=35190 + _DISCONNECTRESPONSE._serialized_start=35192 + _DISCONNECTRESPONSE._serialized_end=35212 + _FEERATESREQUEST._serialized_start=35214 + _FEERATESREQUEST._serialized_end=35321 + _FEERATESREQUEST_FEERATESSTYLE._serialized_start=35284 + _FEERATESREQUEST_FEERATESSTYLE._serialized_end=35321 + _FEERATESRESPONSE._serialized_start=35324 + _FEERATESRESPONSE._serialized_end=35608 + _FEERATESPERKB._serialized_start=35611 + _FEERATESPERKB._serialized_end=36012 + _FEERATESPERKBESTIMATES._serialized_start=36015 + _FEERATESPERKBESTIMATES._serialized_end=36165 + _FEERATESPERKW._serialized_start=36168 + _FEERATESPERKW._serialized_end=36569 + _FEERATESPERKWESTIMATES._serialized_start=36572 + _FEERATESPERKWESTIMATES._serialized_end=36722 + _FEERATESONCHAIN_FEE_ESTIMATES._serialized_start=36725 + _FEERATESONCHAIN_FEE_ESTIMATES._serialized_end=36918 + _FUNDCHANNELREQUEST._serialized_start=36921 + _FUNDCHANNELREQUEST._serialized_end=37406 + _FUNDCHANNELRESPONSE._serialized_start=37409 + _FUNDCHANNELRESPONSE._serialized_end=37564 + _GETROUTEREQUEST._serialized_start=37567 + _GETROUTEREQUEST._serialized_end=37803 + _GETROUTERESPONSE._serialized_start=37805 + _GETROUTERESPONSE._serialized_end=37858 + _GETROUTEROUTE._serialized_start=37861 + _GETROUTEROUTE._serialized_end=38058 + _GETROUTEROUTE_GETROUTEROUTESTYLE._serialized_start=38029 + _GETROUTEROUTE_GETROUTEROUTESTYLE._serialized_end=38058 + _LISTFORWARDSREQUEST._serialized_start=38061 + _LISTFORWARDSREQUEST._serialized_end=38319 + _LISTFORWARDSREQUEST_LISTFORWARDSSTATUS._serialized_start=38201 + _LISTFORWARDSREQUEST_LISTFORWARDSSTATUS._serialized_end=38277 + _LISTFORWARDSRESPONSE._serialized_start=38321 + _LISTFORWARDSRESPONSE._serialized_end=38388 + _LISTFORWARDSFORWARDS._serialized_start=38391 + _LISTFORWARDSFORWARDS._serialized_end=38997 + _LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTATUS._serialized_start=38780 + _LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTATUS._serialized_end=38864 + _LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTYLE._serialized_start=38866 + _LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTYLE._serialized_end=38914 + _LISTPAYSREQUEST._serialized_start=39000 + _LISTPAYSREQUEST._serialized_end=39219 + _LISTPAYSREQUEST_LISTPAYSSTATUS._serialized_start=39125 + _LISTPAYSREQUEST_LISTPAYSSTATUS._serialized_end=39180 + _LISTPAYSRESPONSE._serialized_start=39221 + _LISTPAYSRESPONSE._serialized_end=39272 + _LISTPAYSPAYS._serialized_start=39275 + _LISTPAYSPAYS._serialized_end=39794 + _LISTPAYSPAYS_LISTPAYSPAYSSTATUS._serialized_start=39606 + _LISTPAYSPAYS_LISTPAYSPAYSSTATUS._serialized_end=39665 + _PINGREQUEST._serialized_start=39796 + _PINGREQUEST._serialized_end=39885 + _PINGRESPONSE._serialized_start=39887 + _PINGRESPONSE._serialized_end=39917 + _SENDCUSTOMMSGREQUEST._serialized_start=39919 + _SENDCUSTOMMSGREQUEST._serialized_end=39971 + _SENDCUSTOMMSGRESPONSE._serialized_start=39973 + _SENDCUSTOMMSGRESPONSE._serialized_end=40012 + _SETCHANNELREQUEST._serialized_start=40015 + _SETCHANNELREQUEST._serialized_end=40263 + _SETCHANNELRESPONSE._serialized_start=40265 + _SETCHANNELRESPONSE._serialized_end=40328 + _SETCHANNELCHANNELS._serialized_start=40331 + _SETCHANNELCHANNELS._serialized_end=40735 + _SIGNINVOICEREQUEST._serialized_start=40737 + _SIGNINVOICEREQUEST._serialized_end=40776 + _SIGNINVOICERESPONSE._serialized_start=40778 + _SIGNINVOICERESPONSE._serialized_end=40815 + _SIGNMESSAGEREQUEST._serialized_start=40817 + _SIGNMESSAGEREQUEST._serialized_end=40854 + _SIGNMESSAGERESPONSE._serialized_start=40856 + _SIGNMESSAGERESPONSE._serialized_end=40926 + _STOPREQUEST._serialized_start=40928 + _STOPREQUEST._serialized_end=40941 + _STOPRESPONSE._serialized_start=40943 + _STOPRESPONSE._serialized_end=40957 + _PREAPPROVEKEYSENDREQUEST._serialized_start=40960 + _PREAPPROVEKEYSENDREQUEST._serialized_end=41127 + _PREAPPROVEKEYSENDRESPONSE._serialized_start=41129 + _PREAPPROVEKEYSENDRESPONSE._serialized_end=41156 + _PREAPPROVEINVOICEREQUEST._serialized_start=41158 + _PREAPPROVEINVOICEREQUEST._serialized_end=41216 + _PREAPPROVEINVOICERESPONSE._serialized_start=41218 + _PREAPPROVEINVOICERESPONSE._serialized_end=41245 + _NODE._serialized_start=41248 + _NODE._serialized_end=44842 # @@protoc_insertion_point(module_scope) diff --git a/contrib/pyln-testing/pyln/testing/node_pb2_grpc.py b/contrib/pyln-testing/pyln/testing/node_pb2_grpc.py index c682d92b6bb9..439f6197cead 100644 --- a/contrib/pyln-testing/pyln/testing/node_pb2_grpc.py +++ b/contrib/pyln-testing/pyln/testing/node_pb2_grpc.py @@ -199,6 +199,26 @@ def __init__(self, channel): request_serializer=node__pb2.TxsendRequest.SerializeToString, response_deserializer=node__pb2.TxsendResponse.FromString, ) + self.ListPeerChannels = channel.unary_unary( + '/cln.Node/ListPeerChannels', + request_serializer=node__pb2.ListpeerchannelsRequest.SerializeToString, + response_deserializer=node__pb2.ListpeerchannelsResponse.FromString, + ) + self.ListClosedChannels = channel.unary_unary( + '/cln.Node/ListClosedChannels', + request_serializer=node__pb2.ListclosedchannelsRequest.SerializeToString, + response_deserializer=node__pb2.ListclosedchannelsResponse.FromString, + ) + self.DecodePay = channel.unary_unary( + '/cln.Node/DecodePay', + request_serializer=node__pb2.DecodepayRequest.SerializeToString, + response_deserializer=node__pb2.DecodepayResponse.FromString, + ) + self.Decode = channel.unary_unary( + '/cln.Node/Decode', + request_serializer=node__pb2.DecodeRequest.SerializeToString, + response_deserializer=node__pb2.DecodeResponse.FromString, + ) self.Disconnect = channel.unary_unary( '/cln.Node/Disconnect', request_serializer=node__pb2.DisconnectRequest.SerializeToString, @@ -234,11 +254,21 @@ def __init__(self, channel): request_serializer=node__pb2.PingRequest.SerializeToString, response_deserializer=node__pb2.PingResponse.FromString, ) + self.SendCustomMsg = channel.unary_unary( + '/cln.Node/SendCustomMsg', + request_serializer=node__pb2.SendcustommsgRequest.SerializeToString, + response_deserializer=node__pb2.SendcustommsgResponse.FromString, + ) self.SetChannel = channel.unary_unary( '/cln.Node/SetChannel', request_serializer=node__pb2.SetchannelRequest.SerializeToString, response_deserializer=node__pb2.SetchannelResponse.FromString, ) + self.SignInvoice = channel.unary_unary( + '/cln.Node/SignInvoice', + request_serializer=node__pb2.SigninvoiceRequest.SerializeToString, + response_deserializer=node__pb2.SigninvoiceResponse.FromString, + ) self.SignMessage = channel.unary_unary( '/cln.Node/SignMessage', request_serializer=node__pb2.SignmessageRequest.SerializeToString, @@ -249,6 +279,16 @@ def __init__(self, channel): request_serializer=node__pb2.StopRequest.SerializeToString, response_deserializer=node__pb2.StopResponse.FromString, ) + self.PreApproveKeysend = channel.unary_unary( + '/cln.Node/PreApproveKeysend', + request_serializer=node__pb2.PreapprovekeysendRequest.SerializeToString, + response_deserializer=node__pb2.PreapprovekeysendResponse.FromString, + ) + self.PreApproveInvoice = channel.unary_unary( + '/cln.Node/PreApproveInvoice', + request_serializer=node__pb2.PreapproveinvoiceRequest.SerializeToString, + response_deserializer=node__pb2.PreapproveinvoiceResponse.FromString, + ) class NodeServicer(object): @@ -476,6 +516,30 @@ def TxSend(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def ListPeerChannels(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ListClosedChannels(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def DecodePay(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Decode(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def Disconnect(self, request, context): """Missing associated documentation comment in .proto file.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) @@ -518,12 +582,24 @@ def Ping(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def SendCustomMsg(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def SetChannel(self, request, context): """Missing associated documentation comment in .proto file.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def SignInvoice(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def SignMessage(self, request, context): """Missing associated documentation comment in .proto file.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) @@ -536,6 +612,18 @@ def Stop(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def PreApproveKeysend(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def PreApproveInvoice(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def add_NodeServicer_to_server(servicer, server): rpc_method_handlers = { @@ -724,6 +812,26 @@ def add_NodeServicer_to_server(servicer, server): request_deserializer=node__pb2.TxsendRequest.FromString, response_serializer=node__pb2.TxsendResponse.SerializeToString, ), + 'ListPeerChannels': grpc.unary_unary_rpc_method_handler( + servicer.ListPeerChannels, + request_deserializer=node__pb2.ListpeerchannelsRequest.FromString, + response_serializer=node__pb2.ListpeerchannelsResponse.SerializeToString, + ), + 'ListClosedChannels': grpc.unary_unary_rpc_method_handler( + servicer.ListClosedChannels, + request_deserializer=node__pb2.ListclosedchannelsRequest.FromString, + response_serializer=node__pb2.ListclosedchannelsResponse.SerializeToString, + ), + 'DecodePay': grpc.unary_unary_rpc_method_handler( + servicer.DecodePay, + request_deserializer=node__pb2.DecodepayRequest.FromString, + response_serializer=node__pb2.DecodepayResponse.SerializeToString, + ), + 'Decode': grpc.unary_unary_rpc_method_handler( + servicer.Decode, + request_deserializer=node__pb2.DecodeRequest.FromString, + response_serializer=node__pb2.DecodeResponse.SerializeToString, + ), 'Disconnect': grpc.unary_unary_rpc_method_handler( servicer.Disconnect, request_deserializer=node__pb2.DisconnectRequest.FromString, @@ -759,11 +867,21 @@ def add_NodeServicer_to_server(servicer, server): request_deserializer=node__pb2.PingRequest.FromString, response_serializer=node__pb2.PingResponse.SerializeToString, ), + 'SendCustomMsg': grpc.unary_unary_rpc_method_handler( + servicer.SendCustomMsg, + request_deserializer=node__pb2.SendcustommsgRequest.FromString, + response_serializer=node__pb2.SendcustommsgResponse.SerializeToString, + ), 'SetChannel': grpc.unary_unary_rpc_method_handler( servicer.SetChannel, request_deserializer=node__pb2.SetchannelRequest.FromString, response_serializer=node__pb2.SetchannelResponse.SerializeToString, ), + 'SignInvoice': grpc.unary_unary_rpc_method_handler( + servicer.SignInvoice, + request_deserializer=node__pb2.SigninvoiceRequest.FromString, + response_serializer=node__pb2.SigninvoiceResponse.SerializeToString, + ), 'SignMessage': grpc.unary_unary_rpc_method_handler( servicer.SignMessage, request_deserializer=node__pb2.SignmessageRequest.FromString, @@ -774,6 +892,16 @@ def add_NodeServicer_to_server(servicer, server): request_deserializer=node__pb2.StopRequest.FromString, response_serializer=node__pb2.StopResponse.SerializeToString, ), + 'PreApproveKeysend': grpc.unary_unary_rpc_method_handler( + servicer.PreApproveKeysend, + request_deserializer=node__pb2.PreapprovekeysendRequest.FromString, + response_serializer=node__pb2.PreapprovekeysendResponse.SerializeToString, + ), + 'PreApproveInvoice': grpc.unary_unary_rpc_method_handler( + servicer.PreApproveInvoice, + request_deserializer=node__pb2.PreapproveinvoiceRequest.FromString, + response_serializer=node__pb2.PreapproveinvoiceResponse.SerializeToString, + ), } generic_handler = grpc.method_handlers_generic_handler( 'cln.Node', rpc_method_handlers) @@ -1413,6 +1541,74 @@ def TxSend(request, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + @staticmethod + def ListPeerChannels(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/cln.Node/ListPeerChannels', + node__pb2.ListpeerchannelsRequest.SerializeToString, + node__pb2.ListpeerchannelsResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def ListClosedChannels(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/cln.Node/ListClosedChannels', + node__pb2.ListclosedchannelsRequest.SerializeToString, + node__pb2.ListclosedchannelsResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def DecodePay(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/cln.Node/DecodePay', + node__pb2.DecodepayRequest.SerializeToString, + node__pb2.DecodepayResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def Decode(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/cln.Node/Decode', + node__pb2.DecodeRequest.SerializeToString, + node__pb2.DecodeResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + @staticmethod def Disconnect(request, target, @@ -1532,6 +1728,23 @@ def Ping(request, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + @staticmethod + def SendCustomMsg(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/cln.Node/SendCustomMsg', + node__pb2.SendcustommsgRequest.SerializeToString, + node__pb2.SendcustommsgResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + @staticmethod def SetChannel(request, target, @@ -1549,6 +1762,23 @@ def SetChannel(request, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + @staticmethod + def SignInvoice(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/cln.Node/SignInvoice', + node__pb2.SigninvoiceRequest.SerializeToString, + node__pb2.SigninvoiceResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + @staticmethod def SignMessage(request, target, @@ -1582,3 +1812,37 @@ def Stop(request, node__pb2.StopResponse.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def PreApproveKeysend(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/cln.Node/PreApproveKeysend', + node__pb2.PreapprovekeysendRequest.SerializeToString, + node__pb2.PreapprovekeysendResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def PreApproveInvoice(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/cln.Node/PreApproveInvoice', + node__pb2.PreapproveinvoiceRequest.SerializeToString, + node__pb2.PreapproveinvoiceResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/contrib/pyln-testing/pyln/testing/primitives_pb2.py b/contrib/pyln-testing/pyln/testing/primitives_pb2.py index 48421bdf21cc..77fec23789dd 100644 --- a/contrib/pyln-testing/pyln/testing/primitives_pb2.py +++ b/contrib/pyln-testing/pyln/testing/primitives_pb2.py @@ -15,14 +15,16 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10primitives.proto\x12\x03\x63ln\"\x16\n\x06\x41mount\x12\x0c\n\x04msat\x18\x01 \x01(\x04\"D\n\x0b\x41mountOrAll\x12\x1d\n\x06\x61mount\x18\x01 \x01(\x0b\x32\x0b.cln.AmountH\x00\x12\r\n\x03\x61ll\x18\x02 \x01(\x08H\x00\x42\x07\n\x05value\"D\n\x0b\x41mountOrAny\x12\x1d\n\x06\x61mount\x18\x01 \x01(\x0b\x32\x0b.cln.AmountH\x00\x12\r\n\x03\x61ny\x18\x02 \x01(\x08H\x00\x42\x07\n\x05value\"\x19\n\x17\x43hannelStateChangeCause\"(\n\x08Outpoint\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\x0e\n\x06outnum\x18\x02 \x01(\r\"h\n\x07\x46\x65\x65rate\x12\x0e\n\x04slow\x18\x01 \x01(\x08H\x00\x12\x10\n\x06normal\x18\x02 \x01(\x08H\x00\x12\x10\n\x06urgent\x18\x03 \x01(\x08H\x00\x12\x0f\n\x05perkb\x18\x04 \x01(\rH\x00\x12\x0f\n\x05perkw\x18\x05 \x01(\rH\x00\x42\x07\n\x05style\":\n\nOutputDesc\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x1b\n\x06\x61mount\x18\x02 \x01(\x0b\x32\x0b.cln.Amount\"t\n\x08RouteHop\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x18\n\x10short_channel_id\x18\x02 \x01(\t\x12\x1c\n\x07\x66\x65\x65\x62\x61se\x18\x03 \x01(\x0b\x32\x0b.cln.Amount\x12\x0f\n\x07\x66\x65\x65prop\x18\x04 \x01(\r\x12\x13\n\x0b\x65xpirydelta\x18\x05 \x01(\r\"(\n\tRoutehint\x12\x1b\n\x04hops\x18\x01 \x03(\x0b\x32\r.cln.RouteHop\".\n\rRoutehintList\x12\x1d\n\x05hints\x18\x02 \x03(\x0b\x32\x0e.cln.Routehint\"\'\n\x08TlvEntry\x12\x0c\n\x04type\x18\x01 \x01(\x04\x12\r\n\x05value\x18\x02 \x01(\x0c\"+\n\tTlvStream\x12\x1e\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\r.cln.TlvEntry*\x1e\n\x0b\x43hannelSide\x12\x06\n\x02IN\x10\x00\x12\x07\n\x03OUT\x10\x01*\x84\x02\n\x0c\x43hannelState\x12\x0c\n\x08Openingd\x10\x00\x12\x1a\n\x16\x43hanneldAwaitingLockin\x10\x01\x12\x12\n\x0e\x43hanneldNormal\x10\x02\x12\x18\n\x14\x43hanneldShuttingDown\x10\x03\x12\x17\n\x13\x43losingdSigexchange\x10\x04\x12\x14\n\x10\x43losingdComplete\x10\x05\x12\x16\n\x12\x41waitingUnilateral\x10\x06\x12\x14\n\x10\x46undingSpendSeen\x10\x07\x12\x0b\n\x07Onchain\x10\x08\x12\x15\n\x11\x44ualopendOpenInit\x10\t\x12\x1b\n\x17\x44ualopendAwaitingLockin\x10\nb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10primitives.proto\x12\x03\x63ln\"\x16\n\x06\x41mount\x12\x0c\n\x04msat\x18\x01 \x01(\x04\"D\n\x0b\x41mountOrAll\x12\x1d\n\x06\x61mount\x18\x01 \x01(\x0b\x32\x0b.cln.AmountH\x00\x12\r\n\x03\x61ll\x18\x02 \x01(\x08H\x00\x42\x07\n\x05value\"D\n\x0b\x41mountOrAny\x12\x1d\n\x06\x61mount\x18\x01 \x01(\x0b\x32\x0b.cln.AmountH\x00\x12\r\n\x03\x61ny\x18\x02 \x01(\x08H\x00\x42\x07\n\x05value\"\x19\n\x17\x43hannelStateChangeCause\"(\n\x08Outpoint\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\x0e\n\x06outnum\x18\x02 \x01(\r\"h\n\x07\x46\x65\x65rate\x12\x0e\n\x04slow\x18\x01 \x01(\x08H\x00\x12\x10\n\x06normal\x18\x02 \x01(\x08H\x00\x12\x10\n\x06urgent\x18\x03 \x01(\x08H\x00\x12\x0f\n\x05perkb\x18\x04 \x01(\rH\x00\x12\x0f\n\x05perkw\x18\x05 \x01(\rH\x00\x42\x07\n\x05style\":\n\nOutputDesc\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x1b\n\x06\x61mount\x18\x02 \x01(\x0b\x32\x0b.cln.Amount\"t\n\x08RouteHop\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x18\n\x10short_channel_id\x18\x02 \x01(\t\x12\x1c\n\x07\x66\x65\x65\x62\x61se\x18\x03 \x01(\x0b\x32\x0b.cln.Amount\x12\x0f\n\x07\x66\x65\x65prop\x18\x04 \x01(\r\x12\x13\n\x0b\x65xpirydelta\x18\x05 \x01(\r\"(\n\tRoutehint\x12\x1b\n\x04hops\x18\x01 \x03(\x0b\x32\r.cln.RouteHop\".\n\rRoutehintList\x12\x1d\n\x05hints\x18\x02 \x03(\x0b\x32\x0e.cln.Routehint\"\'\n\x08TlvEntry\x12\x0c\n\x04type\x18\x01 \x01(\x04\x12\r\n\x05value\x18\x02 \x01(\x0c\"+\n\tTlvStream\x12\x1e\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\r.cln.TlvEntry*$\n\x0b\x43hannelSide\x12\t\n\x05LOCAL\x10\x00\x12\n\n\x06REMOTE\x10\x01*\x84\x02\n\x0c\x43hannelState\x12\x0c\n\x08Openingd\x10\x00\x12\x1a\n\x16\x43hanneldAwaitingLockin\x10\x01\x12\x12\n\x0e\x43hanneldNormal\x10\x02\x12\x18\n\x14\x43hanneldShuttingDown\x10\x03\x12\x17\n\x13\x43losingdSigexchange\x10\x04\x12\x14\n\x10\x43losingdComplete\x10\x05\x12\x16\n\x12\x41waitingUnilateral\x10\x06\x12\x14\n\x10\x46undingSpendSeen\x10\x07\x12\x0b\n\x07Onchain\x10\x08\x12\x15\n\x11\x44ualopendOpenInit\x10\t\x12\x1b\n\x17\x44ualopendAwaitingLockin\x10\n*\xea\x03\n\tHtlcState\x12\x0f\n\x0bSentAddHtlc\x10\x00\x12\x11\n\rSentAddCommit\x10\x01\x12\x15\n\x11RcvdAddRevocation\x10\x02\x12\x14\n\x10RcvdAddAckCommit\x10\x03\x12\x18\n\x14SentAddAckRevocation\x10\x04\x12\x18\n\x14RcvdAddAckRevocation\x10\x05\x12\x12\n\x0eRcvdRemoveHtlc\x10\x06\x12\x14\n\x10RcvdRemoveCommit\x10\x07\x12\x18\n\x14SentRemoveRevocation\x10\x08\x12\x17\n\x13SentRemoveAckCommit\x10\t\x12\x1b\n\x17RcvdRemoveAckRevocation\x10\n\x12\x11\n\rRCVD_ADD_HTLC\x10\x0b\x12\x13\n\x0fRCVD_ADD_COMMIT\x10\x0c\x12\x17\n\x13SENT_ADD_REVOCATION\x10\r\x12\x17\n\x13SENT_ADD_ACK_COMMIT\x10\x0e\x12\x14\n\x10SENT_REMOVE_HTLC\x10\x0f\x12\x16\n\x12SENT_REMOVE_COMMIT\x10\x10\x12\x1a\n\x16RCVD_REMOVE_REVOCATION\x10\x11\x12\x1a\n\x16RCVD_REMOVE_ACK_COMMIT\x10\x12\x12\x1e\n\x1aSENT_REMOVE_ACK_REVOCATION\x10\x13\x62\x06proto3') _CHANNELSIDE = DESCRIPTOR.enum_types_by_name['ChannelSide'] ChannelSide = enum_type_wrapper.EnumTypeWrapper(_CHANNELSIDE) _CHANNELSTATE = DESCRIPTOR.enum_types_by_name['ChannelState'] ChannelState = enum_type_wrapper.EnumTypeWrapper(_CHANNELSTATE) -IN = 0 -OUT = 1 +_HTLCSTATE = DESCRIPTOR.enum_types_by_name['HtlcState'] +HtlcState = enum_type_wrapper.EnumTypeWrapper(_HTLCSTATE) +LOCAL = 0 +REMOTE = 1 Openingd = 0 ChanneldAwaitingLockin = 1 ChanneldNormal = 2 @@ -34,6 +36,26 @@ Onchain = 8 DualopendOpenInit = 9 DualopendAwaitingLockin = 10 +SentAddHtlc = 0 +SentAddCommit = 1 +RcvdAddRevocation = 2 +RcvdAddAckCommit = 3 +SentAddAckRevocation = 4 +RcvdAddAckRevocation = 5 +RcvdRemoveHtlc = 6 +RcvdRemoveCommit = 7 +SentRemoveRevocation = 8 +SentRemoveAckCommit = 9 +RcvdRemoveAckRevocation = 10 +RCVD_ADD_HTLC = 11 +RCVD_ADD_COMMIT = 12 +SENT_ADD_REVOCATION = 13 +SENT_ADD_ACK_COMMIT = 14 +SENT_REMOVE_HTLC = 15 +SENT_REMOVE_COMMIT = 16 +RCVD_REMOVE_REVOCATION = 17 +RCVD_REMOVE_ACK_COMMIT = 18 +SENT_REMOVE_ACK_REVOCATION = 19 _AMOUNT = DESCRIPTOR.message_types_by_name['Amount'] @@ -136,9 +158,11 @@ DESCRIPTOR._options = None _CHANNELSIDE._serialized_start=718 - _CHANNELSIDE._serialized_end=748 - _CHANNELSTATE._serialized_start=751 - _CHANNELSTATE._serialized_end=1011 + _CHANNELSIDE._serialized_end=754 + _CHANNELSTATE._serialized_start=757 + _CHANNELSTATE._serialized_end=1017 + _HTLCSTATE._serialized_start=1020 + _HTLCSTATE._serialized_end=1510 _AMOUNT._serialized_start=25 _AMOUNT._serialized_end=47 _AMOUNTORALL._serialized_start=49 diff --git a/contrib/pyln-testing/pyln/testing/utils.py b/contrib/pyln-testing/pyln/testing/utils.py index 4a964d8a6792..ae5a0d2138a9 100644 --- a/contrib/pyln-testing/pyln/testing/utils.py +++ b/contrib/pyln-testing/pyln/testing/utils.py @@ -18,7 +18,6 @@ import lzma import math import os -import psutil # type: ignore import random import re import shutil @@ -460,7 +459,7 @@ def get_proxy(self): # int > 0 := wait for at least N transactions # 'tx_id' := wait for one transaction id given as a string # ['tx_id1', 'tx_id2'] := wait until all of the specified transaction IDs - def generate_block(self, numblocks=1, wait_for_mempool=0, to_addr=None): + def generate_block(self, numblocks=1, wait_for_mempool=0, to_addr=None, needfeerate=None): if wait_for_mempool: if isinstance(wait_for_mempool, str): wait_for_mempool = [wait_for_mempool] @@ -469,7 +468,7 @@ def generate_block(self, numblocks=1, wait_for_mempool=0, to_addr=None): else: wait_for(lambda: len(self.rpc.getrawmempool()) >= wait_for_mempool) - mempool = self.rpc.getrawmempool() + mempool = self.rpc.getrawmempool(True) logging.debug("Generating {numblocks}, confirming {lenmempool} transactions: {mempool}".format( numblocks=numblocks, mempool=mempool, @@ -479,6 +478,21 @@ def generate_block(self, numblocks=1, wait_for_mempool=0, to_addr=None): # As of 0.16, generate() is removed; use generatetoaddress. if to_addr is None: to_addr = self.rpc.getnewaddress() + + # We assume all-or-nothing. + if needfeerate is not None: + assert numblocks == 1 + # If any tx including ancestors is above the given feerate, mine all. + for txid, details in mempool.items(): + feerate = float(details['fees']['ancestor']) * 100_000_000 / (float(details['ancestorsize']) * 4 / 1000) + if feerate >= needfeerate: + return self.rpc.generatetoaddress(numblocks, to_addr) + else: + print(f"Feerate {feerate} for {txid} below {needfeerate}") + + # Otherwise, mine none. + return self.rpc.generateblock(to_addr, []) + return self.rpc.generatetoaddress(numblocks, to_addr) def simple_reorg(self, height, shift=0): @@ -547,6 +561,7 @@ def __init__(self, bitcoin_dir="/tmp/bitcoind-test", rpcport=None): '-nowallet', '-validatepegin=0', '-con_blocksubsidy=5000000000', + '-acceptnonstdtxn=1', # FIXME Issues such as dust limit interacting with anchors ] conf_file = os.path.join(bitcoin_dir, 'elements.conf') config['rpcport'] = self.rpcport @@ -583,7 +598,7 @@ def __init__( self.disconnect_file = None self.rpcproxy = bitcoindproxy - self.env['CLN_PLUGIN_LOG'] = "gl_plugin=trace,gl_rpc=trace,gl_grpc=trace,debug" + self.env['CLN_PLUGIN_LOG'] = "cln_plugin=trace,cln_rpc=trace,cln_grpc=trace,debug" self.opts = LIGHTNINGD_CONFIG.copy() opts = { @@ -780,7 +795,7 @@ def __init__(self, node_id, lightning_dir, bitcoind, executor, valgrind, may_fai if dsn is not None: self.daemon.opts['wallet'] = dsn if valgrind: - trace_skip_pattern = '*python*,*bitcoin-cli*,*elements-cli*,*cln-grpc' + trace_skip_pattern = '*python*,*bitcoin-cli*,*elements-cli*,*cln-*' if not valgrind_plugins: trace_skip_pattern += ',*plugins*' self.daemon.cmd_prefix = [ @@ -836,8 +851,41 @@ def _create_jsonrpc_rpc(self, jsonschemas): jsonschemas=jsonschemas ) + @property + def grpc(self): + """Tiny helper to return a grpc stub if grpc was configured. + """ + # Before doing anything let's see if we have a grpc-port at all + try: + grpc_port = int(filter( + lambda v: v[0] == 'grpc-port', + self.daemon.opts.items() + ).__next__()[1]) + except Exception: + raise ValueError("grpc-port is not specified, can't connect over grpc") + + import grpc + p = Path(self.daemon.lightning_dir) / TEST_NETWORK + cert, key, ca = [f.open('rb').read() for f in [ + p / 'client.pem', + p / 'client-key.pem', + p / "ca.pem"]] + creds = grpc.ssl_channel_credentials( + root_certificates=ca, + private_key=key, + certificate_chain=cert, + ) + + channel = grpc.secure_channel( + f"localhost:{grpc_port}", + creds, + options=(('grpc.ssl_target_name_override', 'cln'),) + ) + from pyln.testing import node_pb2_grpc as nodegrpc + return nodegrpc.NodeStub(channel) + def connect(self, remote_node): - self.rpc.connect(remote_node.info['id'], '127.0.0.1', remote_node.daemon.port) + self.rpc.connect(remote_node.info['id'], '127.0.0.1', remote_node.port) def is_connected(self, remote_node): return remote_node.info['id'] in [p['id'] for p in self.rpc.listpeers()['peers']] @@ -845,6 +893,7 @@ def is_connected(self, remote_node): def openchannel(self, remote_node, capacity=FUNDAMOUNT, addrtype="bech32", confirm=True, wait_for_announce=True, connect=True): addr, wallettxid = self.fundwallet(10 * capacity, addrtype) + # connect if necessary if connect and not self.is_connected(remote_node): self.connect(remote_node) @@ -867,7 +916,7 @@ def fundwallet(self, sats, addrtype="bech32", mine_block=True): self.daemon.wait_for_log('Owning output .* txid {} CONFIRMED'.format(txid)) return addr, txid - def fundbalancedchannel(self, remote_node, total_capacity, announce=True): + def fundbalancedchannel(self, remote_node, total_capacity=FUNDAMOUNT, announce=True): ''' Creates a perfectly-balanced channel, as all things should be. ''' @@ -891,7 +940,9 @@ def fundbalancedchannel(self, remote_node, total_capacity, announce=True): else: chan_capacity = total_capacity - self.rpc.connect(remote_node.info['id'], 'localhost', remote_node.port) + # connect if necessary + if not self.is_connected(remote_node): + self.connect(remote_node) res = self.rpc.fundchannel(remote_node.info['id'], chan_capacity, feerate='slow', minconf=0, announce=announce, push_msat=Millisatoshi(chan_capacity * 500)) blockid = self.bitcoin.generate_block(1, wait_for_mempool=res['txid'])[0] @@ -972,11 +1023,6 @@ def restart(self, timeout=10, clean=True): self.start() - def fund_channel(self, l2, amount, wait_for_active=True, announce_channel=True): - warnings.warn("LightningNode.fund_channel is deprecated in favor of " - "LightningNode.fundchannel", category=DeprecationWarning) - return self.fundchannel(l2, amount, wait_for_active, announce_channel) - def fundchannel(self, l2, amount=FUNDAMOUNT, wait_for_active=True, announce_channel=True, **kwargs): # Give yourself some funds to work with @@ -998,6 +1044,10 @@ def has_funds_on_addr(addr): # Now we should. wait_for(lambda: has_funds_on_addr(addr)) + # connect if necessary + if not self.is_connected(l2): + self.connect(l2) + # Now go ahead and open a channel res = self.rpc.fundchannel(l2.info['id'], amount, announce=announce_channel, @@ -1099,14 +1149,13 @@ def wait_for_route(self, destination, timeout=TIMEOUT): # `scids` can be a list of strings. If unset wait on all channels. def wait_for_htlcs(self, scids=None): peers = self.rpc.listpeers()['peers'] - for p, peer in enumerate(peers): - if 'channels' in peer: - channels_peer = self.rpc.listpeerchannels(peer['id']) - for c, channel in enumerate(channels_peer['channels']): - if scids is not None and channel['short_channel_id'] not in scids: - continue - if 'htlcs' in channel: - wait_for(lambda: len(self.rpc.listpeerchannels(peer["id"])['channels'][c]['htlcs']) == 0) + for peer in peers: + channels = self.rpc.listpeerchannels(peer['id'])['channels'] + for idx, channel in enumerate(channels): + if scids is not None and channel['short_channel_id'] not in scids: + continue + if 'htlcs' in channel: + wait_for(lambda: len(self.rpc.listpeerchannels(peer["id"])['channels'][idx]['htlcs']) == 0) # This sends money to a directly connected peer def pay(self, dst, amt, label=None): @@ -1190,7 +1239,7 @@ def mock_estimatesmartfee(r): self.daemon.rpcproxy.mock_rpc('estimatesmartfee', mock_estimatesmartfee) # Technically, this waits until it's called, not until it's processed. - # We wait until all three levels have been called. + # We wait until all four levels have been called. if wait_for_effect: wait_for(lambda: self.daemon.rpcproxy.mock_counts['estimatesmartfee'] >= 4) @@ -1204,6 +1253,53 @@ def force_feerates(self, rate): self.daemon.wait_for_log('peer_out WIRE_UPDATE_FEE') assert(self.rpc.feerates('perkw')['perkw']['opening'] == rate) + def wait_for_onchaind_txs(self, *args): + """Wait for onchaind to ask lightningd to create one or more txs. Each arg is a pair of typename, resolvename. Returns tuples of the rawtx, txid and number of blocks delay for each pair. + """ + # Could happen in any order. + needle = self.daemon.logsearch_start + ret = () + for (name, resolve) in args: + self.daemon.logsearch_start = needle + r = self.daemon.wait_for_log('Telling lightningd about {} to resolve {}' + .format(name, resolve)) + blocks = int(re.search(r'\(([-0-9]*) more blocks\)', r).group(1)) + + # The next 'Broadcast for onchaind' will be the tx. + # Now grab the corresponding broadcast lightningd did, to get actual tx: + r = self.daemon.wait_for_log('Broadcast for onchaind tx') + rawtx = re.search(r'.* tx ([0-9a-fA-F]*)', r).group(1) + txid = self.bitcoin.rpc.decoderawtransaction(rawtx, True)['txid'] + ret = ret + ((rawtx, txid, blocks),) + return ret + + def wait_for_onchaind_tx(self, name, resolve): + return self.wait_for_onchaind_txs((name, resolve))[0] + + def mine_txid_or_rbf(self, txid, numblocks=1): + """Wait for a txid to be broadcast, or an rbf. Return the one actually mined""" + # Hack so we can mutate the txid: pass it in a list + def rbf_or_txid_broadcast(txids): + # RBF onchain txid d4b597505b543a4b8b42ab4d481fd7a533febb7e7df150ca70689e6d046612f7 (fee 6564sat) with txid 979878b8f855d3895d1cd29bd75a60b21492c4842e38099186a8e649bee02c7c (fee 8205sat) + line = self.daemon.is_in_log("RBF onchain txid {}".format(txids[-1])) + if line is not None: + newtxid = re.search(r'with txid ([0-9a-fA-F]*)', line).group(1) + txids.append(newtxid) + mempool = self.bitcoin.rpc.getrawmempool() + return any([t in mempool for t in txids]) + + txids = [txid] + wait_for(lambda: rbf_or_txid_broadcast(txids)) + blocks = self.bitcoin.generate_block(numblocks) + + # It might have snuck an RBF in at the last minute! + rbf_or_txid_broadcast(txids) + + for tx in self.bitcoin.rpc.getblock(blocks[0])['tx']: + if tx in txids: + return tx + raise ValueError("None of the rbf txs were mined?") + def wait_for_onchaind_broadcast(self, name, resolve=None): """Wait for onchaind to drop tx name to resolve (if any)""" if resolve: @@ -1252,11 +1348,18 @@ def passes_filters(hmsg, filters): def config(self, config_name): try: - opt = self.rpc.listconfigs(config_name) - return opt[config_name] + config = self.rpc.listconfigs(config_name) except RpcError: return None + config = config['configs'][config_name] + for valfield in ('set', + 'value_str', 'value_bool', 'value_int', + 'values_str', 'values_bool', 'values_int'): + if valfield in config: + return config[valfield] + raise ValueError("Unknown value in config {}".format(config)) + def dev_pay(self, bolt11, amount_msat=None, label=None, riskfactor=None, maxfeepercent=None, retry_for=None, maxdelay=None, exemptfee=None, use_shadow=True, exclude=[]): @@ -1328,57 +1431,11 @@ def flock(directory: Path): fname.unlink() -class Throttler(object): - """Throttles the creation of system-processes to avoid overload. - - There is no reason to overload the system with too many processes - being spawned or run at the same time. It causes timeouts by - aggressively preempting processes and swapping if the memory limit is - reached. In order to reduce this loss of performance we provide a - `wait()` method which will serialize the creation of processes, but - also delay if the system load is too high. - - Notice that technically we are throttling too late, i.e., we react - to an overload, but chances are pretty good that some other - already running process is about to terminate, and so the overload - is short-lived. We throttle when the process object is first - created, not when restarted, in order to avoid delaying running - tests, which could cause more timeouts. - - """ - def __init__(self, directory: str, target: float = 90): - """If specified we try to stick to a load of target (in percent). - """ - self.target = target - self.current_load = self.target # Start slow - psutil.cpu_percent() # Prime the internal load metric - self.directory = directory - - def wait(self): - start_time = time.time() - with flock(self.directory): - # We just got the lock, assume someone else just released it - self.current_load = 100 - while self.load() >= self.target: - time.sleep(1) - - self.current_load = 100 # Back off slightly to avoid triggering right away - print("Throttler delayed startup for {} seconds".format(time.time() - start_time)) - - def load(self): - """An exponential moving average of the load - """ - decay = 0.5 - load = psutil.cpu_percent() - self.current_load = decay * load + (1 - decay) * self.current_load - return self.current_load - - class NodeFactory(object): """A factory to setup and start `lightningd` daemons. """ def __init__(self, request, testname, bitcoind, executor, directory, - db_provider, node_cls, throttler, jsonschemas): + db_provider, node_cls, jsonschemas): if request.node.get_closest_marker("slow_test") and SLOW_MACHINE: self.valgrind = False else: @@ -1393,7 +1450,6 @@ def __init__(self, request, testname, bitcoind, executor, directory, self.lock = threading.Lock() self.db_provider = db_provider self.node_cls = node_cls - self.throttler = throttler self.jsonschemas = jsonschemas def split_options(self, opts): @@ -1461,7 +1517,6 @@ def get_node(self, node_id=None, options=None, dbfile=None, bkpr_dbfile=None, feerates=(15000, 11000, 7500, 3750), start=True, wait_for_bitcoind_sync=True, may_fail=False, expect_fail=False, cleandir=True, **kwargs): - self.throttler.wait() node_id = self.get_node_id() if not node_id else node_id port = reserve_unused_port() @@ -1578,12 +1633,14 @@ def killall(self, expected_successes): err_msgs = [] for i in range(len(self.nodes)): leaks = None - # leak detection upsets VALGRIND by reading uninitialized mem. + # leak detection upsets VALGRIND by reading uninitialized mem, + # and valgrind adds extra fds. # If it's dead, we'll catch it below. if not self.valgrind and DEVELOPER: try: # This also puts leaks in log. leaks = self.nodes[i].rpc.dev_memleak()['leaks'] + self.nodes[i].rpc.dev_report_fds() except Exception: pass diff --git a/contrib/pyln-testing/pyproject.toml b/contrib/pyln-testing/pyproject.toml index 549c96de5ab6..f9c3ebea55be 100644 --- a/contrib/pyln-testing/pyproject.toml +++ b/contrib/pyln-testing/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pyln-testing" -version = "22.11rc1" +version = "23.05" description = "Test your Core Lightning integration, plugins or whatever you want" authors = ["Christian Decker "] license = "BSD-MIT" @@ -22,7 +22,7 @@ Flask = "^2.0.3" cheroot = "^8.6.0" psutil = "^5.9.0" grpcio = ">=1.47" -protobuf = ">=3.20.3,<4" +protobuf = ">=3.20.3" [tool.poetry.dev-dependencies] pyln-client = { path = "../pyln-client", develop = true} diff --git a/contrib/reprobuild/Dockerfile.bionic b/contrib/reprobuild/Dockerfile.bionic index 782631de3c6b..173553425b46 100644 --- a/contrib/reprobuild/Dockerfile.bionic +++ b/contrib/reprobuild/Dockerfile.bionic @@ -4,6 +4,7 @@ ENV TZ=UTC RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone ENV RUST_PROFILE=release ENV PATH=/root/.cargo/bin:/root/.pyenv/shims:/root/.pyenv/bin:$PATH +ENV PROTOC_VERSION=22.0 RUN sed -i '/updates/d' /etc/apt/sources.list && \ sed -i '/security/d' /etc/apt/sources.list @@ -45,20 +46,24 @@ RUN wget https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py && python3 /tmp RUN wget https://sh.rustup.rs -O rustup-install.sh && \ bash rustup-install.sh --default-toolchain none --quiet -y && \ rm rustup-install.sh && \ - /root/.cargo/bin/rustup install 1.62 + /root/.cargo/bin/rustup install 1.65 + +# Download protoc manually, it is in the update repos which we +# disabled above, so `apt-get` can't find it anymore. +RUN cd /tmp/ && \ + wget https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip && \ + unzip protoc-${PROTOC_VERSION}-linux-x86_64.zip && \ + mv bin/protoc /usr/local/bin && \ + rm -rf include bin protoc-${PROTOC_VERSION}-linux-x86_64.zip RUN mkdir /build WORKDIR /build -CMD git clone /repo /build \ - && poetry export -o requirements.txt --without-hashes \ +CMD poetry export -o requirements.txt --without-hashes \ && pip install -r requirements.txt\ - && tools/build-release.sh zipfile \ && mkdir -p /repro \ && cd /repro \ && unzip /build/release/*.zip \ && cd clightning* \ && tools/repro-build.sh \ - && cp *.xz /build/release/* /repo/release/ \ - && cd /repo/release \ - && sha256sum * + && cp *.xz /build/release/ diff --git a/contrib/reprobuild/Dockerfile.focal b/contrib/reprobuild/Dockerfile.focal index b0a20f10d7f0..80a2ab8e770e 100644 --- a/contrib/reprobuild/Dockerfile.focal +++ b/contrib/reprobuild/Dockerfile.focal @@ -3,7 +3,8 @@ FROM focal ENV TZ=UTC RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone ENV RUST_PROFILE=release -ENV PATH=/root/.cargo/bin:$PATH +ENV PATH=/root/.pyenv/shims:/root/.pyenv/bin:/root/.cargo/bin:$PATH +ENV PROTOC_VERSION=22.0 RUN sed -i '/updates/d' /etc/apt/sources.list && \ sed -i '/security/d' /etc/apt/sources.list @@ -16,17 +17,27 @@ RUN apt-get update \ file \ gettext \ git \ - libgmp-dev \ libpq-dev \ libsodium23 \ libtool \ m4 \ - python3-setuptools \ sudo \ unzip \ wget \ zip +# install Python3.8 (more reproducible than relying on python3-setuptools) +RUN git clone https://github.com/pyenv/pyenv.git /root/.pyenv && \ + apt-get install -y --no-install-recommends \ + libbz2-dev \ + libffi-dev \ + libreadline-dev \ + libsqlite3-dev \ + libssl-dev \ + zlib1g-dev && \ + pyenv install 3.8.0 && \ + pyenv global 3.8.0 + RUN wget https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py && python3 /tmp/get-pip.py \ && rm /tmp/get-pip.py \ && pip install poetry @@ -34,21 +45,24 @@ RUN wget https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py && python3 /tmp RUN wget https://sh.rustup.rs -O rustup-install.sh && \ bash rustup-install.sh --default-toolchain none --quiet -y && \ rm rustup-install.sh && \ - /root/.cargo/bin/rustup install 1.62 + /root/.cargo/bin/rustup install 1.65 + +# Download protoc manually, it is in the update repos which we +# disabled above, so `apt-get` can't find it anymore. +RUN cd /tmp/ && \ + wget https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip && \ + unzip protoc-${PROTOC_VERSION}-linux-x86_64.zip && \ + mv bin/protoc /usr/local/bin && \ + rm -rf include bin protoc-${PROTOC_VERSION}-linux-x86_64.zip RUN mkdir /build WORKDIR /build -CMD git clone /repo /build \ - && poetry export -o requirements.txt --without-hashes \ +CMD poetry export -o requirements.txt --without-hashes \ && pip install -r requirements.txt \ - && tools/build-release.sh zipfile \ && mkdir -p /repro \ && cd /repro \ && unzip /build/release/*.zip \ && cd clightning* \ - && tools/repro-build.sh \ - && mkdir -p /repo/release \ - && cp *.xz /build/release/* /repo/release/ \ - && cd /repo/release/ \ - && sha256sum * + && tools/repro-build.sh \ + && cp *.xz /build/release/ diff --git a/contrib/reprobuild/Dockerfile.jammy b/contrib/reprobuild/Dockerfile.jammy index f76d2ea64706..efd015f232f8 100644 --- a/contrib/reprobuild/Dockerfile.jammy +++ b/contrib/reprobuild/Dockerfile.jammy @@ -3,7 +3,8 @@ FROM jammy ENV TZ=UTC RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone ENV RUST_PROFILE=release -ENV PATH=/root/.cargo/bin:$PATH +ENV PATH=/root/.pyenv/shims:/root/.pyenv/bin:/root/.cargo/bin:$PATH +ENV PROTOC_VERSION=22.0 RUN sed -i '/updates/d' /etc/apt/sources.list && \ sed -i '/security/d' /etc/apt/sources.list @@ -16,18 +17,28 @@ RUN apt-get update \ file \ gettext \ git \ - libgmp-dev \ libsqlite3-dev \ libpq-dev \ libsodium23 \ libtool \ m4 \ - python3-setuptools \ sudo \ unzip \ wget \ zip +# Install Python3.10 (more reproducible than relying on python3-setuptools) +RUN git clone https://github.com/pyenv/pyenv.git /root/.pyenv && \ + apt-get install -y --no-install-recommends \ + libbz2-dev \ + libffi-dev \ + libreadline-dev \ + libsqlite3-dev \ + libssl-dev \ + zlib1g-dev && \ + pyenv install 3.10.0 && \ + pyenv global 3.10.0 + RUN wget https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py && python3 /tmp/get-pip.py \ && rm /tmp/get-pip.py \ && pip install poetry @@ -35,21 +46,24 @@ RUN wget https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py && python3 /tmp RUN wget https://sh.rustup.rs -O rustup-install.sh && \ bash rustup-install.sh --default-toolchain none --quiet -y && \ rm rustup-install.sh && \ - /root/.cargo/bin/rustup install 1.62 + /root/.cargo/bin/rustup install 1.65 + +# Download protoc manually, it is in the update repos which we +# disabled above, so `apt-get` can't find it anymore. +RUN cd /tmp/ && \ + wget https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip && \ + unzip protoc-${PROTOC_VERSION}-linux-x86_64.zip && \ + mv bin/protoc /usr/local/bin && \ + rm -rf include bin protoc-${PROTOC_VERSION}-linux-x86_64.zip RUN mkdir /build WORKDIR /build -CMD git clone /repo /build \ - && poetry export -o requirements.txt --without-hashes \ +CMD poetry export -o requirements.txt --without-hashes \ && pip install -r requirements.txt \ - && tools/build-release.sh zipfile \ && mkdir -p /repro \ && cd /repro \ && unzip /build/release/*.zip \ && cd clightning* \ - && tools/repro-build.sh \ - && mkdir -p /repo/release \ - && cp *.xz /build/release/* /repo/release/ \ - && cd /repo/release/ \ - && sha256sum * + && tools/repro-build.sh \ + && cp *.xz /build/release/ diff --git a/contrib/startup_regtest.sh b/contrib/startup_regtest.sh index 3f40fcb912c4..07fab1c3dc00 100755 --- a/contrib/startup_regtest.sh +++ b/contrib/startup_regtest.sh @@ -122,7 +122,7 @@ start_nodes() { done if [ -z "$EATMYDATA" ]; then - echo "WARNING: eatmydata not found: instal it for faster testing" + echo "WARNING: eatmydata not found: install it for faster testing" fi # Give a hint. echo "Commands: " @@ -144,6 +144,8 @@ start_ln() { # Modern bitcoind needs createwallet echo "Making \"default\" bitcoind wallet." bitcoin-cli -regtest createwallet default >/dev/null 2>&1 + # But it might already exist, load it + bitcoin-cli -regtest loadwallet default bitcoin-cli -regtest generatetoaddress 1 "$(bitcoin-cli -regtest getnewaddress)" > /dev/null else bitcoin-cli -regtest loadwallet default diff --git a/db/bindings.c b/db/bindings.c index fc95ca52f031..ac2fc4fa211a 100644 --- a/db/bindings.c +++ b/db/bindings.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -131,6 +132,11 @@ void db_bind_channel_id(struct db_stmt *stmt, int pos, const struct channel_id * db_bind_blob(stmt, pos, id->id, sizeof(id->id)); } +void db_bind_channel_type(struct db_stmt *stmt, int pos, const struct channel_type *type) +{ + db_bind_talarr(stmt, pos, type->features); +} + void db_bind_node_id(struct db_stmt *stmt, int pos, const struct node_id *id) { db_bind_blob(stmt, pos, id->k, sizeof(id->k)); @@ -159,8 +165,8 @@ void db_bind_pubkey(struct db_stmt *stmt, int pos, const struct pubkey *pk) db_bind_blob(stmt, pos, der, PUBKEY_CMPR_LEN); } -void db_bind_scid(struct db_stmt *stmt, int col, - const struct short_channel_id *id) +void db_bind_short_channel_id(struct db_stmt *stmt, int col, + const struct short_channel_id *id) { db_bind_u64(stmt, col, id->u64); } @@ -361,12 +367,23 @@ void db_col_pubkey(struct db_stmt *stmt, assert(ok); } -void db_col_scid(struct db_stmt *stmt, const char *colname, - struct short_channel_id *dest) +void db_col_short_channel_id(struct db_stmt *stmt, const char *colname, + struct short_channel_id *dest) { dest->u64 = db_col_u64(stmt, colname); } +void *db_col_optional_(tal_t *dst, + struct db_stmt *stmt, const char *colname, + void (*colfn)(struct db_stmt *, const char *, void *)) +{ + if (db_col_is_null(stmt, colname)) + return tal_free(dst); + + colfn(stmt, colname, dst); + return dst; +} + struct short_channel_id * db_col_short_channel_id_arr(const tal_t *ctx, struct db_stmt *stmt, const char *colname) { @@ -413,19 +430,33 @@ struct bitcoin_tx *db_col_tx(const tal_t *ctx, struct db_stmt *stmt, const char size_t col = db_query_colnum(stmt, colname); const u8 *src = db_column_blob(stmt, col); size_t len = db_column_bytes(stmt, col); + struct bitcoin_tx *tx; + bool is_null; - db_column_null_warn(stmt, colname, col); - return pull_bitcoin_tx(ctx, &src, &len); + is_null = db_column_null_warn(stmt, colname, col); + tx = pull_bitcoin_tx(ctx, &src, &len); + + if (is_null || tx) return tx; + + /* Column wasn't null, but we couldn't retrieve a valid wally_tx! */ + u8 *tx_dup = tal_dup_arr(stmt, u8, src, len, 0); + + db_fatal("db_col_tx: Invalid bitcoin transaction bytes retrieved: %s", + tal_hex(stmt, tx_dup)); + return NULL; } struct wally_psbt *db_col_psbt(const tal_t *ctx, struct db_stmt *stmt, const char *colname) { + struct wally_psbt *psbt; size_t col = db_query_colnum(stmt, colname); const u8 *src = db_column_blob(stmt, col); size_t len = db_column_bytes(stmt, col); db_column_null_warn(stmt, colname, col); - return psbt_from_bytes(ctx, src, len); + psbt = psbt_from_bytes(ctx, src, len); + psbt_set_version(psbt, 2); + return psbt; } struct bitcoin_tx *db_col_psbt_to_tx(const tal_t *ctx, struct db_stmt *stmt, const char *colname) @@ -436,6 +467,12 @@ struct bitcoin_tx *db_col_psbt_to_tx(const tal_t *ctx, struct db_stmt *stmt, con return bitcoin_tx_with_psbt(ctx, psbt); } +struct channel_type *db_col_channel_type(const tal_t *ctx, struct db_stmt *stmt, + const char *colname) +{ + return channel_type_from(ctx, take(db_col_arr(NULL, stmt, colname, u8))); +} + void *db_col_arr_(const tal_t *ctx, struct db_stmt *stmt, const char *colname, size_t bytes, const char *label, const char *caller) { @@ -453,7 +490,8 @@ void *db_col_arr_(const tal_t *ctx, struct db_stmt *stmt, const char *colname, caller, colname, col, sourcelen, label, bytes); p = tal_arr_label(ctx, char, sourcelen, label); - memcpy(p, db_column_blob(stmt, col), sourcelen); + if (sourcelen != 0) + memcpy(p, db_column_blob(stmt, col), sourcelen); return p; } diff --git a/db/bindings.h b/db/bindings.h index cc7707cf5c4f..4a5556eb07ae 100644 --- a/db/bindings.h +++ b/db/bindings.h @@ -10,6 +10,7 @@ #include struct channel_id; +struct channel_type; struct db_stmt; struct node_id; struct onionreply; @@ -33,12 +34,13 @@ void db_bind_secret(struct db_stmt *stmt, int pos, const struct secret *s); void db_bind_secret_arr(struct db_stmt *stmt, int col, const struct secret *s); void db_bind_txid(struct db_stmt *stmt, int pos, const struct bitcoin_txid *t); void db_bind_channel_id(struct db_stmt *stmt, int pos, const struct channel_id *id); +void db_bind_channel_type(struct db_stmt *stmt, int pos, const struct channel_type *type); void db_bind_node_id(struct db_stmt *stmt, int pos, const struct node_id *ni); void db_bind_node_id_arr(struct db_stmt *stmt, int col, const struct node_id *ids); void db_bind_pubkey(struct db_stmt *stmt, int pos, const struct pubkey *p); -void db_bind_scid(struct db_stmt *stmt, int col, - const struct short_channel_id *id); +void db_bind_short_channel_id(struct db_stmt *stmt, int col, + const struct short_channel_id *id); void db_bind_short_channel_id_arr(struct db_stmt *stmt, int col, const struct short_channel_id *id); void db_bind_signature(struct db_stmt *stmt, int col, @@ -78,13 +80,15 @@ struct secret *db_col_secret_arr(const tal_t *ctx, struct db_stmt *stmt, const char *colname); void db_col_txid(struct db_stmt *stmt, const char *colname, struct bitcoin_txid *t); void db_col_channel_id(struct db_stmt *stmt, const char *colname, struct channel_id *dest); +struct channel_type *db_col_channel_type(const tal_t *ctx, struct db_stmt *stmt, + const char *colname); void db_col_node_id(struct db_stmt *stmt, const char *colname, struct node_id *ni); struct node_id *db_col_node_id_arr(const tal_t *ctx, struct db_stmt *stmt, const char *colname); void db_col_pubkey(struct db_stmt *stmt, const char *colname, struct pubkey *p); -void db_col_scid(struct db_stmt *stmt, const char *colname, - struct short_channel_id *dest); +void db_col_short_channel_id(struct db_stmt *stmt, const char *colname, + struct short_channel_id *dest); struct short_channel_id * db_col_short_channel_id_arr(const tal_t *ctx, struct db_stmt *stmt, const char *colname); bool db_col_signature(struct db_stmt *stmt, const char *colname, @@ -105,6 +109,20 @@ void *db_col_arr_(const tal_t *ctx, struct db_stmt *stmt, const char *colname, size_t bytes, const char *label, const char *caller); +/* Assumes void db_col_@type(stmt, colname, addr), and struct @type! */ +#define db_col_optional(ctx, stmt, colname, type) \ + ((struct type *)db_col_optional_(tal(ctx, struct type), \ + (stmt), (colname), \ + typesafe_cb_cast(void (*)(struct db_stmt *, const char *, void *), \ + void (*)(struct db_stmt *, const char *, struct type *), \ + db_col_##type))) + +void *WARN_UNUSED_RESULT db_col_optional_(tal_t *dst, + struct db_stmt *stmt, + const char *colname, + void (*colfn)(struct db_stmt *, + const char *, void *)); + /* Some useful default variants */ int db_col_int_or_default(struct db_stmt *stmt, const char *colname, int def); void db_col_amount_msat_or_default(struct db_stmt *stmt, const char *colname, diff --git a/db/exec.c b/db/exec.c index b791be16cf29..21b9beef36b3 100644 --- a/db/exec.c +++ b/db/exec.c @@ -25,7 +25,7 @@ int db_get_version(struct db *db) * table that doesn't exist yet, so we need to terminate and restart * the DB transaction. */ - if (!db_query_prepared(stmt)) { + if (!db_query_prepared_canfail(stmt)) { db_commit_transaction(stmt->db); db_begin_transaction(stmt->db); tal_free(stmt); @@ -45,7 +45,7 @@ u32 db_data_version_get(struct db *db) u32 version; stmt = db_prepare_v2(db, SQL("SELECT intval FROM vars WHERE name = 'data_version'")); /* postgres will act upset if the table doesn't exist yet. */ - if (!db_query_prepared(stmt)) { + if (!db_query_prepared_canfail(stmt)) { tal_free(stmt); return 0; } @@ -58,14 +58,13 @@ u32 db_data_version_get(struct db *db) return version; } -void db_set_intvar(struct db *db, char *varname, s64 val) +void db_set_intvar(struct db *db, const char *varname, s64 val) { size_t changes; struct db_stmt *stmt = db_prepare_v2(db, SQL("UPDATE vars SET intval=? WHERE name=?;")); db_bind_int(stmt, 0, val); db_bind_text(stmt, 1, varname); - if (!db_exec_prepared_v2(stmt)) - db_fatal("Error executing update: %s", stmt->error); + db_exec_prepared_v2(stmt); changes = db_count_changes(stmt); tal_free(stmt); @@ -73,19 +72,18 @@ void db_set_intvar(struct db *db, char *varname, s64 val) stmt = db_prepare_v2(db, SQL("INSERT INTO vars (name, intval) VALUES (?, ?);")); db_bind_text(stmt, 0, varname); db_bind_int(stmt, 1, val); - if (!db_exec_prepared_v2(stmt)) - db_fatal("Error executing insert: %s", stmt->error); + db_exec_prepared_v2(stmt); tal_free(stmt); } } -s64 db_get_intvar(struct db *db, char *varname, s64 defval) +s64 db_get_intvar(struct db *db, const char *varname, s64 defval) { s64 res = defval; struct db_stmt *stmt = db_prepare_v2( db, SQL("SELECT intval FROM vars WHERE name= ? LIMIT 1")); db_bind_text(stmt, 0, varname); - if (db_query_prepared(stmt) && db_step(stmt)) + if (db_query_prepared_canfail(stmt) && db_step(stmt)) res = db_col_int(stmt, "intval"); tal_free(stmt); diff --git a/db/exec.h b/db/exec.h index 70799532a55a..e592042d925c 100644 --- a/db/exec.h +++ b/db/exec.h @@ -13,7 +13,7 @@ struct db; * Utility function to store generic integer values in the * database. */ -void db_set_intvar(struct db *db, char *varname, s64 val); +void db_set_intvar(struct db *db, const char *varname, s64 val); /** * db_get_intvar - Retrieve an integer variable from the database @@ -21,7 +21,7 @@ void db_set_intvar(struct db *db, char *varname, s64 val); * Either returns the value in the database, or @defval if * the query failed or no such variable exists. */ -s64 db_get_intvar(struct db *db, char *varname, s64 defval); +s64 db_get_intvar(struct db *db, const char *varname, s64 defval); /* Get the current data version (entries). */ u32 db_data_version_get(struct db *db); diff --git a/db/utils.c b/db/utils.c index 106aae834905..9449e0160267 100644 --- a/db/utils.c +++ b/db/utils.c @@ -21,9 +21,13 @@ size_t db_query_colnum(const struct db_stmt *stmt, assert(stmt->query->colnames != NULL); col = hash_djb2(colname) % stmt->query->num_colnames; - /* Will crash on NULL, which is the Right Thing */ - while (!streq(stmt->query->colnames[col].sqlname, - colname)) { + for (;;) { + const char *n = stmt->query->colnames[col].sqlname; + if (!n) + db_fatal("Unknown column name %s in query %s", + colname, stmt->query->query); + if (streq(n, colname)) + break; col = (col + 1) % stmt->query->num_colnames; } @@ -135,7 +139,7 @@ struct db_stmt *db_prepare_untranslated(struct db *db, const char *query) return stmt; } -bool db_query_prepared(struct db_stmt *stmt) +bool db_query_prepared_canfail(struct db_stmt *stmt) { /* Make sure we don't accidentally execute a modifying query using a * read-only path. */ @@ -147,6 +151,13 @@ bool db_query_prepared(struct db_stmt *stmt) return ret; } +void db_query_prepared(struct db_stmt *stmt) +{ + if (!db_query_prepared_canfail(stmt)) + db_fatal("query failed: %s: %s", + stmt->location, stmt->query->query); +} + bool db_step(struct db_stmt *stmt) { bool ret; @@ -164,7 +175,7 @@ bool db_step(struct db_stmt *stmt) return ret; } -bool db_exec_prepared_v2(struct db_stmt *stmt TAKES) +void db_exec_prepared_v2(struct db_stmt *stmt TAKES) { bool ret = stmt->db->config->exec_fn(stmt); @@ -184,8 +195,6 @@ bool db_exec_prepared_v2(struct db_stmt *stmt TAKES) if (taken(stmt)) tal_free(stmt); - - return ret; } size_t db_count_changes(struct db_stmt *stmt) diff --git a/db/utils.h b/db/utils.h index e0c1f97f337d..8793d5c09953 100644 --- a/db/utils.h +++ b/db/utils.h @@ -34,7 +34,7 @@ bool db_step(struct db_stmt *stmt); * * @stmt: The prepared statement to execute */ -bool db_exec_prepared_v2(struct db_stmt *stmt TAKES); +void db_exec_prepared_v2(struct db_stmt *stmt TAKES); /** * db_query_prepared -- Execute a prepared query @@ -49,7 +49,12 @@ bool db_exec_prepared_v2(struct db_stmt *stmt TAKES); * * @stmt: The prepared statement to execute */ -bool db_query_prepared(struct db_stmt *stmt); +void db_query_prepared(struct db_stmt *stmt); + +/** + * Variation which allows failure. + */ +bool db_query_prepared_canfail(struct db_stmt *stmt); size_t db_count_changes(struct db_stmt *stmt); void db_report_changes(struct db *db, const char *final, size_t min); diff --git a/devtools/Makefile b/devtools/Makefile index 0d5e3cf9a90c..50150ab6cfa2 100644 --- a/devtools/Makefile +++ b/devtools/Makefile @@ -24,7 +24,6 @@ DEVTOOLS_COMMON_OBJS := \ common/bolt11.o \ common/blockheight_states.o \ common/channel_id.o \ - common/configdir.o \ common/decode_array.o \ common/features.o \ common/fee_states.o \ @@ -43,8 +42,8 @@ DEVTOOLS_COMMON_OBJS := \ common/utils.o \ common/version.o \ common/wireaddr.o \ - wire/onion$(EXP)_wiregen.o \ - wire/peer$(EXP)_wiregen.o \ + wire/onion_wiregen.o \ + wire/peer_wiregen.o \ wire/channel_type_wiregen.o \ wire/tlvstream.o @@ -58,7 +57,7 @@ devtools/bolt11-cli: $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(BITCOIN_OBJS) wire/f devtools/encodeaddr: common/utils.o common/bech32.o devtools/encodeaddr.o -devtools/bolt12-cli: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) wire/bolt12$(EXP)_wiregen.o wire/fromwire.o wire/towire.o common/bolt12.o common/bolt12_merkle.o devtools/bolt12-cli.o common/setup.o common/iso4217.o +devtools/bolt12-cli: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) wire/bolt12_wiregen.o wire/fromwire.o wire/towire.o common/bolt12.o common/bolt12_merkle.o devtools/bolt12-cli.o common/setup.o common/iso4217.o devtools/decodemsg: $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(BITCOIN_OBJS) $(WIRE_PRINT_OBJS) wire/fromwire.o wire/towire.o devtools/print_wire.o devtools/decodemsg.o @@ -73,7 +72,7 @@ devtools/onion.c: ccan/config.h devtools/onion: $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(BITCOIN_OBJS) common/onion_decode.o common/onion_encode.o common/onionreply.o wire/fromwire.o wire/towire.o devtools/onion.o common/sphinx.o -devtools/gossipwith: $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o wire/peer$(EXP)_wiregen.o devtools/gossipwith.o common/cryptomsg.o common/cryptomsg.o +devtools/gossipwith: $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o wire/peer_wiregen.o devtools/gossipwith.o common/cryptomsg.o common/cryptomsg.o $(DEVTOOLS_OBJS) $(DEVTOOLS_TOOL_OBJS): wire/wire.h @@ -87,7 +86,7 @@ devtools/mkgossip: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/ devtools/mkencoded: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o devtools/mkencoded.o -devtools/checkchannels: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) common/configdir.o wire/fromwire.o wire/towire.o devtools/checkchannels.o +devtools/checkchannels: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o devtools/checkchannels.o common/configdir.o common/configvar.o devtools/mkquery: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o devtools/mkquery.o diff --git a/devtools/blockreplace.py b/devtools/blockreplace.py index 72d92bcd0fb9..fe4d7a5de5af 100644 --- a/devtools/blockreplace.py +++ b/devtools/blockreplace.py @@ -17,6 +17,7 @@ class Language(str, Enum): md = 'md' rst = 'rst' c = 'c' + yml = 'yml' comment_style = { @@ -32,6 +33,10 @@ class Language(str, Enum): "/* block_start {blockname} */", "/* block_end {blockname} */", ), + Language.yml: ( + "# block_start {blockname}", + "# block_end {blockname}", + ), } diff --git a/devtools/bolt12-cli.c b/devtools/bolt12-cli.c index 9d815cff8f49..610a6ec18bf3 100644 --- a/devtools/bolt12-cli.c +++ b/devtools/bolt12-cli.c @@ -414,6 +414,8 @@ static bool print_extra_fields(const struct tlv_field *fields) return ok; } +bool deprecated_apis = true; + int main(int argc, char *argv[]) { const tal_t *ctx = tal(NULL, char); @@ -424,7 +426,6 @@ int main(int argc, char *argv[]) bool to_hex = false; common_setup(argv[0]); - deprecated_apis = true; opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn); opt_register_noarg("--help|-h", opt_usage_and_exit, diff --git a/devtools/checkchannels.c b/devtools/checkchannels.c index 85d4184dd364..538912938fee 100644 --- a/devtools/checkchannels.c +++ b/devtools/checkchannels.c @@ -109,7 +109,7 @@ static void copy_column(void *dst, size_t size, int main(int argc, char *argv[]) { - char *config_dir, *net_dir, *config_filename, *rpc_filename, *hsmfile, *dbfile; + char *net_dir, *rpc_filename, *hsmfile, *dbfile; sqlite3 *sql; sqlite3_stmt *stmt; int flags = SQLITE_OPEN_READONLY, dberr; @@ -124,14 +124,13 @@ int main(int argc, char *argv[]) setup_option_allocators(); - initial_config_opts(top_ctx, argc, argv, - &config_filename, &config_dir, &net_dir, - &rpc_filename); + minimal_config_opts(top_ctx, argc, argv, &net_dir, &rpc_filename); opt_register_noarg("-v|--verbose", opt_set_bool, &verbose, "Print everything"); opt_parse(&argc, argv, opt_log_stderr_exit); + if (argc != 1) errx(1, "no arguments accepted"); diff --git a/devtools/decodemsg.c b/devtools/decodemsg.c index fdead6bf9e92..2a5d05c7efe9 100644 --- a/devtools/decodemsg.c +++ b/devtools/decodemsg.c @@ -2,14 +2,10 @@ #include #include #include +#include #include -#if EXPERIMENTAL_FEATURES - #include - #include -#else - #include - #include -#endif +#include +#include static char *opt_set_tlvname(const char *arg, bool (**printwire)(const char *fieldname, @@ -55,6 +51,7 @@ int main(int argc, char *argv[]) bool (*printwire)(const u8 *msg) = printpeer_wire_message; bool ok = true; + common_setup(argv[0]); setup_locale(); opt_register_noarg("--onion", opt_set_onionprint, &printwire, diff --git a/devtools/dump-gossipstore.c b/devtools/dump-gossipstore.c index af0da532c067..1f0df55a0720 100644 --- a/devtools/dump-gossipstore.c +++ b/devtools/dump-gossipstore.c @@ -74,7 +74,7 @@ int main(int argc, char *argv[]) deleted = (flags & GOSSIP_STORE_DELETED_BIT); push = (flags & GOSSIP_STORE_PUSH_BIT); ratelimit = (flags & GOSSIP_STORE_RATELIMIT_BIT); - zombie = (msglen & GOSSIP_STORE_ZOMBIE_BIT); + zombie = (flags & GOSSIP_STORE_ZOMBIE_BIT); msg = tal_arr(NULL, u8, msglen); if (read(fd, msg, msglen) != msglen) diff --git a/devtools/gossipwith.c b/devtools/gossipwith.c index 365fb4f04646..21dec7c231e9 100644 --- a/devtools/gossipwith.c +++ b/devtools/gossipwith.c @@ -82,9 +82,10 @@ static char *opt_set_network(const char *arg, void *unused) return NULL; } -static void opt_show_network(char buf[OPT_SHOW_LEN], const void *unused) +static bool opt_show_network(char *buf, size_t len, const void *unused) { - snprintf(buf, OPT_SHOW_LEN, "%s", chainparams->network_name); + snprintf(buf, len, "%s", chainparams->network_name); + return true; } void ecdh(const struct pubkey *point, struct secret *ss) @@ -168,6 +169,7 @@ static struct io_plan *handshake_success(struct io_conn *conn, const struct wireaddr_internal *addr, struct crypto_state *cs, struct oneshot *timer, + enum is_websocket is_websocket, char **args) { int peer_fd = io_conn_fd(conn); @@ -254,9 +256,9 @@ static char *opt_set_secret(const char *arg, struct secret *s) return NULL; } -static void opt_show_secret(char buf[OPT_SHOW_LEN], const struct secret *s) +static bool opt_show_secret(char *buf, size_t len, const struct secret *s) { - hex_encode(s->data, sizeof(s->data), buf, OPT_SHOW_LEN); + return hex_encode(s->data, sizeof(s->data), buf, len); } static char *opt_set_features(const char *arg, u8 **features) @@ -325,8 +327,8 @@ int main(int argc, char *argv[]) opt_usage_exit_fail("Invalid id %.*s", (int)(at - argv[1]), argv[1]); - if (!parse_wireaddr_internal(at+1, &addr, chainparams_get_ln_port(chainparams), NULL, - true, false, &err_msg)) + err_msg = parse_wireaddr_internal(tmpctx, at+1, chainparams_get_ln_port(chainparams), true, &addr); + if (err_msg) opt_usage_exit_fail("%s '%s'", err_msg, argv[1]); switch (addr.itype) { @@ -341,14 +343,14 @@ int main(int argc, char *argv[]) opt_usage_exit_fail("Don't support proxy use"); case ADDR_INTERNAL_WIREADDR: - switch (addr.u.wireaddr.type) { + if (addr.u.wireaddr.is_websocket) + opt_usage_exit_fail("Don't support websocket use"); + + switch (addr.u.wireaddr.wireaddr.type) { case ADDR_TYPE_TOR_V2_REMOVED: case ADDR_TYPE_TOR_V3: opt_usage_exit_fail("Don't support proxy use"); break; - case ADDR_TYPE_WEBSOCKET: - opt_usage_exit_fail("Don't support websockets"); - break; case ADDR_TYPE_DNS: opt_usage_exit_fail("Don't support DNS"); break; @@ -359,7 +361,7 @@ int main(int argc, char *argv[]) af = AF_INET6; break; } - ai = wireaddr_to_addrinfo(tmpctx, &addr.u.wireaddr); + ai = wireaddr_to_addrinfo(tmpctx, &addr.u.wireaddr.wireaddr); } if (af == -1 || ai == NULL) @@ -375,7 +377,7 @@ int main(int argc, char *argv[]) if (connect(conn->fd, ai->ai_addr, ai->ai_addrlen) != 0) err(1, "Connecting to %s", at+1); - initiator_handshake(conn, &us, &them, &addr, NULL, + initiator_handshake(conn, &us, &them, &addr, NULL, NORMAL_SOCKET, handshake_success, argv+2); exit(0); } diff --git a/devtools/onion.c b/devtools/onion.c index b08a6f25bd94..4f3e65147dae 100644 --- a/devtools/onion.c +++ b/devtools/onion.c @@ -175,9 +175,9 @@ static char *opt_set_ad(const char *arg, u8 **assocdata) return NULL; } -static void opt_show_ad(char buf[OPT_SHOW_LEN], u8 *const *assocdata) +static bool opt_show_ad(char *buf, size_t len, u8 *const *assocdata) { - hex_encode(*assocdata, tal_bytelen(*assocdata), buf, OPT_SHOW_LEN); + return hex_encode(*assocdata, tal_bytelen(*assocdata), buf, len); } static char *opt_set_node_id(const char *arg, struct node_id *node_id) diff --git a/devtools/route.c b/devtools/route.c index ebf809301a72..30a87a26796a 100644 --- a/devtools/route.c +++ b/devtools/route.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,8 @@ int main(int argc, char *argv[]) bool clean_topology = false; size_t num_channel_updates_rejected; + common_setup(argv[0]); + opt_register_noarg("--clean-topology", opt_set_bool, &clean_topology, "Clean up topology before run"); opt_register_noarg("-h|--help", opt_usage_and_exit, diff --git a/doc/BACKUP.md b/doc/BACKUP.md index 55f1c2a45ae1..a607b141698e 100644 --- a/doc/BACKUP.md +++ b/doc/BACKUP.md @@ -30,7 +30,9 @@ For example, if you are running `--mainnet`, it will be ## `hsm_secret` -`/!\` WHO SHOULD DO THIS: Everyone. +!!! note + + WHO SHOULD DO THIS: Everyone. You need a copy of the `hsm_secret` file regardless of whatever backup strategy you use. @@ -84,12 +86,14 @@ backup strategies below. ## SQLITE3 `--wallet=${main}:${backup}` And Remote NFS Mount -`/!\` WHO SHOULD DO THIS: Casual users. +!!! note + + WHO SHOULD DO THIS: Casual users. + +!!! warning -`/!\` **CAUTION** `/!\` This technique is only supported after the version v0.10.2 (not included) -or later. -On earlier versions, the `:` character is not special and will be -considered part of the path of the database file. + This technique is only supported after the version v0.10.2 (not included) or later. + On earlier versions, the `:` character is not special and will be considered part of the path of the database file. When using the SQLITE3 backend (the default), you can specify a second database file to replicate to, by separating the second @@ -100,11 +104,15 @@ For example, if the user running `lightningd` is named `user`, and you are on the Bitcoin mainnet with the default `${LIGHTNINGDIR}`, you can specify in your `config` file: - wallet=sqlite3:///home/user/.lightning/bitcoin/lightningd.sqlite3:/my/backup/lightningd.sqlite3 +```bash +wallet=sqlite3:///home/user/.lightning/bitcoin/lightningd.sqlite3:/my/backup/lightningd.sqlite3 +``` Or via command line: - lightningd --wallet=sqlite3:///home/user/.lightning/bitcoin/lightningd.sqlite3:/my/backup/lightningd.sqlite3 +```bash +lightningd --wallet=sqlite3:///home/user/.lightning/bitcoin/lightningd.sqlite3:/my/backup/lightningd.sqlite3 +``` If the second database file does not exist but the directory that would contain it does exist, the file is created. @@ -173,7 +181,9 @@ like fire or computer confiscation. ## `backup` Plugin And Remote NFS Mount -`/!\` WHO SHOULD DO THIS: Casual users. +!!! note + + WHO SHOULD DO THIS: Casual users. You can find the full source for the `backup` plugin here: https://github.com/lightningd/plugins/tree/master/backup @@ -221,8 +231,9 @@ like fire or computer confiscation. ## Filesystem Redundancy -`/!\` WHO SHOULD DO THIS: Filesystem nerds, data hoarders, home labs, -enterprise users. +!!! note + + WHO SHOULD DO THIS: Filesystem nerds, data hoarders, home labs, enterprise users. You can set up a RAID-1 with multiple storage devices, and point the `$LIGHTNINGDIR` to the RAID-1 setup. @@ -336,7 +347,9 @@ of new storage devices to set up a new node. ## PostgreSQL Cluster -`/!\` WHO SHOULD DO THIS: Enterprise users, whales. +!!! note + + WHO SHOULD DO THIS: Enterprise users, whales. `lightningd` may also be compiled with PostgreSQL support. PostgreSQL is generally faster than SQLITE3, and also supports running a @@ -420,10 +433,75 @@ This can be difficult to create remote replicas due to the latency. [pqsyncreplication]: https://www.postgresql.org/docs/13/warm-standby.html#SYNCHRONOUS-REPLICATION +## SQLite Litestream Replication + +!!! warning + + Previous versions of this document recommended this technique, but we no longer do so. + According to [issue 4857][], even with a 60-second timeout that we added + in 0.10.2, this leads to constant crashing of `lightningd` in some + situations. + This section will be removed completely six months after 0.10.3. + Consider using + + ``` + --wallet=sqlite3://${main}:${backup} + ``` + + above, instead. + +[issue 4857]: https://github.com/ElementsProject/lightning/issues/4857 + +One of the simpler things on any system is to use Litestream to replicate the SQLite database. +It continuously streams SQLite changes to file or external storage - the cloud storage option +should not be used. +Backups/replication should not be on the same disk as the original SQLite DB. + +You need to enable WAL mode on your database. +To do so, first stop `lightningd`, then: + + $ sqlite3 lightningd.sqlite3 + sqlite3> PRAGMA journal_mode = WAL; + sqlite3> .quit + +Then just restart `lightningd`. + +/etc/litestream.yml : + + dbs: + - path: /home/bitcoin/.lightning/bitcoin/lightningd.sqlite3 + replicas: + - path: /media/storage/lightning_backup + + and start the service using systemctl: + + $ sudo systemctl start litestream + +Restore: + + $ litestream restore -o /media/storage/lightning_backup /home/bitcoin/restore_lightningd.sqlite3 + +Because Litestream only copies small changes and not the entire +database (holding a read lock on the file while doing so), the +60-second timeout on locking should not be reached unless +something has made your backup medium very very slow. + +Litestream has its own timer, so there is a tiny (but +non-negligible) probability that `lightningd` updates the +database, then irrevocably commits to the update by sending +revocation keys to the counterparty, and *then* your main +storage media crashes before Litestream can replicate the +update. +Treat this as a superior version of "Database File Backups" +section below and prefer recovering via other backup methods +first. + ## Database File Backups -`/!\` WHO SHOULD DO THIS: Those who already have at least one of the -other backup methods, those who are #reckless. +!!! note + + WHO SHOULD DO THIS: Those who already have at least one of the + other backup methods, those who are #reckless. This is the least desirable backup strategy, as it *can* lead to loss of all in-channel funds if you use it. @@ -528,3 +606,38 @@ still not assured with this backup strategy. `sqlite3` has `.dump` and `VACUUM INTO` commands, but note that those lock the main database for long time periods, which will negatively affect your `lightningd` instance. + +### `sqlite3` `.dump` or `VACUUM INTO` Commands + +!!! warning + + Previous versions of this document recommended + this technique, but we no longer do so. + According to [issue 4857][issue 4857], even with a 60-second timeout that we added + in 0.10.2, this may lead to constant crashing of `lightningd` in some + situations; this technique uses substantially the same techniques as + `litestream`. + This section will be removed completely six months after 0.10.3. + Consider using `--wallet=sqlite3://${main}:${backup}` above, instead. + +Use the `sqlite3` command on the `lightningd.sqlite3` file, and +feed it with `.dump "/path/to/backup.sqlite3"` or `VACUUM INTO +"/path/to/backup.sqlite3";`. + +These create a snapshot copy that, unlike the previous technique, +is assuredly uncorrupted (barring any corruption caused by your +backup media). + +However, if the copying process takes a long time (approaching the +timeout of 60 seconds) then you run the risk of `lightningd` +attempting to grab a write lock, waiting up to 60 seconds, and +then failing with a "database is locked" error. +Your backup system could `.dump` to a fast `tmpfs` RAMDISK or +local media, and *then* copy to the final backup media on a remote +system accessed via slow network, for example, to reduce this +risk. + +It is recommended that you use `.dump` instead of `VACUUM INTO`, +as that is assuredly faster; you can just open the backup copy +in a new `sqlite3` session and `VACUUM;` to reduce the size +of the backup. diff --git a/doc/FAQ.md b/doc/FAQ.md index 12c70e52ef11..b56e4b8b6c99 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -1,10 +1,4 @@ -# FAQ - -## Table of contents -- [General questions](#general-questions) -- [Loss of {funds / data}](#loss) - - +# Frequently Asked Questions (FAQ) ## General questions ### I don't know where to start, help me ! diff --git a/doc/FUZZING.md b/doc/FUZZING.md index 1be23dfcd4ed..6805be820d8e 100644 --- a/doc/FUZZING.md +++ b/doc/FUZZING.md @@ -24,10 +24,17 @@ a few sanitizers for bug detections as well as experimental features for an exte coverage (not required though). ``` -DEVELOPER=1 EXPERIMENTAL_FEATURES=1 ASAN=1 UBSAN=1 VALGRIND=0 FUZZING=1 CC=clang ./configure && make +./configure --enable-developer --enable-address-sanitizer --enable-ub-sanitizer --enable-fuzzing --disable-valgrind CC=clang && make ``` -The targets will be built in `tests/fuzz/` as `fuzz-` binaries. +The targets will be built in `tests/fuzz/` as `fuzz-` binaries, with their best +known seed corpora stored in `tests/fuzz/corpora/`. + +You can run the fuzz targets on their seed corpora to check for regressions: + +``` +make check-fuzz +``` ## Run one or more target(s) @@ -53,7 +60,43 @@ The latter will run all targets two by two `12345` times. If you want to contribute new seeds, be sure to merge your corpus with the main one: ``` ./tests/fuzz/run.py my_locally_extended_fuzz_corpus -j2 --generate --runs 12345 -./tests/fuzz/run.py main_fuzz_corpus --merge_dir my_locally_extended_fuzz_corpus +./tests/fuzz/run.py tests/fuzz/corpora --merge_dir my_locally_extended_fuzz_corpus +``` + + +## Improve seed corpora + +If you find coverage increasing inputs while fuzzing, please create a pull +request to add them into `tests/fuzz/corpora`. Be sure to minimize any additions +to the corpora first. + +### Example + +Here's an example workflow to contribute new inputs for the `fuzz-addr` target. + +Create a directory for newly found corpus inputs and begin fuzzing: + +```shell +mkdir -p local_corpora/fuzz-addr +./tests/fuzz/fuzz-addr -jobs=4 local_corpora/fuzz-addr tests/fuzz/corpora/fuzz-addr/ +``` + +After some time, libFuzzer may find some potential coverage increasing inputs +and save them in `local_corpora/fuzz-addr`. We can then merge them into the seed +corpora in `tests/fuzz/corpora`: + +```shell +./tests/fuzz/run.py tests/fuzz/corpora --merge_dir local_corpora +``` + +This will copy over any inputs that improve the coverage of the existing corpus. +If any new inputs were added, create a pull request to improve the upstream seed +corpus: + +```shell +git add tests/fuzz/corpora/fuzz-addr/* +git commit +... ``` @@ -65,7 +108,8 @@ In order to write a new target: repeatedly with mutated data. - read about [what makes a good fuzz target](https://github.com/google/fuzzing/blob/master/docs/good-fuzz-target.md). -A simple example is [`fuzz-addr`][tests/fuzz/fuzz-addr.c]. It setups the chainparams and -context (wally, tmpctx, ..) in `init()` then bruteforces the bech32 encoder in `run()`. +A simple example is [`fuzz-addr`][fuzz-addr]. It setups the +chainparams and context (wally, tmpctx, ..) in `init()` then +bruteforces the bech32 encoder in `run()`. -[tests/fuzz/fuzz-addr.c]: https://github.com/ElementsProject/lightning/blob/master/tests/fuzz/fuzz-addr.c +[fuzz-addr]: https://github.com/ElementsProject/lightning/blob/master/tests/fuzz/fuzz-addr.c diff --git a/doc/INSTALL.md b/doc/INSTALL.md index 5a306ae8fc5c..906c47db5d71 100644 --- a/doc/INSTALL.md +++ b/doc/INSTALL.md @@ -20,7 +20,6 @@ Library Requirements You will need several development libraries: * libsqlite3: for database support. -* libgmp: for secp256k1 * zlib: for compression routines. For actually doing development and running the tests, you will also need: @@ -38,7 +37,7 @@ Get dependencies: sudo apt-get update sudo apt-get install -y \ - autoconf automake build-essential git libtool libgmp-dev libsqlite3-dev \ + autoconf automake build-essential git libtool libsqlite3-dev \ python3 python3-pip net-tools zlib1g-dev libsodium-dev gettext pip3 install --upgrade pip pip3 install --user poetry @@ -119,7 +118,6 @@ $ sudo dnf update -y && \ clang \ gettext \ git \ - gmp-devel \ libsq3-devel \ python3-devel \ python3-pip \ @@ -204,7 +202,7 @@ OS version: OpenBSD 6.7 Install dependencies: ``` -pkg_add git python gmake py3-pip libtool gmp +pkg_add git python gmake py3-pip libtool pkg_add automake # (select highest version, automake1.16.2 at time of writing) pkg_add autoconf # (select highest version, autoconf-2.69p2 at time of writing) ``` @@ -236,7 +234,7 @@ To Build on NixOS Use nix-shell launch a shell with a full clightning dev environment: ``` -$ nix-shell -Q -p gdb sqlite autoconf git clang libtool gmp sqlite autoconf \ +$ nix-shell -Q -p gdb sqlite autoconf git clang libtool sqlite autoconf \ autogen automake libsodium 'python3.withPackages (p: [p.bitcoinlib])' \ valgrind --run make ``` @@ -246,7 +244,7 @@ To Build on macOS Assuming you have Xcode and Homebrew installed. Install dependencies: - $ brew install autoconf automake libtool python3 gmp gnu-sed gettext libsodium + $ brew install autoconf automake libtool python3 gnu-sed gettext libsodium protobuf $ ln -s /usr/local/Cellar/gettext/0.20.1/bin/xgettext /usr/local/opt $ export PATH="/usr/local/opt:$PATH" @@ -266,9 +264,9 @@ If you need Python 3.x for mako (or get a mako build error): $ brew install pyenv $ echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init -)"\nfi' >> ~/.bash_profile $ source ~/.bash_profile - $ pyenv install 3.7.4 - $ pip install --upgrade pip - $ pip install poetry + $ pyenv install 3.8.10 + $ pip3 install --upgrade pip + $ pip3 install poetry If you don't have bitcoind installed locally you'll need to install that as well: @@ -306,9 +304,9 @@ need to include `testnet=1` ./cli/lightning-cli help -To install the built binaries into your system, you'll need to run `make install`: +To install the built binaries into your system, you'll need to run `sudo make install`: - make install + sudo make install On an M1 mac you may need to use this command instead: @@ -407,7 +405,7 @@ Config the arm elf interpreter prefix: export QEMU_LD_PREFIX=/path/to/raspberry/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/arm-linux-gnueabihf/sysroot/ -Obtain and install cross-compiled versions of sqlite3, gmp and zlib: +Obtain and install cross-compiled versions of sqlite3 and zlib: Download and build zlib: @@ -427,15 +425,6 @@ Download and build sqlite3: make make install -Download and build gmp: - - wget https://gmplib.org/download/gmp/gmp-6.1.2.tar.xz - tar xvf gmp-6.1.2.tar.xz - cd gmp-6.1.2 - ./configure --disable-assembly --host=$target_host --prefix=$QEMU_LD_PREFIX - make - make install - Then, build Core Lightning with the following commands: ./configure @@ -456,7 +445,7 @@ Get dependencies: ``` apk update apk add --virtual .build-deps ca-certificates alpine-sdk autoconf automake git libtool \ - gmp-dev sqlite-dev python3 py3-mako net-tools zlib-dev libsodium gettext + sqlite-dev python3 py3-mako net-tools zlib-dev libsodium gettext ``` Clone lightning: ``` @@ -477,7 +466,7 @@ apk del .build-deps ``` Install runtime dependencies: ``` -apk add gmp libgcc libsodium sqlite-libs zlib +apk add libgcc libsodium sqlite-libs zlib ``` Additional steps diff --git a/doc/LICENSE.md b/doc/LICENSE.md new file mode 120000 index 000000000000..ea5b60640b01 --- /dev/null +++ b/doc/LICENSE.md @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/doc/MAKING-RELEASES.md b/doc/MAKING-RELEASES.md index d9f4fe670dd4..6bba94d8bf54 100644 --- a/doc/MAKING-RELEASES.md +++ b/doc/MAKING-RELEASES.md @@ -14,8 +14,9 @@ Here's a checklist for the release process. 4. Create a milestone for the *next* release on Github, and go though open issues and PRs and mark accordingly. 5. Ask (via email) the most significant contributor who has not - already named a release to name the release (use devtools/credit to - find this contributor). CC previous namers and team. + already named a release to name the release (use + `devtools/credit --verbose v` to find this contributor). + CC previous namers and team. ### Preparing for -rc1 @@ -40,52 +41,75 @@ Here's a checklist for the release process. should get a prompt to give this tag a 'message'. Make sure you fill this in. 3. Confirm that the tag will show up for builds with `git describe` 4. Push the tag to remote `git push --tags`. -3. Update the /topic on #c-lightning on Libera. -4. Prepare draft release notes (see devtools/credit), and share with team for editing. -5. Upgrade your personal nodes to the rc1, to help testing. -6. Test `tools/build-release.sh` to build the non-reprodicible images - and reproducible zipfile. -7. Use the zipfile to produce a [reproducible build](REPRODUCIBLE.md). +5. Announce rc1 release on core-lightning's release-chat channel on Discord + & [BuildOnL2](https://community.corelightning.org/c/general-questions/). +6. Use `devtools/credit --verbose v` to get commits, days + and contributors data for release note. +7. Prepare draft release notes including information from above step, and share + with the team for editing. +8. Upgrade your personal nodes to the rc1, to help testing. +9. Follow [reproducible build](REPRODUCIBLE.md) for [Builder image setup](https://lightning.readthedocs.io/REPRODUCIBLE.html#builder-image-setup). It will create builder images `cl-repro-` which are required for the next step. +10. Run `tools/build-release.sh bin-Fedora-28-amd64 bin-Ubuntu sign` script to prepare required builds for the release. With `bin-Fedora-28-amd64 bin-Ubuntu sign`, it will build a zipfile, a non-reproducible Fedora, reproducible Ubuntu images. Once it is done, the script will sign the release contents and create SHA256SUMS and SHA256SUMS.asc in the release folder. +10. RC images are not uploaded on Docker. Hence they can be removed from the target list for RC versions. Each docker image takes approx. 90 minutes to bundle but it is highly recommended to test docker setup once, if you haven't done that before. Prior to building docker images, ensure that `multiarch/qemu-user-static` setup is working on your system as described [here](https://lightning.readthedocs.io/REPRODUCIBLE.html#setting-up-multiarch-qemu-user-static). -### Releasing -rc2, etc +### Releasing -rc2, ..., -rcN -1. Change rc1 to rc2 in CHANGELOG.md. -2. Add a PR with the rc2. -3. Tag it `git pull && git tag -s vrc2 && git push --tags` -4. Update the /topic on #c-lightning on Libera. -5. Upgrade your personal nodes to the rc2. +1. Change rc(N-1) to rcN in CHANGELOG.md. +2. Update the contrib/pyln package versions: `make update-pyln-versions NEW_VERSION=` +3. Add a PR with the rcN. +4. Tag it `git pull && git tag -s vrcN && git push --tags` +5. Announce tagged rc release on core-lightning's release-chat channel on Discord + & [BuildOnL2](https://community.corelightning.org/c/general-questions/). +6. Upgrade your personal nodes to the rcN. ### Tagging the Release 1. Update the CHANGELOG.md; remove -rcN in both places, update the date and add title and namer. -2. Add a PR with that release. -3. Merge the PR, then: - - `export VERSION=0.9.3` +2. Update the contrib/pyln package versions: `make update-pyln-versions NEW_VERSION=` +3. Add a PR with that release. +4. Merge the PR, then: + - `export VERSION=23.05` - `git pull` - `git tag -a -s v${VERSION} -m v${VERSION}` - `git push --tags` -4. Run `tools/build-release.sh` to build the non-reprodicible images - and reproducible zipfile. -5. Use the zipfile to produce a [reproducible build](REPRODUCIBLE.md). -6. Create the checksums for signing: `sha256sum release/* > release/SHA256SUMS` -7. Create the first signature with `gpg -sb --armor release/SHA256SUMS` -8. Upload the files resulting files to github and - save as a draft. - (https://github.com/ElementsProject/lightning/releases/) -9. Ping the rest of the team to check the SHA256SUMS file and have them send their - `gpg -sb --armor SHA256SUMS`. -10. Append the signatures into a file called `SHA256SUMS.asc`, verify - with `gpg --verify SHA256SUMS.asc` and include the file in the draft - release. -11.`make pyln-release` to upload pyln modules to pypi.org. +5. Run `tools/build-release.sh` to: + - Create reproducible zipfile + - Build non-reproducible Fedora image + - Build reproducible Ubuntu-v18.04, Ubuntu-v20.04, Ubuntu-v22.04 images. Follow [link](https://lightning.readthedocs.io/REPRODUCIBLE.html#building-using-the-builder-image) for manually Building Ubuntu Images. + - Build Docker images for amd64 and arm64v8 + - Create and sign checksums. Follow [link](https://lightning.readthedocs.io/REPRODUCIBLE.html#co-signing-the-release-manifest) for manually signing the release. +6. The tarballs may be owned by root, so revert ownership if necessary: + `sudo chown ${USER}:${USER} *${VERSION}*` +7. Upload the resulting files to github and save as a draft. + (https://github.com/ElementsProject/lightning/releases/) +8. Send `SHA256SUMS` & `SHA256SUMS.asc` files to the rest of the team to check and sign the release. +9. Team members can verify the release with the help of `build-release.sh`: + 9.1 Rename release captain's `SHA256SUMS` to `SHA256SUMS-v${VERSION}` and `SHA256SUMS.asc` to `SHA256SUMS-v${VERSION}.asc`. + 9.2 Copy them in the root folder (`lightning`). + 9.3 Run `tools/build-release.sh --verify`. It will create reproducible images, verify checksums and sign. + 9.4 Send your signatures from `release/SHA256SUMS.new` to release captain. + 9.5 Or follow [link](https://lightning.readthedocs.io/REPRODUCIBLE.html#verifying-a-reproducible-build) for manual verification instructions. +10. Append signatures shared by the team into the `SHA256SUMS.asc` file, verify + with `gpg --verify SHA256SUMS.asc` and include the file in the draft release. +11. `make pyln-release` to upload pyln modules to pypi.org. This requires keys + for each of pyln-client, pyln-proto, and pyln-testing accessible to poetry. + This can be done by configuring the python keyring library along with a + suitable backend. Alternatively, the key can be set as an environment + variable and each of the pyln releases can be built and published + independently: + - `export POETRY_PYPI_TOKEN_PYPI=` + - `make pyln-release-client` + - ... repeat for each pyln package. ### Performing the Release 1. Edit the GitHub draft and include the `SHA256SUMS.asc` file. 2. Publish the release as not a draft. -3. Update the /topic on #c-lightning on Libera. +3. Announce the final release on core-lightning's release-chat channel on Discord + & [BuildOnL2](https://community.corelightning.org/c/general-questions/). 4. Send a mail to c-lightning and lightning-dev mailing lists, using the same wording as the Release Notes in github. +5. Write release blog, post it on [Blockstream](https://blog.blockstream.com/) and announce the release on Twitter. ### Post-release diff --git a/doc/Makefile b/doc/Makefile index 1562ca9c559c..84bb63c3b3cc 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -23,6 +23,8 @@ MANPAGES := doc/lightning-cli.1 \ doc/lightning-close.7 \ doc/lightning-connect.7 \ doc/lightning-commando.7 \ + doc/lightning-commando-blacklist.7 \ + doc/lightning-commando-listrunes.7 \ doc/lightning-commando-rune.7 \ doc/lightning-createonion.7 \ doc/lightning-createinvoice.7 \ @@ -34,6 +36,7 @@ MANPAGES := doc/lightning-cli.1 \ doc/lightning-delforward.7 \ doc/lightning-delinvoice.7 \ doc/lightning-delpay.7 \ + doc/lightning-disableinvoicerequest.7 \ doc/lightning-disableoffer.7 \ doc/lightning-disconnect.7 \ doc/lightning-emergencyrecover.7 \ @@ -48,19 +51,21 @@ MANPAGES := doc/lightning-cli.1 \ doc/lightning-getroute.7 \ doc/lightning-hsmtool.8 \ doc/lightning-invoice.7 \ + doc/lightning-invoicerequest.7 \ doc/lightning-keysend.7 \ doc/lightning-listchannels.7 \ + doc/lightning-listclosedchannels.7 \ doc/lightning-listdatastore.7 \ doc/lightning-listforwards.7 \ doc/lightning-listfunds.7 \ doc/lightning-listhtlcs.7 \ doc/lightning-listinvoices.7 \ + doc/lightning-listinvoicerequests.7 \ doc/lightning-listoffers.7 \ doc/lightning-listpays.7 \ doc/lightning-listpeers.7 \ doc/lightning-listpeerchannels.7 \ doc/lightning-listsendpays.7 \ - doc/lightning-listsqlschemas.7 \ doc/lightning-makesecret.7 \ doc/lightning-multifundchannel.7 \ doc/lightning-multiwithdraw.7 \ @@ -84,9 +89,10 @@ MANPAGES := doc/lightning-cli.1 \ doc/lightning-sendonionmessage.7 \ doc/lightning-sendpay.7 \ doc/lightning-setchannel.7 \ + doc/lightning-setpsbtversion.7 \ doc/lightning-sendcustommsg.7 \ + doc/lightning-signinvoice.7 \ doc/lightning-signmessage.7 \ - doc/lightning-sql.7 \ doc/lightning-staticbackup.7 \ doc/lightning-txprepare.7 \ doc/lightning-txdiscard.7 \ @@ -110,6 +116,11 @@ MANPAGES := doc/lightning-cli.1 \ doc/lightning-getlog.7 \ doc/reckless.7 +ifeq ($(HAVE_SQLITE3),1) +MANPAGES += doc/lightning-listsqlschemas.7 \ + doc/lightning-sql.7 +endif + doc-all: $(MANPAGES) doc/index.rst SCHEMAS := $(wildcard doc/schemas/*.json) @@ -216,18 +227,19 @@ doc/index.rst: $(MANPAGES:=.md) python3 devtools/blockreplace.py doc/index.rst manpages --language=rst --indent " " \ ) -# For CI to (very roughly!) check that we only deprecated fields, or labelled added ones -# When running on GitHub (CI=true), we need to fetch origin/master +# Overridden by GH CI if necessary. +BASE_REF=master schema-added-check: - @if ! test -z $$CI; then git fetch origin master; fi; \ - if git diff origin/master -- doc/schemas | grep -q '^+.*{' && ! git diff origin/master -- doc/schemas | grep -q '^+.*"added"'; then \ - git diff origin/master -- doc/schemas; \ + if git show --format=%B -s $(BASE_REF).. | grep -q '^No-schema-diff-check'; then echo $@ suppressed; exit 0; fi; \ + if git diff $(BASE_REF) -- doc/schemas | grep -q '^+.*{' && ! git diff $(BASE_REF) -- doc/schemas | grep -q '^+.*"added"'; then \ + git diff $(BASE_REF) -- doc/schemas; \ echo 'New schema fields must have "added": "vNEXTVERSION"' >&2; exit 1; \ fi + schema-removed-check: - @if ! test -z $$CI; then git fetch origin master; fi; \ - if git diff origin/master -- doc/schemas | grep -q '^-.*{' && ! git diff origin/master -- doc/schemas | grep -q '^-.*"deprecated"'; then \ - git diff origin/master -- doc/schemas ; \ + if git show --format=%B -s $(BASE_REF).. | grep -q '^No-schema-diff-check'; then echo $@ suppressed; exit 0; fi; \ + if git diff $(BASE_REF) -- doc/schemas | grep -q '^-.*{' && ! git diff $(BASE_REF) -- doc/schemas | grep -q '^-.*"deprecated"' && ! git diff $(BASE_REF) -- doc/schemas | grep -q '^-.*EXPERIMENTAL_FEATURES'; then \ + git diff $(BASE_REF) -- doc/schemas ; \ echo 'Schema fields must be "deprecated", with version, not removed' >&2; exit 1; \ fi diff --git a/doc/PLUGINS.md b/doc/PLUGINS.md index b98576a3b198..c74072b8a706 100644 --- a/doc/PLUGINS.md +++ b/doc/PLUGINS.md @@ -207,11 +207,12 @@ There are currently four supported option 'types': - string: a string - bool: a boolean - int: parsed as a signed integer (64-bit) - - flag: no-arg flag option. Is boolean under the hood. Defaults to false. + - flag: no-arg flag option. Presented as `true` if config specifies it. In addition, string and int types can specify `"multi": true` to indicate they can be specified multiple times. These will always be represented in -`init` as a (possibly empty) JSON array. +`init` as a (possibly empty) JSON array. "multi" flag types do not make +sense. Nota bene: if a `flag` type option is not set, it will not appear in the options set that is passed to the plugin. @@ -229,7 +230,6 @@ Here's an example option set, as sent in response to `getmanifest` { "name": "run-hot", "type": "flag", - "default": None, // defaults to false "description": "If set, overclocks plugin" }, { @@ -1257,7 +1257,8 @@ the v2 protocol, and it has passed basic sanity checks: "channel_max_msat": 16777215000, "requested_lease_msat": 100000000, "lease_blockheight_start": 683990, - "node_blockheight": 683990 + "node_blockheight": 683990, + "require_confirmed_inputs": false } } ``` @@ -1389,6 +1390,7 @@ requests an RBF for a channel funding transaction. "channel_max_msat": 16777215000, "locktime": 2453, "requested_lease_msat": 100000000, + "require_confirmed_inputs": false } } ``` @@ -1714,7 +1716,8 @@ data. Each plugin must follow the below specification for `lightningd` to operat ### `getchaininfo` Called at startup, it's used to check the network `lightningd` is operating on and to -get the sync status of the backend. +get the sync status of the backend. Optionally, the plugins can use `last_height` to +make sure that the Bitcoin backend is not behind core lightning. The plugin must respond to `getchaininfo` with the following fields: - `chain` (string), the network name as introduced in bip70 @@ -1727,17 +1730,26 @@ The plugin must respond to `getchaininfo` with the following fields: Polled by `lightningd` to get the current feerate, all values must be passed in sat/kVB. -If fee estimation fails, the plugin must set all the fields to `null`. +The plugin must return `feerate_floor` (e.g. 1000 if mempool is +empty), and an array of 0 or more `feerates`. Each element of +`feerates` is an object with `blocks` and `feerate`, in +ascending-blocks order, for example: -The plugin, if fee estimation succeeds, must respond with the following fields: - - `opening` (number), used for funding and also misc transactions - - `mutual_close` (number), used for the mutual close transaction - - `unilateral_close` (number), used for unilateral close (/commitment) transactions - - `delayed_to_us` (number), used for resolving our output from our unilateral close - - `htlc_resolution` (number), used for resolving HTLCs after an unilateral close - - `penalty` (number), used for resolving revoked transactions - - `min_acceptable` (number), used as the minimum acceptable feerate - - `max_acceptable` (number), used as the maximum acceptable feerate +``` +{ + "feerate_floor": , + "feerates": { + { "blocks": 2, "feerate": }, + { "blocks": 6, "feerate": }, + { "blocks": 12, "feerate": } + { "blocks": 100, "feerate": } + } +} +``` + +lightningd will currently linearly interpolate to estimate between +given blocks (it will not extrapolate, but use the min/max blocks +values). ### `getrawblockbyheight` @@ -1792,3 +1804,6 @@ The plugin must broadcast it and respond with the following fields: [contrib/plugins]: https://github.com/ElementsProject/lightning/tree/master/contrib/plugins [tests]: https://github.com/ElementsProject/lightning/tree/master/tests [lightning-rpc.7.md]: lightningd-rpc.7.md +[example-plugin]: https://github.com/ElementsProject/lightning/blob/master/contrib/plugins/helloworld.py +[cln-tests]: https://github.com/ElementsProject/lightning/tree/master/tests +[cln-repo]: https://github.com/lightningd/plugins diff --git a/doc/REPRODUCIBLE.md b/doc/REPRODUCIBLE.md index 8bbbbaf5e703..f5e53a02e6bd 100644 --- a/doc/REPRODUCIBLE.md +++ b/doc/REPRODUCIBLE.md @@ -146,8 +146,13 @@ this point we have a container image that has been prepared to build reproducibly. As you can see from the `Dockerfile` above we assume the source git repository gets mounted as `/repo` in the docker container. The container will clone the repository to an internal path, in order to keep the repository -clean, build the artifacts there, and then copy them back to -`/repo/release`. We can simply execute the following command inside the git +clean, build the artifacts there, and then copy them back to `/repo/release`. +We'll need the release directory available for this, so create it now if it +doesn't exist: + +`mkdir release` + +Then we can simply execute the following command inside the git repository (remember to checkout the tag you are trying to build): ```bash @@ -169,6 +174,72 @@ Repeat this step for each distribution and each architecture you wish to sign. Once all the binaries are in the `release/` subdirectory we can sign the hashes: +# Setting up Docker's Buildx +Docker Buildx is an extension of Docker's build command, that provides a more efficient way to create images. It is part of Docker 19.03 and can also be manually installed as a CLI plugin for older versions. + +1: Enable Docker CLI experimental features +Docker CLI experimental features are required to use Buildx. Enable them by setting the DOCKER_CLI_EXPERIMENTAL environment variable to enabled. +You can do this by adding the following line to your shell profile file (.bashrc, .zshrc, etc.): +``` +export DOCKER_CLI_EXPERIMENTAL=enabled +``` +After adding it, source your shell profile file or restart your shell to apply the changes. + +2: Create a new builder instance +By default, Docker uses the "legacy" builder. You need to create a new builder instance that uses BuildKit. To create a new builder instance, use the following command: +``` +docker buildx create --use +``` +The --use flag sets the newly created builder as the current one. + +# Setting up multiarch/qemu-user-static +1: Check Buildx is working + +Use the `docker buildx inspect --bootstrap` command to verify that Buildx is working correctly. The `--bootstrap` option ensures the builder instance is running before inspecting it. The output should look something like this: +``` +Name: my_builder +Driver: docker-container +Last Activity: 2023-06-13 04:37:30 +0000 UTC + +Nodes: +Name: my_builder0 +Endpoint: unix:///var/run/docker.sock +Status: running +Buildkit: v0.11.6 +Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/386 +``` + +2:Install `binfmt-support` and `qemu-user-static` if not installed already. + +``` +sudo apt-get update +sudo apt-get install docker.io binfmt-support qemu-user-static +sudo systemctl restart docker +``` + +3: Setup QEMU to run binaries from multiple different architectures + +``` +docker run --rm --privileged multiarch/qemu-user-static --reset -p yes +``` + +4: Confirm QEMU is working + +Again run `docker buildx inspect --bootstrap` command to verify that `linux/arm64` is in the list of platforms. + +``` +Name: my_builder +Driver: docker-container +Last Activity: 2023-06-13 04:37:30 +0000 UTC + +Nodes: +Name: my_builder0 +Endpoint: unix:///var/run/docker.sock +Status: running +Buildkit: v0.11.6 +Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/386, linux/arm64, linux/riscv64, linux/ppc64, linux/ppc64le, linux/s390x, linux/mips64le, linux/mips64 +``` + # (Co-)Signing the release manifest The release captain is in charge of creating the manifest, whereas diff --git a/doc/STYLE.md b/doc/STYLE.md index 78422daf1aae..a75e82fb5154 100644 --- a/doc/STYLE.md +++ b/doc/STYLE.md @@ -236,7 +236,7 @@ have a line with one of the following prefixes: not yet removed - `Changelog-Fixed: ` if a bug has been fixed - `Changelog-Removed: ` if a (previously deprecated) feature has been removed - - `Changelog-Experimental: ` if it only affects --enable-experimental-features builds, or experimental- config options. + - `Changelog-Experimental: ` if it only affects experimental- config options. In case you think the pull request is small enough not to require a changelog entry please use `Changelog-None` in one of the commit messages to opt out. diff --git a/doc/dev/contributors/codegen.md b/doc/dev/contributors/codegen.md new file mode 100644 index 000000000000..3c05d4fd7f3c --- /dev/null +++ b/doc/dev/contributors/codegen.md @@ -0,0 +1,138 @@ +# Code Generation + +The CLN project has a multitude of interfaces, most of which are +generated from an abstract schema: + + - Wire format for peer-to-peer communication: this is the binary + format that is specific by the [LN spec][spec]. It uses the + [generate-wire.py][generate-wire.py] script to parse the (faux) CSV + files that are automatically extrated from the specification and + writes C source code files that are then used internally to encode + and decode messages, as well as provide print functions for the + messages. + + - Wire format for inter-daemon communication: CLN follows a + multi-daemon architecture, making communication explicit across + daemons. For this inter-daemon communication we use a slightly + altered message format from the [LN spec][spec]. The changes are 1) + addition of FD passing semantics to allow establishing a new + connection between daemons (communication uses + [socketpair][socketpair]s, so no `connect`), and 2) change the + message length prefix from `u16` to `u32`, allowing for messages + larger than 65Kb. The CSV files are with the respective sub-daemon + and also use [generate-wire.py][generate-wire.py] to generate + encoding, decoding and printing functions. + + - We describe the JSON-RPC using [JSON Schema][jschema] in the + [`doc/schemas`][doc-schemas] directory. Each method has a + `.request.json` for the request message, and a `.schema.json` for + the response (the mismatch is historical and will eventually be + addressed). During tests the `pytest` target will verify responses, + however the JSON-RPC methods are _not_ generated (yet?). We do + generate various client stubs for languages, using the + [`msggen`][msggen] tool. More on the generated stubs and utilities + below. + +## Man pages + +The [manpages][man] are partially generated from the JSON schemas +using the [`fromschema`][fromschema] tool. It reads the request schema +and fills in the manpage between two markers: + +```markdown +[comment]: # (GENERATE-FROM-SCHEMA-START) +... +[comment]: # (GENERATE-FROM-SCHEMA-END) +``` + +!!! note + + Some of this functionality overlaps with [`msggen`][msggen] (parsing the Schemas) + and [blockreplace.py][blockreplace.py] (filling in the template). It + is likely that this will eventually be merged. + +[blockreplace.py]: https://github.com/ElementsProject/lightning/blob/master/devtools/blockreplace.py +[man]: ../../reference/ +[fromschema]: https://github.com/ElementsProject/lightning/blob/master/tools/fromschema.py + +## `msggen` + +`msggen` is used to generate JSON-RPC client stubs, and converters +between in-memory formats and the JSON format. In addition, by +chaining some of these we can expose a [grpc][grpc] interface that +matches the JSON-RPC interface. This conversion chain is implemented +in the [grpc-plugin][grpc-plugin] + + +
+```mermaid +graph LR + A[JSON schema]; + A --> B[cln-rpc]; + B --> B1[Request Structs]; + B --> B2[Response Structs]; + B --> B3[Method stubs]; + + A --> C[cln-grpc]; + C --> C1[Protobuf File]; + C --> C2[In-memory conversion]; + C --> C3[Service Implementation]; +``` +
Artifacts generated from the JSON Schemas using `msggen`
+
+ +### `cln-rpc` + +We use `msggen` to generate the Rust bindings crate +[`cln-rpc`][cln-rpc]. These bindings contain the stubs for the +JSON-RPC methods, as well as types for the request and response +structs. The [generator code][cln-rpc-gen] maps each abstract JSON-RPC +type to a Rust type, minimizing size (e.g., binary data is +hex-decoded). + +The calling pattern follows the `call(req_obj) -> resp_obj` format, +and the individual arguments are not expanded. For more ergonomic +handling of generic requests and responses we also define the +`Request` and `Response` enumerations, so you can hand them to a +generic function without having to resort to dynamic dispatch. + +The remainder of the crate implements an async/await JSON-RPC client, +that can deal with the Unix Domain Socket [transport][man:json-rpc] +used by CLN. + +### `cln-grpc` + +The `cln-grpc` crate is mostly used to provide the primitives to build +the `grpc-plugin`. As mentioned above, the grpc functionality relies on a chain of generated parts: + + - First `msggen` is used to generate the [protobuf file][proto], + containing the service definition with the method stubs, and the types + referenced by those stubs. + - Next it generates the `convert.rs` file which is used to convert + the structs for in-memory representation from `cln-rpc` into the + corresponding protobuf structs. + - Finally `msggen` generates the `server.rs` file which can be bound + to a grpc endpoint listening for incoming grpc requests, and it + will convert the request and forward it to the JSON-RPC. Upon + receiving the response it gets converted back into a grpc response + and sent back. + +```mermaid +graph LR + A[grpc client] --> B[grpc server] -->|convert.rs| C[cln-rpc] --> D[lightningd]; + D --> C -->|convert.rs| B --> A; +``` + +[proto]: https://github.com/ElementsProject/lightning/blob/master/cln-grpc/proto/node.proto +[man:json-rpc]: ../../lightningd-rpc.7.md +[cln-rpc-gen]: https://github.com/ElementsProject/lightning/blob/master/contrib/msggen/msggen/gen/rust.py +[spec]: https://github.com/lightning/bolts +[generate-wire.py]: https://github.com/ElementsProject/lightning/blob/master/tools/generate-wire.py +[socketpair]: https://man7.org/linux/man-pages/man2/socketpair.2.html +[jschema]: https://json-schema.org/ +[doc-schemas]: https://github.com/ElementsProject/lightning/tree/master/doc/schemas +[msggen]: https://github.com/ElementsProject/lightning/tree/master/contrib/msggen +[grpc]: https://grpc.io/ +[cln-grpc]: https://docs.rs/cln-grpc/0.1.1/cln_grpc/ +[grpc-plugin]: https://github.com/ElementsProject/lightning/tree/master/plugins/grpc-plugin +[cln-rpc]: https://github.com/ElementsProject/lightning/tree/master/cln-rpc diff --git a/doc/dev/contributors/index.md b/doc/dev/contributors/index.md new file mode 100644 index 000000000000..4796167e6af9 --- /dev/null +++ b/doc/dev/contributors/index.md @@ -0,0 +1 @@ +# Developer Documentation diff --git a/doc/dev/index.md b/doc/dev/index.md new file mode 100644 index 000000000000..4796167e6af9 --- /dev/null +++ b/doc/dev/index.md @@ -0,0 +1 @@ +# Developer Documentation diff --git a/doc/guides/Beginner-s Guide/backup-and-recovery.md b/doc/guides/Beginner-s Guide/backup-and-recovery.md new file mode 100644 index 000000000000..a4ae4a384750 --- /dev/null +++ b/doc/guides/Beginner-s Guide/backup-and-recovery.md @@ -0,0 +1,438 @@ +--- +title: "Backup and recovery" +slug: "backup-and-recovery" +excerpt: "Learn the various backup and recovery options available for your Core Lightning node." +hidden: false +createdAt: "2022-11-18T16:28:17.292Z" +updatedAt: "2023-04-22T12:51:49.775Z" +--- +Lightning Network channels get their scalability and privacy benefits from the very simple technique of _not telling anyone else about your in-channel activity_. +This is in contrast to onchain payments, where you have to tell everyone about each and every payment and have it recorded on the blockchain, leading to scaling problems (you have to push data to everyone, everyone needs to validate every transaction) and privacy problems (everyone knows every payment you were ever involved in). + +Unfortunately, this removes a property that onchain users are so used to, they react in surprise when learning about this removal. +Your onchain activity is recorded in all archival fullnodes, so if you forget all your onchain activity because your storage got fried, you just go redownload the activity from the nearest archival full node. + +But in Lightning, since _you_ are the only one storing all your financial information, you **_cannot_** recover this financial information from anywhere else. + +This means that on Lightning, **you have to** responsibly back up your financial information yourself, using various processes and automation. + +The discussion below assumes that you know where you put your `$LIGHTNINGDIR`, and you know the directory structure within. By default your `$LIGHTNINGDIR` will be in `~/.lightning/${COIN}`. For example, if you are running `--mainnet`, it will be +`~/.lightning/bitcoin`. + +## `hsm_secret` + +> 📘 Who should do this: +> +> Everyone. + +You need a copy of the `hsm_secret` file regardless of whatever backup strategy you use. + +The `hsm_secret` is created when you first create the node, and does not change. +Thus, a one-time backup of `hsm_secret` is sufficient. + +This is just 32 bytes, and you can do something like the below and write the hexadecimal digits a few times on a piece of paper: + +```shell +cd $LIGHTNINGDIR +xxd hsm_secret +``` + + + +You can re-enter the hexdump into a text file later and use `xxd` to convert it back to a binary `hsm_secret`: + +``` +cat > hsm_secret_hex.txt < hsm_secret +chmod 0400 hsm_secret +``` + + + +Notice that you need to ensure that the `hsm_secret` is only readable by the user, and is not writable, as otherwise `lightningd` will refuse to start. Hence the `chmod 0400 hsm_secret` command. + +Alternatively, if you are deploying a new node that has no funds and channels yet, you can generate BIP39 words using any process, and create the `hsm_secret` using the `hsmtool generatehsm` command. +If you did `make install` then `hsmtool` is installed as [`lightning-hsmtool`](ref:lightning-hsmtool), else you can find it in the `tools/` directory of the build directory. + +```shell +lightning-hsmtool generatehsm hsm_secret +``` + + + +Then enter the BIP39 words, plus an optional passphrase. Then copy the `hsm_secret` to `${LIGHTNINGDIR}` + +You can regenerate the same `hsm_secret` file using the same BIP39 words, which again, you can back up on paper. + +Recovery of the `hsm_secret` is sufficient to recover any onchain funds. +Recovery of the `hsm_secret` is necessary, but insufficient, to recover any in-channel funds. +To recover in-channel funds, you need to use one or more of the other backup strategies below. + +## SQLITE3 `--wallet=${main}:${backup}` And Remote NFS Mount + +> 📘 Who should do this: +> +> Casual users. + +> 🚧 +> +> This technique is only supported after the version v0.10.2 (not included) or later. +> +> On earlier versions, the `:` character is not special and will be considered part of the path of the database file. + +When using the SQLITE3 backend (the default), you can specify a second database file to replicate to, by separating the second file with a single `:` character in the `--wallet` option, after the main database filename. + +For example, if the user running `lightningd` is named `user`, and you are on the Bitcoin mainnet with the default `${LIGHTNINGDIR}`, you can specify in your `config` file: + +```shell +wallet=sqlite3:///home/user/.lightning/bitcoin/lightningd.sqlite3:/my/backup/lightningd.sqlite3 +``` + + + +Or via command line: + +``` +lightningd --wallet=sqlite3:///home/user/.lightning/bitcoin/lightningd.sqlite3:/my/backup/lightningd.sqlite3 +``` + + + +If the second database file does not exist but the directory that would contain it does exist, the file is created. +If the directory of the second database file does not exist, `lightningd` will fail at startup. +If the second database file already exists, on startup it will be overwritten with the main database. +During operation, all database updates will be done on both databases. + +The main and backup files will **not** be identical at every byte, but they will still contain the same data. + +It is recommended that you use **the same filename** for both files, just on different directories. + +This has the advantage compared to the `backup` plugin below of requiring exactly the same amount of space on both the main and backup storage. The `backup` plugin will take more space on the backup than on the main storage. +It has the disadvantage that it will only work with the SQLITE3 backend and is not supported by the PostgreSQL backend, and is unlikely to be supported on any future database backends. + +You can only specify _one_ replica. + +It is recommended that you use a network-mounted filesystem for the backup destination. +For example, if you have a NAS you can access remotely. + +At the minimum, set the backup to a different storage device. +This is no better than just using RAID-1 (and the RAID-1 will probably be faster) but this is easier to set up --- just plug in a commodity USB flash disk (with metal casing, since a lot of writes are done and you need to dissipate the heat quickly) and use it as the backup location, without +repartitioning your OS disk, for example. + +> 📘 +> +> Do note that files are not stored encrypted, so you should really not do this with rented space ("cloud storage"). + +To recover, simply get **all** the backup database files. +Note that SQLITE3 will sometimes create a `-journal` or `-wal` file, which is necessary to ensure correct recovery of the backup; you need to copy those too, with corresponding renames if you use a different filename for the backup database, e.g. if you named the backup `backup.sqlite3` and when you recover you find `backup.sqlite3` and `backup.sqlite3-journal` files, you rename `backup.sqlite3` to `lightningd.sqlite3` and +`backup.sqlite3-journal` to `lightningd.sqlite3-journal`. +Note that the `-journal` or `-wal` file may or may not exist, but if they _do_, you _must_ recover them as well (there can be an `-shm` file as well in WAL mode, but it is unnecessary; +it is only used by SQLITE3 as a hack for portable shared memory, and contains no useful data; SQLITE3 will ignore its contents always). +It is recommended that you use **the same filename** for both main and backup databases (just on different directories), and put the backup in its own directory, so that you can just recover all the files in that directory without worrying about missing any needed files or correctly +renaming. + +If your backup destination is a network-mounted filesystem that is in a remote location, then even loss of all hardware in one location will allow you to still recover your Lightning funds. + +However, if instead you are just replicating the database on another storage device in a single location, you remain vulnerable to disasters like fire or computer confiscation. + +## `backup` Plugin And Remote NFS Mount + +> 📘 Who should do this: +> +> Casual users. + +You can find the full source for the `backup` plugin here: + + +The `backup` plugin requires Python 3. + +- Download the source for the plugin. + - `git clone https://github.com/lightningd/plugins.git` +- `cd` into its directory and install requirements. + - `cd plugins/backup` + - `pip3 install -r requirements.txt` +- Figure out where you will put the backup files. + - Ideally you have an NFS or other network-based mount on your system, into which you will put the backup. +- Stop your Lightning node. +- `/path/to/backup-cli init --lightning-dir ${LIGHTNINGDIR} file:///path/to/nfs/mount/file.bkp`. + This creates an initial copy of the database at the NFS mount. +- Add these settings to your `lightningd` configuration: + - `important-plugin=/path/to/backup.py` +- Restart your Lightning node. + +It is recommended that you use a network-mounted filesystem for the backup destination. +For example, if you have a NAS you can access remotely. + +> 📘 +> +> Do note that files are not stored encrypted, so you should really not do this with rented space ("cloud storage"). + +Alternately, you _could_ put it in another storage device (e.g. USB flash disk) in the same physical location. + +To recover: + +- Re-download the `backup` plugin and install Python 3 and the + requirements of `backup`. +- `/path/to/backup-cli restore file:///path/to/nfs/mount ${LIGHTNINGDIR}` + +If your backup destination is a network-mounted filesystem that is in a remote location, then even loss of all hardware in one location will allow you to still recover your Lightning funds. + +However, if instead you are just replicating the database on another storage device in a single location, you remain vulnerable to disasters like fire or computer confiscation. + +## Filesystem Redundancy + +> 📘 Who should do this: +> +> Filesystem nerds, data hoarders, home labs, enterprise users. + +You can set up a RAID-1 with multiple storage devices, and point the `$LIGHTNINGDIR` to the RAID-1 setup. That way, failure of one storage device will still let you recover funds. + +You can use a hardware RAID-1 setup, or just buy multiple commodity storage media you can add to your machine and use a software RAID, such as (not an exhaustive list!): + +- `mdadm` to create a virtual volume which is the RAID combination of multiple physical media. +- BTRFS RAID-1 or RAID-10, a filesystem built into Linux. +- ZFS RAID-Z, a filesystem that cannot be legally distributed with the Linux kernel, but can be distributed in a BSD system, and can be installed on Linux with some extra effort, see + [ZFSonLinux](https://zfsonlinux.org). + +RAID-1 (whether by hardware, or software) like the above protects against failure of a single storage device, but does not protect you in case of certain disasters, such as fire or computer confiscation. + +You can "just" use a pair of high-quality metal-casing USB flash devices (you need metal-casing since the devices will have a lot of small writes, which will cause a lot of heating, which needs to dissipate very fast, otherwise the flash device firmware will internally disconnect the flash device from your computer, reducing your reliability) in RAID-1, if you have enough USB ports. + +### Example: BTRFS on Linux + +On a Linux system, one of the simpler things you can do would be to use BTRFS RAID-1 setup between a partition on your primary storage and a USB flash disk. + +The below "should" work, but assumes you are comfortable with low-level Linux administration. +If you are on a system that would make you cry if you break it, you **MUST** stop your Lightning node and back up all files before doing the below. + +- Install `btrfs-progs` or `btrfs-tools` or equivalent. +- Get a 32Gb USB flash disk. +- Stop your Lightning node and back up everything, do not be stupid. +- Repartition your hard disk to have a 30Gb partition. + - This is risky and may lose your data, so this is best done with a brand-new hard disk that contains no data. +- Connect the USB flash disk. +- Find the `/dev/sdXX` devices for the HDD 30Gb partition and the flash disk. + - `lsblk -o NAME,TYPE,SIZE,MODEL` should help. +- Create a RAID-1 `btrfs` filesystem. + - `mkfs.btrfs -m raid1 -d raid1 /dev/${HDD30GB} /dev/${USB32GB}` + - You may need to add `-f` if the USB flash disk is already formatted. +- Create a mountpoint for the `btrfs` filesystem. +- Create a `/etc/fstab` entry. + - Use the `UUID` option instad of `/dev/sdXX` since the exact device letter can change across boots. + - You can get the UUID by `lsblk -o NAME,UUID`. Specifying _either_ of the devices is sufficient. + - Add `autodefrag` option, which tends to work better with SQLITE3 databases. + - e.g. `UUID=${UUID} ${BTRFSMOUNTPOINT} btrfs defaults,autodefrag 0 0` +- `mount -a` then `df` to confirm it got mounted. +- Copy the contents of the `$LIGHTNINGDIR` to the BTRFS mount point. + - Copy the entire directory, then `chown -R` the copy to the user who will run the `lightningd`. + - If you are paranoid, run `diff -r` on both copies to check. +- Remove the existing `$LIGHTNINGDIR`. +- `ln -s ${BTRFSMOUNTPOINT}/lightningdirname ${LIGHTNINGDIR}`. + - Make sure the `$LIGHTNINGDIR` has the same structure as what you originally had. +- Add `crontab` entries for `root` that perform regular `btrfs` maintenance tasks. + - `0 0 * * * /usr/bin/btrfs balance start -dusage=50 -dlimit=2 -musage=50 -mlimit=4 ${BTRFSMOUNTPOINT}` + This prevents BTRFS from running out of blocks even if it has unused space _within_ blocks, and is run at midnight everyday. You may need to change the path to the `btrfs` binary. + - `0 0 * * 0 /usr/bin/btrfs scrub start -B -c 2 -n 4 ${BTRFSMOUNTPOINT}` + This detects bit rot (i.e. bad sectors) and auto-heals the filesystem, and is run on Sundays at midnight. +- Restart your Lightning node. + +If one or the other device fails completely, shut down your computer, boot on a recovery disk or similar, then: + +- Connect the surviving device. +- Mount the partition/USB flash disk in `degraded` mode: + - `mount -o degraded /dev/sdXX /mnt/point` +- Copy the `lightningd.sqlite3` and `hsm_secret` to new media. + - Do **not** write to the degraded `btrfs` mount! +- Start up a `lightningd` using the `hsm_secret` and `lightningd.sqlite3` and close all channels and move all funds to onchain cold storage you control, then set up a new Lightning node. + +If the device that fails is the USB flash disk, you can replace it using BTRFS commands. +You should probably stop your Lightning node while doing this. + +- `btrfs replace start /dev/sdOLD /dev/sdNEW ${BTRFSMOUNTPOINT}`. + - If `/dev/sdOLD` no longer even exists because the device is really really broken, use `btrfs filesystem show` to see the number after `devid` of the broken device, and use that number instead of `/dev/sdOLD`. +- Monitor status with `btrfs replace status ${BTRFSMOUNTPOINT}`. + +More sophisticated setups with more than two devices are possible. Take note that "RAID 1" in `btrfs` means "data is copied on up to two devices", meaning only up to one device can fail. +You may be interested in `raid1c3` and `raid1c4` modes if you have three or four storage devices. BTRFS would probably work better if you were purchasing an entire set +of new storage devices to set up a new node. + +## PostgreSQL Cluster + +> 📘 Who should do this: +> +> Enterprise users, whales. + +`lightningd` may also be compiled with PostgreSQL support. + +PostgreSQL is generally faster than SQLITE3, and also supports running a PostgreSQL cluster to be used by `lightningd`, with automatic replication and failover in case an entire node of the PostgreSQL cluster fails. + +Setting this up, however, is more involved. + +By default, `lightningd` compiles with PostgreSQL support **only** if it finds `libpq` installed when you `./configure`. To enable it, you have to install a developer version of `libpq`. On most Debian-derived systems that would be `libpq-dev`. To verify you have it properly installed on your system, check if the following command gives you a path: + +```shell +pg_config --includedir +``` + + + +Versioning may also matter to you. +For example, Debian Stable ("buster") as of late 2020 provides PostgreSQL 11.9 for the `libpq-dev` package, but Ubuntu LTS ("focal") of 2020 provides PostgreSQL 12.5. +Debian Testing ("bullseye") uses PostgreSQL 13.0 as of this writing. PostgreSQL 12 had a non-trivial change in the way the restore operation is done for replication. + +You should use the same PostgreSQL version of `libpq-dev` as what you run on your cluster, which probably means running the same distribution on your cluster. + +Once you have decided on a specific version you will use throughout, refer as well to the "synchronous replication" document of PostgreSQL for the **specific version** you are using: + +- [PostgreSQL 11](https://www.postgresql.org/docs/11/runtime-config-replication.html) +- [PostgreSQL 12](https://www.postgresql.org/docs/12/runtime-config-replication.html) +- [PostgreSQL 13](https://www.postgresql.org/docs/13/runtime-config-replication.html) + +You then have to compile `lightningd` with PostgreSQL support. + +- Clone or untar a new source tree for `lightning` and `cd` into it. + - You _could_ just use `make clean` on an existing one, but for the avoidance of doubt (and potential bugs in our `Makefile` cleanup rules), just create a fresh source tree. +- `./configure` + - Add any options to `configure` that you normally use as well. +- Double-check the `config.vars` file contains `HAVE_POSTGRES=1`. + - `grep 'HAVE_POSTGRES' config.vars` +- `make` +- If you install `lightningd`, `sudo make install`. + +If you were not using PostgreSQL before but have compiled and used `lightningd` on your system, the resulting `lightningd` will still continue supporting and using your current SQLITE3 database; it just gains the option to use a PostgreSQL database as well. + +If you just want to use PostgreSQL without using a cluster (for example, as an initial test without risking any significant funds), then after setting up a PostgreSQL database, you just need to add +`--wallet=postgres://${USER}:${PASSWORD}@${HOST}:${PORT}/${DB}` to your `lightningd` config or invocation. + +To set up a cluster for a brand new node, follow this (external) [guide by @gabridome](https://github.com/gabridome/docs/blob/master/c-lightning_with_postgresql_reliability.md) + +The above guide assumes you are setting up a new node from scratch. It is also specific to PostgreSQL 12, and setting up for other versions **will** have differences; read the PostgreSQL manuals linked above. + +> 🚧 +> +> If you want to continue a node that started using an SQLITE3 database, note that we do not support this. You should set up a new PostgreSQL node, move funds from the SQLITE3 node to the PostgreSQL node, then shut down the SQLITE3 node permanently. + +There are also more ways to set up PostgreSQL replication. +In general, you should use [synchronous replication](https://www.postgresql.org/docs/13/warm-standby.html#SYNCHRONOUS-REPLICATION), since `lightningd` assumes that once a transaction is committed, it is saved in all permanent storage. This can be difficult to create remote replicas due to the latency. + +## SQLite Litestream Replication + + + +> 🚧 +> +> Previous versions of this document recommended this technique, but we no longer do so. +> According to [issue 4857](https://github.com/ElementsProject/lightning/issues/4857), even with a 60-second timeout that we added in 0.10.2, this leads to constant crashing of `lightningd` in some situations. This section will be removed completely six months after 0.10.3. Consider using `--wallet=sqlite3://${main}:${backup}` above instead. + +One of the simpler things on any system is to use Litestream to replicate the SQLite database. It continuously streams SQLite changes to file or external storage - the cloud storage option should not be used. +Backups/replication should not be on the same disk as the original SQLite DB. + +You need to enable WAL mode on your database. +To do so, first stop `lightningd`, then: + +```shell +$ sqlite3 lightningd.sqlite3 +sqlite3> PRAGMA journal_mode = WAL; +sqlite3> .quit +``` + +Then just restart `lightningd`. + +/etc/litestream.yml : + +```shell +dbs: + - path: /home/bitcoin/.lightning/bitcoin/lightningd.sqlite3 + replicas: + - path: /media/storage/lightning_backup +``` + + and start the service using systemctl: + +```shell +$ sudo systemctl start litestream +``` + +Restore: + +```shell +$ litestream restore -o /media/storage/lightning_backup /home/bitcoin/restore_lightningd.sqlite3 +``` + +Because Litestream only copies small changes and not the entire database (holding a read lock on the file while doing so), the 60-second timeout on locking should not be reached unless something has made your backup medium very very slow. + +Litestream has its own timer, so there is a tiny (but non-negligible) probability that `lightningd` updates the +database, then irrevocably commits to the update by sending revocation keys to the counterparty, and _then_ your main storage media crashes before Litestream can replicate the update. + +Treat this as a superior version of "Database File Backups" section below and prefer recovering via other backup methods first. + + + +## Database File Backups + +> 📘 Who should do this: +> +> Those who already have at least one of the other backup methods, those who are #reckless. + +This is the least desirable backup strategy, as it _can_ lead to loss of all in-channel funds if you use it. +However, having _no_ backup strategy at all _will_ lead to loss of all in-channel funds, so this is still better than nothing. + +This backup method is undesirable, since it cannot recover the following channels: + +- Channels with peers that do not support `option_dataloss_protect`. + - Most nodes on the network already support `option_dataloss_protect` as of November 2020. + - If the peer does not support `option_dataloss_protect`, then the entire channel funds will be revoked by the peer. + - Peers can _claim_ to honestly support this, but later steal funds from you by giving obsolete state when you recover. +- Channels created _after_ the copy was made are not recoverable. + - Data for those channels does not exist in the backup, so your node cannot recover them. + +Because of the above, this strategy is discouraged: you _can_ potentially lose all funds in open channels. + +However, again, note that a "no backups #reckless" strategy leads to _definite_ loss of funds, so you should still prefer _this_ strategy rather than having _no_ backups at all. + +Even if you have one of the better options above, you might still want to do this as a worst-case fallback, as long as you: + +- Attempt to recover using the other backup options above first. Any one of them will be better than this backup option. +- Recover by this method **ONLY** as a **_last_** resort. +- Recover using the most recent backup you can find. Take time to look for the most recent available backup. + +Again, this strategy can lead to only **_partial_** recovery of funds, or even to complete failure to recover, so use the other methods first to recover! + +### Offline Backup + +While `lightningd` is not running, just copy the `lightningd.sqlite3` file in the `$LIGHTNINGDIR` on backup media somewhere. + +To recover, just copy the backed up `lightningd.sqlite3` into your new `$LIGHTNINGDIR` together with the `hsm_secret`. + +You can also use any automated backup system as long as it includes the `lightningd.sqlite3` file (and optionally `hsm_secret`, but note that as a secret key, thieves getting a copy of your backups may allow them to steal your funds, even in-channel funds) and as long as it copies the file while `lightningd` is not running. + +### Backing Up While `lightningd` Is Running + +Since `sqlite3` will be writing to the file while `lightningd` is running, `cp`ing the `lightningd.sqlite3` file while `lightningd` is running may result in the file not being copied properly if `sqlite3` happens to be committing database transactions at that time, potentially leading to a corrupted backup file that cannot be recovered from. + +You have to stop `lightningd` before copying the database to backup in order to ensure that backup files are not corrupted, and in particular, wait for the `lightningd` process to exit. +Obviously, this is disruptive to node operations, so you might prefer to just perform the `cp` even if the backup potentially is corrupted. As long as you maintain multiple backups sampled at different times, this may be more acceptable than stopping and restarting `lightningd`; the corruption only exists in the backup, not in the original file. + +If the filesystem or volume manager containing `$LIGHTNINGDIR` has a snapshot facility, you can take a snapshot of the filesystem, then mount the snapshot, copy `lightningd.sqlite3`, unmount the snapshot, and then delete the snapshot. +Similarly, if the filesystem supports a "reflink" feature, such as `cp -c` on an APFS on MacOS, or `cp --reflink=always` on an XFS or BTRFS on Linux, you can also use that, then copy the reflinked copy to a different storage medium; this is equivalent to a snapshot of a single file. +This _reduces_ but does not _eliminate_ this race condition, so you should still maintain multiple backups. + +You can additionally perform a check of the backup by this command: + +```shell +echo 'PRAGMA integrity_check;' | sqlite3 ${BACKUPFILE} +``` + + + +This will result in the string `ok` being printed if the backup is **likely** not corrupted. +If the result is anything else than `ok`, the backup is definitely corrupted and you should make another copy. + +In order to make a proper uncorrupted backup of the SQLITE3 file while `lightningd` is running, we would need to have `lightningd` perform the backup itself, which, as of the version at the time of this writing, is not yet implemented. + +Even if the backup is not corrupted, take note that this backup strategy should still be a last resort; recovery of all funds is still not assured with this backup strategy. + +`sqlite3` has `.dump` and `VACUUM INTO` commands, but note that those lock the main database for long time periods, which will negatively affect your `lightningd` instance. \ No newline at end of file diff --git a/doc/guides/Beginner-s Guide/beginners-guide.md b/doc/guides/Beginner-s Guide/beginners-guide.md new file mode 100644 index 000000000000..7770beb76c59 --- /dev/null +++ b/doc/guides/Beginner-s Guide/beginners-guide.md @@ -0,0 +1,76 @@ +--- +title: "Running your node" +slug: "beginners-guide" +excerpt: "A guide to all the basics you need to get up and running immediately." +hidden: false +createdAt: "2022-11-18T14:27:50.098Z" +updatedAt: "2023-02-21T13:49:20.132Z" +--- +## Starting `lightningd` + +#### Regtest (local, fast-start) option + +If you want to experiment with `lightningd`, there's a script to set up a `bitcoind` regtest test network of two local lightning nodes, which provides a convenient `start_ln` helper. See the notes at the top of the `startup_regtest.sh` file for details on how to use it. + +```bash +. contrib/startup_regtest.sh +``` + + + +Note that your local nodeset will be much faster/more responsive if you've configured your node to expose the developer options, e.g. + +```bash +./configure --enable-developer +``` + + + +#### Mainnet Option + +To test with real bitcoin, you will need to have a local `bitcoind` node running: + +```bash +bitcoind -daemon +``` + + + +Wait until `bitcoind` has synchronized with the network. + +Make sure that you do not have `walletbroadcast=0` in your `~/.bitcoin/bitcoin.conf`, or you may run into trouble. +Notice that running `lightningd` against a pruned node may cause some issues if not managed carefully, see [pruning](doc:bitcoin-core##using-a-pruned-bitcoin-core-node) for more information. + +You can start `lightningd` with the following command: + +```bash +lightningd --network=bitcoin --log-level=debug +``` + + + +This creates a `.lightning/` subdirectory in your home directory: see `man -l doc/lightningd.8` (or [???](???)) for more runtime options. + +## Using The JSON-RPC Interface + +Core Lightning exposes a [JSON-RPC 2.0](https://www.jsonrpc.org/specification) interface over a Unix Domain socket; the [`lightning-cli`](ref:lightning-cli) tool can be used to access it, or there is a [python client library](???). + +You can use `[lightning-cli](ref:lightning-cli) help` to print a table of RPC methods; `[lightning-cli](lightning-cli) help ` will offer specific information on that command. + +Useful commands: + +- [lightning-newaddr](ref:lightning-newaddr): get a bitcoin address to deposit funds into your lightning node. +- [lightning-listfunds](ref:lightning-listfunds): see where your funds are. +- [lightning-connect](ref:lightning-connect): connect to another lightning node. +- [lightning-fundchannel](ref:lightning-fundchannel): create a channel to another connected node. +- [lightning-invoice](ref:lightning-invoice): create an invoice to get paid by another node. +- [lightning-pay](ref:lightning-pay): pay someone else's invoice. +- [lightning-plugin](ref:lightning-plugin): commands to control extensions. + +## Care And Feeding Of Your New Lightning Node + +Once you've started for the first time, there's a script called `contrib/bootstrap-node.sh` which will connect you to other nodes on the lightning network. + +There are also numerous plugins available for Core Lightning which add capabilities: see the [Plugins](doc:plugins) guide, and check out the plugin collection at: , including [helpme](https://github.com/lightningd/plugins/tree/master/helpme) which guides you through setting up your first channels and customising your node. + +For a less reckless experience, you can encrypt the HD wallet seed: see [HD wallet encryption](doc:securing-keys). \ No newline at end of file diff --git a/doc/guides/Beginner-s Guide/opening-channels.md b/doc/guides/Beginner-s Guide/opening-channels.md new file mode 100644 index 000000000000..4341e2188029 --- /dev/null +++ b/doc/guides/Beginner-s Guide/opening-channels.md @@ -0,0 +1,50 @@ +--- +title: "Opening channels" +slug: "opening-channels" +hidden: false +createdAt: "2022-11-18T16:26:57.798Z" +updatedAt: "2023-01-31T15:07:08.196Z" +--- +First you need to transfer some funds to `lightningd` so that it can open a channel: + +```shell +# Returns an address
+lightning-cli newaddr +``` + + + +`lightningd` will register the funds once the transaction is confirmed. + +You may need to generate a p2sh-segwit address if the faucet does not support bech32: + +```shell +# Return a p2sh-segwit address +lightning-cli newaddr p2sh-segwit +``` + + + +Confirm `lightningd` got funds by: + +```shell +# Returns an array of on-chain funds. +lightning-cli listfunds +``` + + + +Once `lightningd` has funds, we can connect to a node and open a channel. Let's assume the **remote** node is accepting connections at `` (and optional ``, if not 9735) and has the node ID ``: + +```shell +lightning-cli connect [] +lightning-cli fundchannel +``` + + + +This opens a connection and, on top of that connection, then opens a channel. + +The funding transaction needs 3 confirmations in order for the channel to be usable, and 6 to be announced for others to use. + +You can check the status of the channel using `lightning-cli listpeers`, which after 3 confirmations (1 on testnet) should say that `state` is `CHANNELD_NORMAL`; after 6 confirmations you can use `lightning-cli listchannels` to verify that the `public` field is now `true`. \ No newline at end of file diff --git a/doc/guides/Beginner-s Guide/securing-keys.md b/doc/guides/Beginner-s Guide/securing-keys.md new file mode 100644 index 000000000000..468a63608196 --- /dev/null +++ b/doc/guides/Beginner-s Guide/securing-keys.md @@ -0,0 +1,10 @@ +--- +title: "Securing keys" +slug: "securing-keys" +hidden: false +createdAt: "2022-11-18T16:28:08.529Z" +updatedAt: "2023-01-31T13:52:27.300Z" +--- +You can encrypt the `hsm_secret` content (which is used to derive the HD wallet's master key) by passing the `--encrypted-hsm` startup argument, or by using the `hsmtool` (which you can find in the `tool/` directory at the root of [Core Lightning repository](https://github.com/ElementsProject/lightning)) with the `encrypt` method. You can unencrypt an encrypted `hsm_secret` using the `hsmtool` with the `decrypt` method. + +If you encrypt your `hsm_secret`, you will have to pass the `--encrypted-hsm` startup option to `lightningd`. Once your `hsm_secret` is encrypted, you **will not** be able to access your funds without your password, so please beware with your password management. Also, beware of not feeling too safe with an encrypted `hsm_secret`: unlike for `bitcoind` where the wallet encryption can restrict the usage of some RPC command, `lightningd` always needs to access keys from the wallet which is thus **not locked** (yet), even with an encrypted BIP32 master seed. \ No newline at end of file diff --git a/doc/guides/Beginner-s Guide/sending-and-receiving-payments.md b/doc/guides/Beginner-s Guide/sending-and-receiving-payments.md new file mode 100644 index 000000000000..cbc757218705 --- /dev/null +++ b/doc/guides/Beginner-s Guide/sending-and-receiving-payments.md @@ -0,0 +1,24 @@ +--- +title: "Sending and receiving payments" +slug: "sending-and-receiving-payments" +hidden: false +createdAt: "2022-11-18T16:27:07.625Z" +updatedAt: "2023-01-31T15:06:02.214Z" +--- +Payments in Lightning are invoice based. + +The recipient creates an invoice with the expected `` in millisatoshi (or `"any"` for a donation), a unique `