Compare commits
1 Commits
btcpaymast
...
fix/pay-pl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c30218199f |
@ -1,3 +0,0 @@
|
||||
Dockerfile
|
||||
contrib/docker/Dockerfile.*
|
||||
target
|
||||
@ -1,18 +0,0 @@
|
||||
# https://editorconfig.org/#file-format-details
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{**.c,**.h,Makefile}]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
|
||||
[**.py]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
14
.gitattributes
vendored
14
.gitattributes
vendored
@ -4,17 +4,3 @@
|
||||
Makefile text eol=lf
|
||||
configure text eol=lf
|
||||
.gitmodules text eol=lf
|
||||
# The following files are generated and should not be shown in the
|
||||
# diffs by default on Github.
|
||||
doc/lightning*.7 linguist-generated=true
|
||||
db_*_sqlgen.c linguist-generated=true
|
||||
statements_gettextgen.po linguist-generated=true
|
||||
*_wiregen.? linguist-generated=true
|
||||
*_printgen.? linguist-generated=true
|
||||
|
||||
# The following are marked as binary and generated since they can be
|
||||
# easily overwritten and don't need deep review.
|
||||
cln-grpc/proto/node.proto -text -diff linguist-generated=true
|
||||
cln-grpc/src/convert.rs -text -diff linguist-generated=true
|
||||
cln-rpc/src/model.rs -text -diff linguist-generated=true
|
||||
contrib/pyln-testing/pyln/testing/node_pb2.py -text -diff linguist-generated=true
|
||||
|
||||
20
.github/CODEOWNERS
vendored
20
.github/CODEOWNERS
vendored
@ -4,16 +4,16 @@
|
||||
# also can optionally require approval from a code owner before the
|
||||
# author can merge a pull request in the repository.
|
||||
|
||||
cln-grpc/ @cdecker
|
||||
cln-rpc/ @cdecker
|
||||
plugins/src/ @cdecker
|
||||
plugins/grpc-plugin/ @cdecker
|
||||
contrib/reprobuild/ @cdecker
|
||||
contrib/msggen/ @cdecker
|
||||
contrib/pyln-client/ @cdecker
|
||||
contrib/pyln-testing/ @cdecker
|
||||
# Needed to ensure hsmd wire compatibility between releases
|
||||
hsmd/hsmd_wire.csv @cdecker @ksedgwic @devrandom
|
||||
wallet/ @cdecker
|
||||
*.py @cdecker
|
||||
|
||||
wallet/invoices.* @ZmnSCPxj
|
||||
lightningd/payalgo.* @ZmnSCPxj
|
||||
|
||||
common/param.* @wythe
|
||||
common/json.* @wythe
|
||||
common/json_tok.* @wythe
|
||||
common/wallet_tx.* @wythe
|
||||
|
||||
# See https://help.github.com/articles/about-codeowners/ for more
|
||||
# information
|
||||
|
||||
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,16 +0,0 @@
|
||||
> [!IMPORTANT]
|
||||
>
|
||||
> 25.09 FREEZE July 28TH: Non-bugfix PRs not ready by this date will wait for 25.12.
|
||||
>
|
||||
> RC1 is scheduled on _August 11th_
|
||||
>
|
||||
> The final release is scheduled for September 1st.
|
||||
|
||||
|
||||
## Checklist
|
||||
Before submitting the PR, ensure the following tasks are completed. If an item is not applicable to your PR, please mark it as checked:
|
||||
|
||||
- [ ] The changelog has been updated in the relevant commit(s) according to the [guidelines](https://docs.corelightning.org/docs/coding-style-guidelines#changelog-entries-in-commit-messages).
|
||||
- [ ] Tests have been added or modified to reflect the changes.
|
||||
- [ ] Documentation has been reviewed and updated as needed.
|
||||
- [ ] Related issues have been listed and linked, including any that this PR closes.
|
||||
31
.github/scripts/install-bitcoind.sh
vendored
31
.github/scripts/install-bitcoind.sh
vendored
@ -1,31 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
export BITCOIN_VERSION=27.1
|
||||
export ELEMENTS_VERSION=23.2.1
|
||||
|
||||
DIRNAME="bitcoin-${BITCOIN_VERSION}"
|
||||
EDIRNAME="elements-${ELEMENTS_VERSION}"
|
||||
FILENAME="${DIRNAME}-x86_64-linux-gnu.tar.gz"
|
||||
EFILENAME="${EDIRNAME}-x86_64-linux-gnu.tar.gz"
|
||||
|
||||
cd /tmp/
|
||||
|
||||
# Since we inadvertently broke `elementsd` support in the past we only
|
||||
# want to download and enable the daemon that is actually going to be
|
||||
# used when running in CI. Otherwise we could end up accidentally
|
||||
# testing against `bitcoind` but still believe that we ran against
|
||||
# `elementsd`.
|
||||
if [ "$TEST_NETWORK" = "liquid-regtest" ]; then
|
||||
wget "https://github.com/ElementsProject/elements/releases/download/elements-${ELEMENTS_VERSION}/${EFILENAME}"
|
||||
tar -xf "${EFILENAME}"
|
||||
sudo mv "${EDIRNAME}"/bin/* "/usr/local/bin"
|
||||
rm -rf "${EFILENAME}" "${EDIRNAME}"
|
||||
else
|
||||
wget "https://bitcoincore.org/bin/bitcoin-core-${BITCOIN_VERSION}/${FILENAME}"
|
||||
tar -xf "${FILENAME}"
|
||||
sudo mv "${DIRNAME}"/bin/* "/usr/local/bin"
|
||||
rm -rf "${FILENAME}" "${DIRNAME}"
|
||||
fi
|
||||
|
||||
93
.github/scripts/setup.sh
vendored
93
.github/scripts/setup.sh
vendored
@ -1,93 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
export RUST_VERSION=stable
|
||||
|
||||
sudo useradd -ms /bin/bash tester
|
||||
sudo apt-get update -qq
|
||||
|
||||
sudo apt-get -qq install --no-install-recommends --allow-unauthenticated -yy \
|
||||
autoconf \
|
||||
automake \
|
||||
binfmt-support \
|
||||
build-essential \
|
||||
clang \
|
||||
cppcheck \
|
||||
docbook-xml \
|
||||
eatmydata \
|
||||
gcc-aarch64-linux-gnu \
|
||||
gcc-arm-linux-gnueabihf \
|
||||
gcc-arm-none-eabi \
|
||||
gettext \
|
||||
git \
|
||||
gnupg \
|
||||
jq \
|
||||
libc6-dev-arm64-cross \
|
||||
libc6-dev-armhf-cross \
|
||||
libev-dev \
|
||||
libevent-dev \
|
||||
libffi-dev \
|
||||
libicu-dev \
|
||||
libpq-dev \
|
||||
libprotobuf-c-dev \
|
||||
libsqlite3-dev \
|
||||
libssl-dev \
|
||||
libtool \
|
||||
libxml2-utils \
|
||||
locales \
|
||||
net-tools \
|
||||
postgresql \
|
||||
python-pkg-resources \
|
||||
python3 \
|
||||
python3-dev \
|
||||
python3-pip \
|
||||
python3-setuptools \
|
||||
qemu \
|
||||
qemu-system-arm \
|
||||
qemu-user-static \
|
||||
shellcheck \
|
||||
software-properties-common \
|
||||
sudo \
|
||||
tcl \
|
||||
tclsh \
|
||||
unzip \
|
||||
valgrind \
|
||||
wget \
|
||||
xsltproc \
|
||||
systemtap-sdt-dev \
|
||||
zlib1g-dev
|
||||
|
||||
echo "tester ALL=(root) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/tester
|
||||
sudo chmod 0440 /etc/sudoers.d/tester
|
||||
|
||||
"$(dirname "$0")"/install-bitcoind.sh
|
||||
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- \
|
||||
-y --default-toolchain ${RUST_VERSION}
|
||||
|
||||
# We also need a relatively recent protobuf-compiler, at least 3.12.0,
|
||||
# in order to support the experimental `optional` flag.
|
||||
|
||||
# BUT WAIT! Gentoo wants this to match the version from the Python protobuf,
|
||||
# which comes from the same tree. Makes sense!
|
||||
|
||||
# And
|
||||
# grpcio-tools-1.69.0` requires `protobuf = ">=5.26.1,<6.0dev"`
|
||||
|
||||
# Now, protoc changed to date-based releases, BUT Python protobuf
|
||||
# didn't, so Python protobuf 4.21.12 (in Ubuntu 23.04) corresponds to
|
||||
# protoc 21.12 (which, FYI, is packaged in Ubuntu as version 3.21.12).
|
||||
|
||||
# In general protobuf version x.y.z corresponds to protoc version y.z
|
||||
|
||||
# Honorable mention go to Matt Whitlock for spelunking this horror with me!
|
||||
|
||||
PROTOC_VERSION=29.4
|
||||
PB_REL="https://github.com/protocolbuffers/protobuf/releases"
|
||||
curl -LO $PB_REL/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip
|
||||
sudo unzip protoc-${PROTOC_VERSION}-linux-x86_64.zip -d /usr/local/
|
||||
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
|
||||
115
.github/scripts/sync-rpc-cmds.py
vendored
115
.github/scripts/sync-rpc-cmds.py
vendored
@ -1,115 +0,0 @@
|
||||
import os
|
||||
from time import sleep
|
||||
import requests
|
||||
import re
|
||||
from enum import Enum
|
||||
|
||||
# readme url
|
||||
URL = "https://dash.readme.com/api/v1"
|
||||
# category id for API reference
|
||||
CATEGORY_ID = "63e4e160c60b2e001dd1cc4e"
|
||||
CATEGORY_SLUG = "json-rpc-apis"
|
||||
|
||||
|
||||
class Action(Enum):
|
||||
ADD = 'add'
|
||||
UPDATE = 'update'
|
||||
DELETE = 'delete'
|
||||
|
||||
|
||||
def getListOfRPCDocs(headers):
|
||||
response = requests.get(f"{URL}/categories/{CATEGORY_SLUG}/docs", headers=headers)
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def publishDoc(action, title, body, order, headers):
|
||||
payload = {
|
||||
"title": title,
|
||||
"type": "basic",
|
||||
"body": body,
|
||||
"category": CATEGORY_ID,
|
||||
"hidden": False,
|
||||
"order": order,
|
||||
}
|
||||
# title == slug
|
||||
if action == Action.ADD:
|
||||
# create doc
|
||||
response = requests.post(URL + "/docs", json=payload, headers=headers)
|
||||
if response.status_code != 201:
|
||||
print(response.text)
|
||||
else:
|
||||
print("Created ", title)
|
||||
elif action == Action.UPDATE:
|
||||
# update doc
|
||||
response = requests.put(f"{URL}/docs/{title}", json=payload, headers=headers)
|
||||
if response.status_code != 200:
|
||||
print(response.text)
|
||||
else:
|
||||
print("Updated ", title)
|
||||
elif action == Action.DELETE:
|
||||
# delete doc
|
||||
response = requests.delete(f"{URL}/docs/{title}", headers=headers)
|
||||
if response.status_code != 204:
|
||||
print(response.text)
|
||||
else:
|
||||
print("Deleted ", title)
|
||||
else:
|
||||
print("Invalid action")
|
||||
|
||||
|
||||
def extract_rpc_commands(rst_content):
|
||||
manpages_block = re.search(
|
||||
r"\.\. block_start manpages(.*?)" r"\.\. block_end manpages",
|
||||
rst_content,
|
||||
re.DOTALL,
|
||||
)
|
||||
if manpages_block:
|
||||
commands = re.findall(
|
||||
r"\b([a-zA-Z0-9_-]+)" r"\s+<([^>]+)>\n", manpages_block.group(1)
|
||||
)
|
||||
return commands
|
||||
return []
|
||||
|
||||
|
||||
def main():
|
||||
# define headers for requests
|
||||
headers = {
|
||||
"accept": "application/json",
|
||||
"content-type": "application/json",
|
||||
"authorization": "Basic " + os.environ.get("README_API_KEY"),
|
||||
}
|
||||
|
||||
# path to the rst file from where we fetch all the RPC commands
|
||||
path_to_rst = "doc/index.rst"
|
||||
with open(path_to_rst, "r") as file:
|
||||
rst_content = file.read()
|
||||
|
||||
commands_from_local = extract_rpc_commands(rst_content)
|
||||
commands_from_readme = getListOfRPCDocs(headers)
|
||||
|
||||
# Compare local and server commands list to get the list of command to add or delete
|
||||
commands_local_title = set(command[0] for command in commands_from_local)
|
||||
commands_readme_title = set(command['title'] for command in commands_from_readme)
|
||||
commands_to_delete = commands_readme_title - commands_local_title
|
||||
commands_to_add = commands_local_title - commands_readme_title
|
||||
for name in commands_to_delete:
|
||||
publishDoc(Action.DELETE, name, "", 0, headers)
|
||||
sleep(3)
|
||||
|
||||
if commands_from_local:
|
||||
order = 0
|
||||
for name, file in commands_from_local:
|
||||
with open("doc/" + file) as f:
|
||||
body = f.read()
|
||||
publishDoc(Action.ADD if name in commands_to_add else Action.UPDATE, name, body, order, headers)
|
||||
order = order + 1
|
||||
sleep(3)
|
||||
else:
|
||||
print("No commands found in the Manpages block.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
79
.github/workflows/bsd.yml
vendored
79
.github/workflows/bsd.yml
vendored
@ -1,79 +0,0 @@
|
||||
name: FreeBSD Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
testfreebsd:
|
||||
runs-on: ubuntu-22.04
|
||||
name: Build and test on FreeBSD
|
||||
timeout-minutes: 120
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
bitcoind-version: ["27.1"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test in FreeBSD
|
||||
id: test
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
usesh: true
|
||||
sync: rsync
|
||||
copyback: false
|
||||
prepare: |
|
||||
pkg install -y \
|
||||
bash \
|
||||
wget \
|
||||
python310 \
|
||||
gmake \
|
||||
git \
|
||||
python \
|
||||
postgresql16-server \
|
||||
autoconf \
|
||||
automake \
|
||||
libtool \
|
||||
bash \
|
||||
gettext \
|
||||
sqlite3 \
|
||||
lowdown \
|
||||
pkgconf \
|
||||
jq \
|
||||
protobuf \
|
||||
curl
|
||||
|
||||
python3.10 -m ensurepip
|
||||
python3.10 -m pip install --upgrade pip
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
|
||||
|
||||
|
||||
run: |
|
||||
PATH=/root/.local/bin:$PATH:/root/.cargo/bin; export PATH
|
||||
pip install --user -U wheel pip
|
||||
pip3 install --user poetry
|
||||
poetry install
|
||||
|
||||
git clone https://github.com/lightning/bolts.git ../bolts
|
||||
# fatal: unsafe repository ('/Users/runner/work/lightning/lightning' is owned by someone else)
|
||||
git config --global --add safe.directory `pwd`
|
||||
for d in libsodium libwally-core gheap jsmn libbacktrace lowdown; do git config --global --add safe.directory `pwd`/external/$d; done
|
||||
git submodule update --init --recursive
|
||||
|
||||
./configure CC="$CC" --disable-valgrind
|
||||
|
||||
cat config.vars
|
||||
|
||||
cat << EOF > pytest.ini
|
||||
[pytest]
|
||||
addopts=-p no:logging --color=yes --timeout=1800 --timeout-method=thread --test-group-random-seed=42 --junitxml=report.xml --json-report --json-report-file=report.json --json-report-indent=2
|
||||
markers =
|
||||
slow_test: marks tests as slow (deselect with '-m "not slow_test"')
|
||||
EOF
|
||||
|
||||
# Just run a "quick" test without memory checking
|
||||
poetry run gmake
|
||||
|
||||
653
.github/workflows/ci.yaml
vendored
653
.github/workflows/ci.yaml
vendored
@ -1,653 +0,0 @@
|
||||
---
|
||||
name: Continuous Integration
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
# Makes the upload-artifact work more reliably at the cost
|
||||
# of a bit of compile time.
|
||||
RUST_PROFILE: release
|
||||
SLOW_MACHINE: 1
|
||||
CI_SERVER_URL: "http://35.239.136.52:3170"
|
||||
|
||||
jobs:
|
||||
prebuild:
|
||||
name: Pre-build checks
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
BOLTDIR: bolts
|
||||
strategy:
|
||||
fail-fast: true
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Rebase
|
||||
# We can't rebase if we're on master already.
|
||||
if: github.ref != 'refs/heads/master'
|
||||
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: Check changelog
|
||||
env:
|
||||
PR_DESCRIPTION: "${{ github.event.pull_request.body || '' }}"
|
||||
EVENT_NAME: "${{ github.event_name }}"
|
||||
BASE_REF: "${{ github.base_ref || 'master' }}"
|
||||
run: |
|
||||
echo "Event Name: $EVENT_NAME"
|
||||
echo "Base Ref: $BASE_REF"
|
||||
echo "PR DESCRIPTION: $PR_DESCRIPTION"
|
||||
if [ "$EVENT_NAME" = "pull_request" ]; then
|
||||
if [[ "$PR_DESCRIPTION" != *"Changelog-None"* && \
|
||||
-z "$(git log origin/$BASE_REF..HEAD --oneline --grep='Changelog-')" && \
|
||||
"$(git rev-parse --abbrev-ref HEAD)" != "$BASE_REF" ]]; then
|
||||
echo "::error::'Changelog' entry is missing in all commits, and 'Changelog-None' not specified in the PR description"
|
||||
exit 1
|
||||
else
|
||||
if [[ "$PR_DESCRIPTION" == *"Changelog-None"* ]]; then
|
||||
echo "Changelog found in PR description"
|
||||
else
|
||||
echo "Changelog found in Commit \"$(git log origin/$BASE_REF..HEAD --oneline --grep='Changelog-')\""
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "Not a PR event."
|
||||
fi
|
||||
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
bash -x .github/scripts/setup.sh
|
||||
pip install -U pip wheel poetry
|
||||
poetry self add poetry-plugin-export
|
||||
# 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
|
||||
# We're going to check BOLT quotes, so get the latest version
|
||||
git clone https://github.com/lightning/bolts.git ../${BOLTDIR}
|
||||
- name: Configure
|
||||
run: ./configure --enable-debugbuild --enable-rust
|
||||
- name: Check source
|
||||
env:
|
||||
VALGRIND: 0
|
||||
PYTEST_OPTS: --timeout=1200
|
||||
run: make check-source BASE_REF="origin/${{ github.base_ref }}"
|
||||
- name: Check Generated Files have been updated
|
||||
run: make check-gen-updated
|
||||
- name: Check docs
|
||||
run: make check-doc
|
||||
|
||||
compile:
|
||||
name: Compile CLN ${{ matrix.cfg }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 30
|
||||
needs:
|
||||
- prebuild
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
include:
|
||||
- CFG: compile-gcc
|
||||
VALGRIND: 1
|
||||
COMPILER: gcc
|
||||
- CFG: compile-gcc-O3
|
||||
VALGRIND: 1
|
||||
COMPILER: gcc
|
||||
COPTFLAGS_VAR: COPTFLAGS="-O3 -Werror"
|
||||
# While we're at it let's try to compile with clang
|
||||
- CFG: compile-clang
|
||||
VALGRIND: 1
|
||||
COMPILER: clang
|
||||
- CFG: compile-clang-sanitizers
|
||||
COMPILER: clang
|
||||
ASAN: 1
|
||||
UBSAN: 1
|
||||
VALGRIND: 0
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
bash -x .github/scripts/setup.sh
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
COMPILER: ${{ matrix.COMPILER }}
|
||||
ASAN: ${{ matrix.ASAN }}
|
||||
UBSAN: ${{ matrix.UBSAN }}
|
||||
VALGRIND: ${{ matrix.VALGRIND }}
|
||||
COMPAT: 1
|
||||
CFG: ${{ matrix.CFG }}
|
||||
run: |
|
||||
set -e
|
||||
pip3 install --user pip wheel poetry
|
||||
poetry self add poetry-plugin-export
|
||||
poetry export -o requirements.txt --with dev --without-hashes
|
||||
python3 -m pip install -r requirements.txt
|
||||
./configure --enable-debugbuild CC="$COMPILER" ${{ matrix.COPTFLAGS_VAR }}
|
||||
|
||||
make -j $(nproc) testpack.tar.bz2
|
||||
|
||||
# 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@v4
|
||||
with:
|
||||
name: cln-${{ matrix.CFG }}.tar.bz2
|
||||
path: cln-${{ matrix.CFG }}.tar.bz2
|
||||
|
||||
check-units:
|
||||
# The unit test checks are not in the critical path (not dependent
|
||||
# on the integration tests), so run them with `valgrind`
|
||||
name: Run unit tests
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
BOLTDIR: bolts
|
||||
needs:
|
||||
- compile
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
include:
|
||||
- CFG: compile-gcc
|
||||
VALGRIND: 1
|
||||
- CFG: compile-clang-sanitizers
|
||||
VALGRIND: 0
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
bash -x .github/scripts/setup.sh
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y -qq lowdown
|
||||
pip install -U pip wheel poetry
|
||||
poetry self add poetry-plugin-export
|
||||
# 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
|
||||
# We're going to check BOLT quotes, so get the latest version
|
||||
git clone https://github.com/lightning/bolts.git ../${BOLTDIR}
|
||||
|
||||
- name: Download build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cln-${{ matrix.CFG }}.tar.bz2
|
||||
|
||||
- name: Check
|
||||
run: |
|
||||
tar -xaf cln-${{ matrix.CFG }}.tar.bz2
|
||||
eatmydata make -j $(nproc) check-units installcheck VALGRIND=${{ matrix.VALGRIND }}
|
||||
|
||||
check-fuzz:
|
||||
name: Run fuzz regression tests
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- prebuild
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
bash -x .github/scripts/setup.sh
|
||||
pip install -U pip wheel poetry
|
||||
poetry self add poetry-plugin-export
|
||||
# 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-debugbuild --enable-fuzzing --enable-address-sanitizer --enable-ub-sanitizer --disable-valgrind CC=clang
|
||||
make -j $(nproc) check-fuzz
|
||||
|
||||
integration:
|
||||
name: Test CLN ${{ matrix.name }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 120
|
||||
env:
|
||||
RUST_PROFILE: release # Has to match the one in the compile step
|
||||
PYTEST_OPTS: --timeout=1200
|
||||
needs:
|
||||
- compile
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- NAME: gcc
|
||||
CFG: compile-gcc
|
||||
TEST_DB_PROVIDER: sqlite3
|
||||
COMPILER: gcc
|
||||
TEST_NETWORK: regtest
|
||||
# While we're at it let's try to compile with clang
|
||||
- NAME: clang
|
||||
CFG: compile-clang
|
||||
TEST_DB_PROVIDER: sqlite3
|
||||
COMPILER: clang
|
||||
TEST_NETWORK: regtest
|
||||
# And of course we want to test postgres too
|
||||
- NAME: postgres
|
||||
CFG: compile-gcc
|
||||
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: compile-gcc
|
||||
COMPILER: gcc
|
||||
TEST_NETWORK: liquid-regtest
|
||||
TEST_DB_PROVIDER: sqlite3
|
||||
# And dual funding!
|
||||
- NAME: dual-fund
|
||||
CFG: compile-gcc
|
||||
TEST_DB_PROVIDER: sqlite3
|
||||
COMPILER: gcc
|
||||
TEST_NETWORK: regtest
|
||||
EXPERIMENTAL_DUAL_FUND: 1
|
||||
# And splicing!
|
||||
- NAME: splicing
|
||||
CFG: compile-gcc
|
||||
TEST_DB_PROVIDER: sqlite3
|
||||
COMPILER: gcc
|
||||
TEST_NETWORK: regtest
|
||||
EXPERIMENTAL_SPLICING: 1
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pip3 install --user pip wheel poetry
|
||||
poetry install
|
||||
|
||||
- name: Install bitcoind
|
||||
env:
|
||||
TEST_NETWORK: ${{ matrix.TEST_NETWORK }}
|
||||
run: .github/scripts/install-bitcoind.sh
|
||||
|
||||
- name: Download build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cln-${{ matrix.CFG }}.tar.bz2
|
||||
|
||||
- name: Unpack pre-built CLN
|
||||
env:
|
||||
CFG: ${{ matrix.CFG }}
|
||||
run: |
|
||||
tar -xaf cln-${CFG}.tar.bz2
|
||||
|
||||
- name: Switch network
|
||||
if: ${{ matrix.TEST_NETWORK == 'liquid-regtest' }}
|
||||
run: |
|
||||
# Loading the network from config.vars rather than the envvar is a terrible idea...
|
||||
sed -i 's/TEST_NETWORK=regtest/TEST_NETWORK=liquid-regtest/g' config.vars
|
||||
cat config.vars
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
COMPILER: ${{ matrix.COMPILER }}
|
||||
EXPERIMENTAL_DUAL_FUND: ${{ matrix.EXPERIMENTAL_DUAL_FUND }}
|
||||
EXPERIMENTAL_SPLICING: ${{ matrix.EXPERIMENTAL_SPLICING }}
|
||||
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 }}
|
||||
LIGHTNINGD_POSTGRES_NO_VACUUM: 1
|
||||
run: |
|
||||
env
|
||||
cat config.vars
|
||||
VALGRIND=0 poetry run eatmydata pytest tests/ -vvv -n ${PYTEST_PAR} ${PYTEST_OPTS}
|
||||
|
||||
integration-valgrind:
|
||||
name: Valgrind Test CLN ${{ matrix.name }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 120
|
||||
env:
|
||||
RUST_PROFILE: release # Has to match the one in the compile step
|
||||
CFG: compile-gcc
|
||||
PYTEST_OPTS: --test-group-random-seed=42 --timeout=1800
|
||||
needs:
|
||||
- compile
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- NAME: Valgrind (01/10)
|
||||
PYTEST_OPTS: --test-group=1 --test-group-count=10
|
||||
- NAME: Valgrind (02/10)
|
||||
PYTEST_OPTS: --test-group=2 --test-group-count=10
|
||||
- NAME: Valgrind (03/10)
|
||||
PYTEST_OPTS: --test-group=3 --test-group-count=10
|
||||
- NAME: Valgrind (04/10)
|
||||
PYTEST_OPTS: --test-group=4 --test-group-count=10
|
||||
- NAME: Valgrind (05/10)
|
||||
PYTEST_OPTS: --test-group=5 --test-group-count=10
|
||||
- NAME: Valgrind (06/10)
|
||||
PYTEST_OPTS: --test-group=6 --test-group-count=10
|
||||
- NAME: Valgrind (07/10)
|
||||
PYTEST_OPTS: --test-group=7 --test-group-count=10
|
||||
- NAME: Valgrind (08/10)
|
||||
PYTEST_OPTS: --test-group=8 --test-group-count=10
|
||||
- NAME: Valgrind (09/10)
|
||||
PYTEST_OPTS: --test-group=9 --test-group-count=10
|
||||
- NAME: Valgrind (10/10)
|
||||
PYTEST_OPTS: --test-group=10 --test-group-count=10
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -yyq valgrind
|
||||
pip3 install --user pip wheel poetry
|
||||
poetry install
|
||||
|
||||
- name: Install bitcoind
|
||||
run: .github/scripts/install-bitcoind.sh
|
||||
|
||||
- name: Download build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cln-compile-gcc.tar.bz2
|
||||
|
||||
- name: Unpack build
|
||||
run: tar -xvjf cln-compile-gcc.tar.bz2
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
SLOW_MACHINE: 1
|
||||
TEST_DEBUG: 1
|
||||
run: |
|
||||
VALGRIND=1 poetry run eatmydata 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:
|
||||
RUST_PROFILE: release
|
||||
SLOW_MACHINE: 1
|
||||
TEST_DEBUG: 1
|
||||
PYTEST_OPTS: --test-group-random-seed=42 --timeout=1800
|
||||
needs:
|
||||
- compile
|
||||
strategy:
|
||||
fail-fast: false
|
||||
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 -n 1
|
||||
- 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@v4
|
||||
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
bash -x .github/scripts/setup.sh
|
||||
set -e
|
||||
pip3 install --user wheel poetry
|
||||
poetry install --with dev --no-root
|
||||
|
||||
- name: Install bitcoind
|
||||
run: .github/scripts/install-bitcoind.sh
|
||||
|
||||
- name: Download build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cln-compile-clang-sanitizers.tar.bz2
|
||||
|
||||
- name: Unpack build
|
||||
run: tar -xvjf cln-compile-clang-sanitizers.tar.bz2
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
poetry run eatmydata pytest tests/ -vvv -n 2 ${PYTEST_OPTS} ${{ matrix.PYTEST_OPTS }}
|
||||
|
||||
update-docs-examples:
|
||||
name: Update examples in doc schemas (disabled temporarily!)
|
||||
if: false
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
env:
|
||||
VALGRIND: 0
|
||||
GENERATE_EXAMPLES: 1
|
||||
PYTEST_OPTS: --timeout=1200
|
||||
TEST_NETWORK: regtest
|
||||
needs:
|
||||
- compile
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
bash -x .github/scripts/setup.sh
|
||||
pip install -U pip wheel poetry
|
||||
poetry self add poetry-plugin-export
|
||||
poetry export -o /tmp/requirements.txt --without-hashes --with dev
|
||||
pip install -r /tmp/requirements.txt
|
||||
- name: Install bitcoind
|
||||
env:
|
||||
TEST_NETWORK: regtest
|
||||
run: .github/scripts/install-bitcoind.sh
|
||||
- name: Download build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cln-compile-gcc.tar.bz2
|
||||
- name: Unpack pre-built CLN
|
||||
run: |
|
||||
tar -xaf cln-compile-gcc.tar.bz2
|
||||
- name: Test
|
||||
run: |
|
||||
eatmydata make -j $(nproc) check-doc-examples
|
||||
|
||||
min-btc-support:
|
||||
name: Test minimum supported BTC v${{ matrix.MIN_BTC_VERSION }} with ${{ matrix.NAME }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 120
|
||||
env:
|
||||
RUST_PROFILE: release # Has to match the one in the compile step
|
||||
PYTEST_OPTS: --timeout=1200
|
||||
needs:
|
||||
- compile
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- NAME: clang
|
||||
CFG: compile-clang
|
||||
TEST_DB_PROVIDER: sqlite3
|
||||
COMPILER: clang
|
||||
TEST_NETWORK: regtest
|
||||
MIN_BTC_VERSION: '25.0'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pip3 install --user pip wheel poetry
|
||||
poetry install
|
||||
|
||||
- name: Download Bitcoin Core
|
||||
run: wget "https://bitcoincore.org/bin/bitcoin-core-${{ matrix.MIN_BTC_VERSION }}/bitcoin-${{ matrix.MIN_BTC_VERSION }}-x86_64-linux-gnu.tar.gz"
|
||||
|
||||
- name: Extract Bitcoin Core
|
||||
run: tar -xf "bitcoin-${{ matrix.MIN_BTC_VERSION }}-x86_64-linux-gnu.tar.gz"
|
||||
|
||||
- name: Move Bitcoin Core Binaries
|
||||
run: sudo mv bitcoin-${{ matrix.MIN_BTC_VERSION }}/bin/* /usr/local/bin/
|
||||
|
||||
- name: Clean Up Downloaded Bitcoin
|
||||
run: rm -rf "bitcoin-${{ matrix.MIN_BTC_VERSION }}-x86_64-linux-gnu.tar.gz" "bitcoin-${{ matrix.MIN_BTC_VERSION }}"
|
||||
|
||||
- name: Download build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cln-${{ matrix.CFG }}.tar.bz2
|
||||
|
||||
- name: Unpack pre-built CLN
|
||||
env:
|
||||
CFG: ${{ matrix.CFG }}
|
||||
run: |
|
||||
tar -xaf cln-${CFG}.tar.bz2
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
COMPILER: ${{ matrix.COMPILER }}
|
||||
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 }}
|
||||
LIGHTNINGD_POSTGRES_NO_VACUUM: 1
|
||||
run: |
|
||||
env
|
||||
cat config.vars
|
||||
VALGRIND=0 poetry run eatmydata pytest tests/ -vvv -n ${PYTEST_PAR} ${PYTEST_OPTS}
|
||||
|
||||
check-flake:
|
||||
name: Check Nix Flake
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
fail-fast: true
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Check Nix flake inputs
|
||||
uses: DeterminateSystems/flake-checker-action@v8
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@V27
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-24.05
|
||||
- name: Check flake
|
||||
run: nix flake check .?submodules=1#
|
||||
|
||||
gather:
|
||||
# A dummy task that depends on the full matrix of tests, and
|
||||
# signals successful completion. Used for the PR status to pass
|
||||
# before merging. Needs to run even if they failed!
|
||||
name: CI completion
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- integration
|
||||
- check-units
|
||||
- integration-valgrind
|
||||
- integration-sanitizers
|
||||
- min-btc-support
|
||||
- check-flake
|
||||
if: ${{ always() }}
|
||||
steps:
|
||||
- name: Complete
|
||||
env:
|
||||
JOB_NAMES: "INTEGRATION CHECK_UNITS VALGRIND SANITIZERS BTC FLAKE"
|
||||
INTEGRATION: ${{ needs.integration.result }}
|
||||
CHECK_UNITS: ${{ needs['check-units'].result }}
|
||||
VALGRIND: ${{ needs['integration-valgrind'].result }}
|
||||
SANITIZERS: ${{ needs['integration-sanitizers'].result }}
|
||||
DOCS: ${{ needs['update-docs-examples'].result }}
|
||||
BTC: ${{ needs['min-btc-support'].result }}
|
||||
FLAKE: ${{ needs['check-flake'].result }}
|
||||
run: |
|
||||
failed=""
|
||||
for name in $JOB_NAMES; do
|
||||
result="${!name}"
|
||||
echo "$name: $result"
|
||||
if [[ "$result" != "success" ]]; then
|
||||
failed="yes"
|
||||
fi
|
||||
done
|
||||
if [[ "$failed" == "yes" ]]; then
|
||||
echo "One or more required jobs failed"
|
||||
exit 1
|
||||
fi
|
||||
30
.github/workflows/crate-io.yml
vendored
30
.github/workflows/crate-io.yml
vendored
@ -1,30 +0,0 @@
|
||||
---
|
||||
name: "Release Rust 🦀"
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
|
||||
jobs:
|
||||
release_rust:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: arduino/setup-protoc@v3
|
||||
- uses: katyo/publish-crates@v2
|
||||
with:
|
||||
path: './cln-rpc'
|
||||
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
ignore-unpublished-changes: true
|
||||
- uses: katyo/publish-crates@v2
|
||||
with:
|
||||
path: './plugins'
|
||||
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
ignore-unpublished-changes: true
|
||||
- uses: katyo/publish-crates@v2
|
||||
with:
|
||||
path: './cln-grpc'
|
||||
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
ignore-unpublished-changes: true
|
||||
118
.github/workflows/docker-release.yml
vendored
118
.github/workflows/docker-release.yml
vendored
@ -1,118 +0,0 @@
|
||||
name: Build and push multi-platform docker images
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v[0-9]+.[0-9]+'
|
||||
- 'v[0-9]+.[0-9]+.[0-9]+'
|
||||
- 'v[0-9]+.[0-9]+[0-9a-z]+'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Release version'
|
||||
required: true
|
||||
|
||||
repository-name:
|
||||
description: 'Docker repository name'
|
||||
default: 'elementsproject'
|
||||
required: false
|
||||
|
||||
platforms-to-build:
|
||||
description: 'List of platforms to build'
|
||||
default: 'linux/amd64,linux/arm64,linux/arm/v7'
|
||||
required: false
|
||||
|
||||
push-latest:
|
||||
description: 'Push the latest tag also?'
|
||||
default: 'false'
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }} # Ensures the branch triggering the workflow is checked out
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Set up values
|
||||
id: set-values
|
||||
run: |
|
||||
if [[ "${{ github.event.inputs.version }}" != "" ]]; then
|
||||
echo "Input version provided"
|
||||
VERSION=${{ github.event.inputs.version }}
|
||||
elif [[ ${{ github.ref_type }} == "tag" ]]; then
|
||||
echo "This is a tag event"
|
||||
VERSION=${{ github.ref_name }}
|
||||
else
|
||||
echo "No version provided and no tag found."
|
||||
exit 1
|
||||
fi
|
||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||
|
||||
if [[ "${{ github.event.inputs.repository-name }}" != "" ]]; then
|
||||
REPONAME=${{ github.event.inputs.repository-name }}
|
||||
else
|
||||
REPONAME="elementsproject"
|
||||
fi
|
||||
echo "REPONAME=$REPONAME" >> $GITHUB_ENV
|
||||
|
||||
if [[ "${{ github.event.inputs.platforms-to-build }}" != "" ]]; then
|
||||
PLATFORMS=${{ github.event.inputs.platforms-to-build }}
|
||||
else
|
||||
PLATFORMS="linux/amd64,linux/arm64,linux/arm/v7"
|
||||
fi
|
||||
echo "PLATFORMS=$PLATFORMS" >> $GITHUB_ENV
|
||||
|
||||
if [[ "${{ github.event.inputs.push-latest }}" == "true" ]] ||
|
||||
([[ "${{ github.ref_type }}" == "tag" ]] && [[ ! "$VERSION" =~ rc ]]); then
|
||||
echo "Latest true"
|
||||
PUSHLATEST="true"
|
||||
else
|
||||
echo "Latest false"
|
||||
PUSHLATEST="false"
|
||||
fi
|
||||
echo "PUSHLATEST=$PUSHLATEST" >> $GITHUB_ENV
|
||||
|
||||
TAGS="$REPONAME/lightningd:$VERSION"
|
||||
if [[ "$PUSHLATEST" == "true" ]]; then
|
||||
TAGS="$TAGS,$REPONAME/lightningd:latest"
|
||||
fi
|
||||
echo "TAGS=$TAGS" >> $GITHUB_ENV
|
||||
|
||||
- name: Print GitHub Ref Values
|
||||
run: |
|
||||
echo "GITHUB REF TYPE: ${{ github.ref_type }}"
|
||||
echo "GITHUB REF NAME: ${{ github.ref_name }}"
|
||||
echo "EVENT INPUT VERSION: ${{ github.event.inputs.version }}"
|
||||
echo "EVENT INPUT REPO: ${{ github.event.inputs.repository-name }}"
|
||||
echo "EVENT INPUT PLATFORMS: ${{ github.event.inputs.platforms-to-build }}"
|
||||
echo "EVENT INPUT PUSH LATEST: ${{ github.event.inputs.push-latest }}"
|
||||
echo "ENV VERSION: ${{ env.VERSION }}"
|
||||
echo "ENV REPO NAME: ${{ env.REPONAME }}"
|
||||
echo "ENV PLATFORMS: ${{ env.PLATFORMS }}"
|
||||
echo "ENV PUSH LATEST: ${{ env.PUSHLATEST }}"
|
||||
echo "ENV TAGS: ${{ env.TAGS }}"
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
tags: ${{ env.TAGS }}
|
||||
34
.github/workflows/docker.yml
vendored
34
.github/workflows/docker.yml
vendored
@ -1,34 +0,0 @@
|
||||
name: Docker packaging
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'basedon-*'
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Environment variables
|
||||
run: env
|
||||
-
|
||||
name: Create images
|
||||
env:
|
||||
DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }}
|
||||
DOCKERHUB_PASS: ${{ secrets.DOCKERHUB_PASS }}
|
||||
DOCKERHUB_REPO: ${{ vars.DOCKERHUB_REPO }}
|
||||
shell: bash
|
||||
run: |
|
||||
LATEST_TAG=${GITHUB_REF#refs/tags/}
|
||||
LATEST_TAG=${LATEST_TAG:8} #trim "basedon-" from tag
|
||||
echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USER" --password-stdin
|
||||
docker buildx create --use
|
||||
DOCKER_BUILDX_OPTS="--platform linux/amd64,linux/arm64,linux/arm/v7 --push"
|
||||
docker buildx build $DOCKER_BUILDX_OPTS -t $DOCKERHUB_REPO:$LATEST_TAG .
|
||||
62
.github/workflows/macos.yaml
vendored
62
.github/workflows/macos.yaml
vendored
@ -1,62 +0,0 @@
|
||||
---
|
||||
name: Mac OS pytest
|
||||
on:
|
||||
pull_request:
|
||||
jobs:
|
||||
smoke-test:
|
||||
name: Smoke Test macOS
|
||||
runs-on: macos-14
|
||||
timeout-minutes: 120
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
bitcoind-version: ["27.1"]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download Bitcoin ${{ matrix.bitcoind-version }} & install binaries
|
||||
run: |
|
||||
export BITCOIND_VERSION=${{ matrix.bitcoind-version }}
|
||||
export TARGET_ARCH="arm64-apple-darwin"
|
||||
|
||||
wget https://bitcoincore.org/bin/bitcoin-core-${BITCOIND_VERSION}/bitcoin-${BITCOIND_VERSION}-${TARGET_ARCH}.tar.gz
|
||||
tar -xzf bitcoin-${BITCOIND_VERSION}-${TARGET_ARCH}.tar.gz
|
||||
sudo mv bitcoin-${BITCOIND_VERSION}/bin/* /usr/local/bin
|
||||
rm -rf bitcoin-${BITCOIND_VERSION}-${TARGET_ARCH}.tar.gz bitcoin-${BITCOIND_VERSION}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
export PATH="/usr/local/opt:/Users/runner/.local/bin:/opt/homebrew/bin/python3.10/bin:$PATH"
|
||||
|
||||
brew install gnu-sed python@3.10 autoconf automake libtool protobuf
|
||||
python3.10 -m pip install -U --user poetry==1.8.0 wheel pip mako
|
||||
python3.10 -m poetry install
|
||||
|
||||
- name: Build and install CLN
|
||||
run: |
|
||||
export CPATH=/opt/homebrew/include
|
||||
export LIBRARY_PATH=/opt/homebrew/lib
|
||||
|
||||
python3.10 -m poetry run ./configure --disable-valgrind --disable-compat
|
||||
python3.10 -m poetry run make
|
||||
|
||||
- name: Start bitcoind in regtest mode
|
||||
run: |
|
||||
bitcoind -regtest -daemon
|
||||
sleep 5
|
||||
|
||||
- name: Generate initial block
|
||||
run: |
|
||||
bitcoin-cli -regtest createwallet default_wallet
|
||||
bitcoin-cli -regtest generatetoaddress 1 $(bitcoin-cli -regtest getnewaddress)
|
||||
sleep 2
|
||||
|
||||
- name: Start CLN in regtest mode
|
||||
run: |
|
||||
lightningd/lightningd --network=regtest --log-file=/tmp/l1.log --daemon
|
||||
sleep 5
|
||||
|
||||
- name: Verify CLN is running
|
||||
run: |
|
||||
cli/lightning-cli --regtest getinfo
|
||||
101
.github/workflows/pypi.yml
vendored
101
.github/workflows/pypi.yml
vendored
@ -1,101 +0,0 @@
|
||||
name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v[0-9]+.[0-9]+'
|
||||
- 'v[0-9]+.[0-9]+.[0-9]+'
|
||||
- 'v[0-9]+.[0-9]+[0-9a-z]+'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dist-location:
|
||||
description: 'Distribution location (test/prod)'
|
||||
default: 'test'
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: Build and publish ${{ matrix.package }} 🐍
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 120
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
include:
|
||||
- PACKAGE: pyln-client
|
||||
WORKDIR: contrib/pyln-client
|
||||
- PACKAGE: pyln-testing
|
||||
WORKDIR: contrib/pyln-testing
|
||||
- PACKAGE: pyln-proto
|
||||
WORKDIR: contrib/pyln-proto
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# Need to fetch entire history in order to locate the version tag
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check version tag
|
||||
run: >-
|
||||
git describe --tags --always --dirty=-modded --abbrev=7
|
||||
|
||||
- name: Setup Version
|
||||
env:
|
||||
WORKDIR: ${{ matrix.WORKDIR }}
|
||||
run: |
|
||||
echo "VERSION=$(git describe --tags --abbrev=0).post$(git describe --tags --abbrev=1 | awk -F "-" '{print $2}')" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up values
|
||||
id: set-values
|
||||
run: |
|
||||
if [[ "${{ github.event.inputs.dist-location }}" != "" ]]; then
|
||||
DISTLOCATION=${{ github.event.inputs.dist-location }}
|
||||
elif [[ "${{ github.ref_type }}" == "tag" ]] && [[ ! "${{ github.ref_name }}" =~ rc ]]; then
|
||||
DISTLOCATION="prod"
|
||||
else
|
||||
DISTLOCATION="test"
|
||||
fi
|
||||
echo "DISTLOCATION=$DISTLOCATION" >> $GITHUB_OUTPUT
|
||||
echo "EVENT DISTLOCATION: ${{ github.event.inputs.dist-location }}"
|
||||
echo "DISTRIBUTION LOCATION: $DISTLOCATION"
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install Poetry
|
||||
run: |
|
||||
curl -sSL https://install.python-poetry.org | python3 -
|
||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
echo "PATH=$HOME/.local/bin:$PATH"
|
||||
|
||||
- name: Publish distribution 📦 to Test PyPI
|
||||
if: github.repository == 'ElementsProject/lightning' && steps.set-values.outputs.DISTLOCATION == 'test'
|
||||
env:
|
||||
POETRY_PYPI_TOKEN_TESTPYPI: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
||||
WORKDIR: ${{ matrix.WORKDIR }}
|
||||
run: |
|
||||
echo "POETRY VERSION TEST: $(poetry --version)"
|
||||
echo "Pyln VERSION: $VERSION"
|
||||
cd ${{ env.WORKDIR }}
|
||||
python3 -m pip config set global.timeout 150
|
||||
poetry config repositories.testpypi https://test.pypi.org/legacy/
|
||||
make upgrade-version NEW_VERSION=$VERSION
|
||||
poetry build --no-interaction
|
||||
poetry publish --repository testpypi --no-interaction --skip-existing
|
||||
|
||||
- name: Publish distribution 📦 to PyPI
|
||||
if: github.repository == 'ElementsProject/lightning' && steps.set-values.outputs.DISTLOCATION == 'prod'
|
||||
env:
|
||||
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }}
|
||||
WORKDIR: ${{ matrix.WORKDIR }}
|
||||
run: |
|
||||
echo "POETRY VERSION PUBLISH: $(poetry --version)"
|
||||
cd ${{ env.WORKDIR }}
|
||||
export VERSION=$(git describe --tags --abbrev=0)
|
||||
echo "Pyln VERSION: $VERSION"
|
||||
make upgrade-version NEW_VERSION=$VERSION
|
||||
python3 -m pip config set global.timeout 150
|
||||
poetry build --no-interaction
|
||||
poetry publish --no-interaction
|
||||
51
.github/workflows/rdme-docs-sync.yml
vendored
51
.github/workflows/rdme-docs-sync.yml
vendored
@ -1,51 +0,0 @@
|
||||
name: ReadMe Sync
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
paths:
|
||||
- 'doc/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
rdme-docs-sync:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out repo 📚
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Sync doc/getting-started/ 🚀
|
||||
uses: readmeio/rdme@v8
|
||||
env:
|
||||
README_API_KEY: ${{ secrets.README_API_KEY }}
|
||||
with:
|
||||
rdme: docs doc/getting-started --key=${{ env.README_API_KEY }} --version=1
|
||||
|
||||
- name: Sync doc/beginners-guide/ 🚀
|
||||
uses: readmeio/rdme@v8
|
||||
env:
|
||||
README_API_KEY: ${{ secrets.README_API_KEY }}
|
||||
with:
|
||||
rdme: docs doc/beginners-guide --key=${{ env.README_API_KEY }} --version=1
|
||||
|
||||
- name: Sync doc/node-operators-guide/ 🚀
|
||||
uses: readmeio/rdme@v8
|
||||
env:
|
||||
README_API_KEY: ${{ secrets.README_API_KEY }}
|
||||
with:
|
||||
rdme: docs doc/node-operators-guide --key=${{ env.README_API_KEY }} --version=1
|
||||
|
||||
- name: Sync doc/developers-guide/ 🚀
|
||||
uses: readmeio/rdme@v8
|
||||
env:
|
||||
README_API_KEY: ${{ secrets.README_API_KEY }}
|
||||
with:
|
||||
rdme: docs doc/developers-guide --key=${{ env.README_API_KEY }} --version=1
|
||||
|
||||
- name: Sync doc/contributing-to-core-lightning/ 🚀
|
||||
uses: readmeio/rdme@v8
|
||||
env:
|
||||
README_API_KEY: ${{ secrets.README_API_KEY }}
|
||||
with:
|
||||
rdme: docs doc/contribute-to-core-lightning --key=${{ env.README_API_KEY }} --version=1
|
||||
43
.github/workflows/readme-rpc-sync.yml
vendored
43
.github/workflows/readme-rpc-sync.yml
vendored
@ -1,43 +0,0 @@
|
||||
name: ReadMe RPC Sync
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
paths:
|
||||
- 'doc/schemas/*.json'
|
||||
- 'doc/*.1.md'
|
||||
- 'doc/*.5.md'
|
||||
- 'doc/*.8.md'
|
||||
- 'doc/lightningd-*.7.md'
|
||||
- 'doc/reckless.7.md'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
rdme-rpc-sync:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.9
|
||||
|
||||
- name: Install python modules
|
||||
run: |
|
||||
python -m pip install requests mako grpcio-tools
|
||||
|
||||
- name: Install dependencies
|
||||
run: bash -x .github/scripts/setup.sh
|
||||
|
||||
- name: Build (including rpc .md files)
|
||||
run: |
|
||||
./configure --enable-debugbuild
|
||||
make -j $(nproc)
|
||||
|
||||
- name: Set environment variable and run
|
||||
env:
|
||||
README_API_KEY: ${{ secrets.README_API_KEY }}
|
||||
run: python .github/scripts/sync-rpc-cmds.py
|
||||
191
.github/workflows/release.yml
vendored
191
.github/workflows/release.yml
vendored
@ -1,191 +0,0 @@
|
||||
---
|
||||
# https://docs.corelightning.org/docs/release-checklist
|
||||
name: "Release 🚀"
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v[0-9]+.[0-9]+'
|
||||
- 'v[0-9]+.[0-9]+.[0-9]+'
|
||||
- 'v[0-9]+.[0-9]+[0-9a-z]+'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Release version'
|
||||
required: true
|
||||
create_release:
|
||||
description: Create a draft release
|
||||
default: no
|
||||
type: choice
|
||||
options:
|
||||
- yes
|
||||
- no
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check
|
||||
outputs:
|
||||
version: ${{ steps.capture.outputs.version }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Determine version
|
||||
run: |
|
||||
if [[ "${{ github.event.inputs.version }}" != "" ]]; then
|
||||
VERSION="${{ github.event.inputs.version }}"
|
||||
elif [ "${{ github.ref_type }}" == "tag" ]; then
|
||||
VERSION="${{ github.ref_name }}"
|
||||
else
|
||||
echo "No release version provided and no tag found."
|
||||
exit 1
|
||||
fi
|
||||
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
|
||||
echo "Determined version: $VERSION"
|
||||
|
||||
- name: Validate release
|
||||
run: tools/check-release.sh --version=${VERSION}
|
||||
|
||||
- name: Catpure version output
|
||||
id: capture
|
||||
run: echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
releases:
|
||||
name: Releases
|
||||
needs: check
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false # Let each build finish.
|
||||
matrix:
|
||||
target:
|
||||
- 'bin-Fedora'
|
||||
- 'bin-Ubuntu-focal'
|
||||
- 'bin-Ubuntu-jammy'
|
||||
- 'bin-Ubuntu-noble'
|
||||
steps:
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-tags: true
|
||||
|
||||
# tools/build-release.sh requires lowdown
|
||||
- name: Prepare base environment
|
||||
run: |
|
||||
sudo apt-get install -y lowdown
|
||||
./configure
|
||||
|
||||
- name: Build environment setup
|
||||
run: |
|
||||
distribution=$(echo ${{ matrix.target }} | cut -d'-' -f3)
|
||||
echo "Building base image for ${distribution}"
|
||||
sudo docker run --rm -v $(pwd):/build ubuntu:${distribution} bash -c "\
|
||||
apt-get update && \
|
||||
apt-get install -y debootstrap && \
|
||||
debootstrap ${distribution} /build/${distribution}"
|
||||
sudo tar -C ${distribution} -c . | docker import - ${distribution}
|
||||
|
||||
# Build Docker image
|
||||
docker build -t cl-repro-${distribution} - < contrib/reprobuild/Dockerfile.${distribution}
|
||||
if: contains(matrix.target, 'Ubuntu')
|
||||
|
||||
- name: Build release
|
||||
run: tools/build-release.sh ${{ matrix.target }}
|
||||
|
||||
- name: Upload target artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: release/
|
||||
name: ${{ matrix.target }}
|
||||
if-no-files-found: error
|
||||
|
||||
artifact:
|
||||
name: Construct release artifact
|
||||
needs:
|
||||
- check
|
||||
- releases
|
||||
env:
|
||||
version: ${{ needs.check.outputs.version }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Merge artifacts
|
||||
uses: actions/upload-artifact/merge@v4
|
||||
with:
|
||||
name: c-lightning-${{ env.version }}
|
||||
pattern: bin-*
|
||||
delete-merged: true
|
||||
|
||||
release:
|
||||
name: Sign and prepare release draft
|
||||
needs:
|
||||
- check
|
||||
- artifact
|
||||
env:
|
||||
version: ${{ needs.check.outputs.version }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-tags: true
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: c-lightning-${{ env.version }}
|
||||
path: release/
|
||||
|
||||
- name: Import GPG keys
|
||||
id: gpg
|
||||
uses: crazy-max/ghaction-import-gpg@v6
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
passphrase: ${{ secrets.GPG_PASSPHRASE }}
|
||||
trust_level: 5
|
||||
|
||||
- name: Set default GPG key
|
||||
run: echo "default-key ${{ steps.gpg.outputs.keyid }}" >> ~/.gnupg/gpg.conf
|
||||
|
||||
- name: Sign release
|
||||
run: |
|
||||
sudo apt-get install -y lowdown
|
||||
./configure
|
||||
tools/build-release.sh --without-zip sign
|
||||
mv release/SHA256SUMS.asc${{ steps.gpg.outputs.keyid }} release/SHA256SUMS.asc
|
||||
|
||||
- name: Upload signed artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: c-lightning-${{ env.version }}
|
||||
overwrite: true
|
||||
path: release/
|
||||
|
||||
- name: Determine release data
|
||||
id: release_data
|
||||
run: |
|
||||
VERSION=${{ env.version }}
|
||||
CHANGELOG_VERSION=${VERSION#v}
|
||||
echo "CHANGELOG_VERSION=$CHANGELOG_VERSION"
|
||||
echo "changelog_version=$CHANGELOG_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
CHANGELOG_TITLE=$(grep "## \[${CHANGELOG_VERSION}\]" CHANGELOG.md)
|
||||
echo "CHANGELOG_TITLE=$CHANGELOG_TITLE"
|
||||
echo "changelog_title=$CHANGELOG_TITLE" >> "$GITHUB_OUTPUT"
|
||||
|
||||
RELEASE_TITLE=$(echo $CHANGELOG_TITLE | cut -d'"' -f2)
|
||||
echo "RELEASE_TITLE=$RELEASE_TITLE"
|
||||
echo "release_title=$RELEASE_TITLE" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Prepare release draft
|
||||
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.create_release == 'yes')
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
name: "${{ env.version }} ${{ steps.release_data.outputs.release_title }}"
|
||||
tag_name: ${{ env.version }}
|
||||
draft: true
|
||||
prerelease: contains(env.version, "-rc")
|
||||
files: release/*
|
||||
fail_on_unmatched_files: true
|
||||
113
.github/workflows/repro.yml
vendored
113
.github/workflows/repro.yml
vendored
@ -1,113 +0,0 @@
|
||||
---
|
||||
# https://docs.corelightning.org/docs/repro
|
||||
name: Repro Build Nightly
|
||||
on:
|
||||
# 05:00 Berlin, 03:00 UTC, 23:00 New York, 20:00 Los Angeles
|
||||
schedule:
|
||||
- cron: "0 3 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
ubuntu:
|
||||
name: "Ubuntu repro build: ${{ matrix.version }}"
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
fail-fast: false # Let each build finish.
|
||||
matrix:
|
||||
version: ['focal', 'jammy', 'noble']
|
||||
steps:
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build environment setup - ${{ matrix.version }}
|
||||
run: |
|
||||
echo "Building base image for ${{ matrix.version }}"
|
||||
echo "STEP=Build environment setup" >> "$GITHUB_ENV"
|
||||
sudo docker run --rm -v $(pwd):/build ubuntu:${{ matrix.version }} bash -c "\
|
||||
apt-get update && \
|
||||
apt-get install -y debootstrap && \
|
||||
debootstrap ${{ matrix.version }} /build/${{ matrix.version }}"
|
||||
sudo tar -C ${{ matrix.version }} -c . | docker import - ${{ matrix.version }}
|
||||
|
||||
- name: Builder image setup - ${{ matrix.version }}
|
||||
run: |
|
||||
echo "STEP=Builder image setup" >> "$GITHUB_ENV"
|
||||
docker build -t cl-repro-${{ matrix.version }} - < contrib/reprobuild/Dockerfile.${{ matrix.version }}
|
||||
|
||||
- name: Build reproducible image and store Git state - ${{ matrix.version }}
|
||||
run: |
|
||||
echo "STEP=Build reproducible image and store Git state" >> "$GITHUB_ENV"
|
||||
|
||||
# Create release directory.
|
||||
mkdir $GITHUB_WORKSPACE/release
|
||||
|
||||
# Perform the repro build.
|
||||
docker run --name cl-build -v $GITHUB_WORKSPACE:/repo -e FORCE_MTIME=$(date +%F) -t cl-repro-${{ matrix.version }}
|
||||
|
||||
# Commit the image in order to inspect the build later.
|
||||
docker commit cl-build cl-repro
|
||||
|
||||
# Inspect the version.
|
||||
docker run --rm -v $GITHUB_WORKSPACE:/repo -t cl-repro bash -c "make version > /repo/release/version.txt"
|
||||
|
||||
# Inspect the Git tree state.
|
||||
docker run --rm -v $GITHUB_WORKSPACE:/repo -t cl-repro bash -c "\
|
||||
git --no-pager status > /repo/release/git.log && \
|
||||
git --no-pager diff >> /repo/release/git.log"
|
||||
|
||||
# Change permissions on the release files for access by the runner environment.
|
||||
sudo chown -R runner $GITHUB_WORKSPACE/release
|
||||
|
||||
- name: Assert clean version - ${{ matrix.version }}
|
||||
run: |
|
||||
echo "STEP=Assert clean version" >> "$GITHUB_ENV"
|
||||
echo 'Version:'
|
||||
cat release/version.txt
|
||||
echo -e
|
||||
|
||||
releasefile=$(ls release/clightning-*)
|
||||
echo 'Release file:'
|
||||
ls -al release/clightning-*
|
||||
echo -e
|
||||
if [ -n "$(cat release/version.txt | sed -n '/-modded/p')" ] || \
|
||||
[ -n "$(echo $releasefile | sed -n '/-modded/p')" ]; then
|
||||
echo "Git Status and Diff:"
|
||||
cat release/git.log
|
||||
echo -e
|
||||
echo 'Error: release modded / dirty tree.'
|
||||
exit 1
|
||||
else
|
||||
echo 'Success! Clean release.'
|
||||
fi
|
||||
|
||||
- name: Upload release artifact - ${{ matrix.version }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-${{ matrix.version }}
|
||||
path: release
|
||||
retention-days: 3 # Automatically delete after 3 days
|
||||
|
||||
- name: Send email on failure
|
||||
if: ${{ failure() }}
|
||||
uses: dawidd6/action-send-mail@v3
|
||||
with:
|
||||
server_address: smtp.gmail.com
|
||||
server_port: 587
|
||||
username: ${{ secrets.EMAIL_USERNAME }}
|
||||
password: ${{ secrets.EMAIL_PASSWORD }}
|
||||
from: ${{ secrets.EMAIL_USERNAME }}
|
||||
to: ${{ vars.DISTRIBUTION_LIST }}
|
||||
subject: "CI Failure: Step ${{ env.STEP }} failed for distro ${{ matrix.version }}"
|
||||
convert_markdown: true
|
||||
html_body: |
|
||||
<html>
|
||||
<body>
|
||||
<p>GitHub Workflow ${{ github.workflow }} Failed! For more details, click on the action below.</p>
|
||||
<strong>Failure Details:</strong><br/>
|
||||
<strong>Event: </strong>${{ github.event_name }}<br/>
|
||||
<strong>Job: </strong>${{ github.job }}<br/>
|
||||
<strong>Distro: </strong>${{ matrix.version }}<br/>
|
||||
<strong>Step: </strong>${{ env.STEP }}<br/>
|
||||
<strong>Action: </strong><a href="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}">${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}</a><br/>
|
||||
</body>
|
||||
</html>
|
||||
76
.gitignore
vendored
76
.gitignore
vendored
@ -9,96 +9,32 @@
|
||||
*.dSYM
|
||||
*.rej
|
||||
*.pyc
|
||||
*.tmp
|
||||
libccan.a
|
||||
.cppcheck-suppress
|
||||
.mypy_cache
|
||||
TAGS
|
||||
tags
|
||||
ccan/tools/configurator/configurator
|
||||
ccan/ccan/cdump/tools/cdump-enumstr
|
||||
*_gen.c
|
||||
*_gen.h
|
||||
gen_*.c
|
||||
gen_*.h
|
||||
wire/gen_*_csv
|
||||
gen_*
|
||||
cli/lightning-cli
|
||||
tools/check-bolt
|
||||
coverage
|
||||
ccan/config.h
|
||||
__pycache__
|
||||
config.vars
|
||||
monkeytype.sqlite3
|
||||
|
||||
# Ignore some generated binaries
|
||||
*/test/run-*
|
||||
!*/test/run-*.c
|
||||
*/test/exp-run-*
|
||||
!*/test/exp-run-*.c
|
||||
*/*/test/run-*
|
||||
!*/*/test/run-*.c
|
||||
external/libbacktrace-build/
|
||||
external/libbacktrace.a
|
||||
external/libbacktrace.la
|
||||
test/test_protocol
|
||||
test/test_sphinx
|
||||
tests/.pytest.restart
|
||||
tests/plugins/test_libplugin
|
||||
tests/fuzz/fuzz-*
|
||||
!tests/fuzz/fuzz-*.c
|
||||
gossip_store
|
||||
.pytest_cache
|
||||
tools/headerversions
|
||||
.tmp.lightningrfc/
|
||||
contrib/pylightning/build/
|
||||
contrib/pylightning/dist/
|
||||
contrib/pylightning/pylightning.egg-info/
|
||||
contrib/pyln-*/build/
|
||||
contrib/pyln-*/dist/
|
||||
contrib/pyln-*/pyln_*.egg-info/
|
||||
contrib/pyln-*/.eggs/
|
||||
contrib/pyln-*/pyln/*/__version__.py
|
||||
tests/plugins/test_selfdisable_after_getmanifest
|
||||
|
||||
# Ignore generated files
|
||||
devtools/features
|
||||
doc/schemas/sql.json
|
||||
doc/*.7.md
|
||||
doc/*.[1578]
|
||||
doc/reckless*.[1578]
|
||||
*_sqlgen.[ch]
|
||||
*_wiregen.[ch]
|
||||
*_printgen.[ch]
|
||||
*_gettextgen.po
|
||||
tests/node_pb2.py
|
||||
tests/node_pb2_grpc.py
|
||||
tests/primitives_pb2.py
|
||||
tests/primitives_pb2_grpc.py
|
||||
tests/autogenerate-examples-status.log
|
||||
tests/autogenerate-examples.json
|
||||
tests/autogenerate-examples-repeat.log
|
||||
|
||||
# Ignore unrelated stuff
|
||||
.DS_Store
|
||||
.gdb_history
|
||||
.python-version
|
||||
compile_commands.json
|
||||
|
||||
# Rust targets
|
||||
target
|
||||
plugins/cln-grpc
|
||||
plugins/clnrest
|
||||
|
||||
# Build directories
|
||||
bionic/
|
||||
focal/
|
||||
jammy/
|
||||
noble/
|
||||
release/
|
||||
.vscode/
|
||||
.cache/
|
||||
|
||||
# Ignore release verification Sha256Sums
|
||||
SHA256SUMS-*
|
||||
doc/.doc_version
|
||||
autogenerate-examples-status.log
|
||||
|
||||
# Ignore nix outputs
|
||||
result
|
||||
result-[0-9]*
|
||||
tests/plugins/channeld_fakenet
|
||||
|
||||
@ -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_COMMIT_SHA || true
|
||||
https://api.github.com/repos/ElementsProject/lightning/statuses/$CI_BUILD_REF || 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_JOB_ID.", "context": "gitlab-ci"}' https://api.github.com/repos/ElementsProject/lightning/statuses/$CI_COMMIT_SHA || 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_BUILD_ID.", "context": "gitlab-ci"}' https://api.github.com/repos/ElementsProject/lightning/statuses/$CI_BUILD_REF || 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_COMMIT_SHA || 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_BUILD_REF || true
|
||||
|
||||
10
.gitmodules
vendored
10
.gitmodules
vendored
@ -1,6 +1,9 @@
|
||||
[submodule "daemon/jsmn"]
|
||||
path = external/jsmn
|
||||
url = https://github.com/zserge/jsmn
|
||||
[submodule "bitcoin/libbase58"]
|
||||
path = external/libbase58
|
||||
url = https://github.com/bitcoin/libbase58.git
|
||||
[submodule "libsodium"]
|
||||
path = external/libsodium
|
||||
url = https://github.com/jedisct1/libsodium.git
|
||||
@ -11,10 +14,3 @@
|
||||
path = external/libwally-core
|
||||
url = https://github.com/ElementsProject/libwally-core.git
|
||||
ignore = dirty
|
||||
[submodule "external/gheap"]
|
||||
path = external/gheap
|
||||
url = https://github.com/valyala/gheap
|
||||
[submodule "external/lowdown"]
|
||||
path = external/lowdown
|
||||
url = https://github.com/kristapsdz/lowdown.git
|
||||
ignore = dirty
|
||||
|
||||
13584
.msggen.json
13584
.msggen.json
File diff suppressed because it is too large
Load Diff
@ -1,13 +0,0 @@
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.8.0
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
args: [ --diff ]
|
||||
exclude: "contrib/pyln-grpc-proto/pyln/grpc/(primitives|node)_pb2(|_grpc).py"
|
||||
# Run the formatter.
|
||||
- id: ruff-format
|
||||
args: [ --diff ]
|
||||
exclude: "contrib/pyln-grpc-proto/pyln/grpc/(primitives|node)_pb2(|_grpc).py"
|
||||
42
.travis.yml
Normal file
42
.travis.yml
Normal file
@ -0,0 +1,42 @@
|
||||
language: c
|
||||
dist: xenial
|
||||
sudo: false
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- python3-pip
|
||||
- libsqlite3-dev
|
||||
- shellcheck
|
||||
- cppcheck
|
||||
- valgrind
|
||||
- libomp-dev
|
||||
- gcc-4.8
|
||||
|
||||
env:
|
||||
- ARCH=64 SOURCE_CHECK_ONLY=true CDEBUGFLAGS="-std=gnu11 -g -fstack-protector -O3 -flto" LDFLAGS="-O3 -flto"
|
||||
# - VALGRIND=0 ARCH=32 DEVELOPER=1 COMPILER=gcc TEST_GROUP=1 TEST_GROUP_COUNT=2 SOURCE_CHECK_ONLY=false
|
||||
# - VALGRIND=0 ARCH=32 DEVELOPER=1 COMPILER=gcc TEST_GROUP=2 TEST_GROUP_COUNT=2 SOURCE_CHECK_ONLY=false
|
||||
- VALGRIND=0 ARCH=64 DEVELOPER=1 COMPILER=gcc SOURCE_CHECK_ONLY=false
|
||||
- VALGRIND=0 ARCH=64 DEVELOPER=0 COMPILER=gcc COMPAT=0 SOURCE_CHECK_ONLY=false
|
||||
- VALGRIND=1 ARCH=64 DEVELOPER=0 COMPILER=gcc TEST_GROUP=1 TEST_GROUP_COUNT=3 SOURCE_CHECK_ONLY=false
|
||||
- VALGRIND=1 ARCH=64 DEVELOPER=0 COMPILER=gcc TEST_GROUP=2 TEST_GROUP_COUNT=3 SOURCE_CHECK_ONLY=false
|
||||
- VALGRIND=1 ARCH=64 DEVELOPER=0 COMPILER=gcc TEST_GROUP=3 TEST_GROUP_COUNT=3 SOURCE_CHECK_ONLY=false
|
||||
- VALGRIND=0 ARCH=64 DEVELOPER=1 COMPILER=clang SOURCE_CHECK_ONLY=false
|
||||
- VALGRIND=0 ARCH=64 DEVELOPER=1 COMPILER=gcc-4.8 SOURCE_CHECK_ONLY=false
|
||||
- VALGRIND=1 ARCH=64 DEVELOPER=1 COMPILER=gcc TEST_GROUP=1 TEST_GROUP_COUNT=6 SOURCE_CHECK_ONLY=false
|
||||
- VALGRIND=1 ARCH=64 DEVELOPER=1 COMPILER=gcc TEST_GROUP=2 TEST_GROUP_COUNT=6 SOURCE_CHECK_ONLY=false
|
||||
- VALGRIND=1 ARCH=64 DEVELOPER=1 COMPILER=gcc TEST_GROUP=3 TEST_GROUP_COUNT=6 SOURCE_CHECK_ONLY=false
|
||||
- VALGRIND=1 ARCH=64 DEVELOPER=1 COMPILER=gcc TEST_GROUP=4 TEST_GROUP_COUNT=6 SOURCE_CHECK_ONLY=false
|
||||
- VALGRIND=1 ARCH=64 DEVELOPER=1 COMPILER=gcc TEST_GROUP=5 TEST_GROUP_COUNT=6 SOURCE_CHECK_ONLY=false
|
||||
- VALGRIND=1 ARCH=64 DEVELOPER=1 COMPILER=gcc TEST_GROUP=6 TEST_GROUP_COUNT=6 SOURCE_CHECK_ONLY=false
|
||||
cache:
|
||||
directories:
|
||||
- dependencies
|
||||
- external
|
||||
|
||||
script:
|
||||
.travis/build.sh
|
||||
44
.travis/build.sh
Executable file
44
.travis/build.sh
Executable file
@ -0,0 +1,44 @@
|
||||
#!/bin/bash -x
|
||||
set -e
|
||||
|
||||
CWD=$(pwd)
|
||||
export SLOW_MACHINE=1
|
||||
export CC=${COMPILER:-gcc}
|
||||
export DEVELOPER=${DEVELOPER:-1}
|
||||
export SOURCE_CHECK_ONLY=${SOURCE_CHECK_ONLY:-"false"}
|
||||
export COMPAT=${COMPAT:-1}
|
||||
export PATH=$CWD/dependencies/bin:"$HOME"/.local/bin:"$PATH"
|
||||
|
||||
mkdir -p dependencies/bin || true
|
||||
|
||||
# Download bitcoind and bitcoin-cli
|
||||
if [ ! -f dependencies/bin/bitcoind ]; then
|
||||
wget https://bitcoin.org/bin/bitcoin-core-0.17.1/bitcoin-0.17.1-x86_64-linux-gnu.tar.gz
|
||||
tar -xzf bitcoin-0.17.1-x86_64-linux-gnu.tar.gz
|
||||
mv bitcoin-0.17.1/bin/* dependencies/bin
|
||||
rm -rf bitcoin-0.17.1-x86_64-linux-gnu.tar.gz bitcoin-0.17.1
|
||||
fi
|
||||
|
||||
pyenv global 3.7
|
||||
pip3 install --user --quiet -r tests/requirements.txt
|
||||
pip3 install --quiet \
|
||||
pytest-test-groups==1.0.3
|
||||
|
||||
echo "Configuration which is going to be built:"
|
||||
echo -en 'travis_fold:start:script.1\\r'
|
||||
./configure CC="$CC"
|
||||
cat config.vars
|
||||
echo -en 'travis_fold:end:script.1\\r'
|
||||
|
||||
if [ "$SOURCE_CHECK_ONLY" == "false" ]; then
|
||||
echo -en 'travis_fold:start:script.2\\r'
|
||||
make -j3 > /dev/null
|
||||
echo -en 'travis_fold:end:script.2\\r'
|
||||
|
||||
echo -en 'travis_fold:start:script.3\\r'
|
||||
make check
|
||||
echo -en 'travis_fold:end:script.3\\r'
|
||||
else
|
||||
git clone https://github.com/lightningnetwork/lightning-rfc.git
|
||||
make check-source BOLTDIR=lightning-rfc
|
||||
fi
|
||||
3437
CHANGELOG.md
3437
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
3030
Cargo.lock
generated
3030
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
13
Cargo.toml
13
Cargo.toml
@ -1,13 +0,0 @@
|
||||
[profile.release]
|
||||
strip = "debuginfo"
|
||||
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"cln-rpc",
|
||||
"cln-grpc",
|
||||
"plugins",
|
||||
"plugins/grpc-plugin",
|
||||
"plugins/rest-plugin",
|
||||
"plugins/lsps-plugin",
|
||||
]
|
||||
382
Dockerfile
382
Dockerfile
@ -1,345 +1,105 @@
|
||||
# This Dockerfile is used by buildx to build ARM64, AMD64, and ARM32 Docker images from an AMD64 host.
|
||||
# To speed up the build process, we are cross-compiling rather than relying on QEMU.
|
||||
# There are four main stages:
|
||||
# * downloader: Downloads specific binaries needed for core lightning for each architecture.
|
||||
# * builder: Cross-compiles for each architecture.
|
||||
# * builder-python: Builds Python dependencies for wss-proxy with QEMU.
|
||||
# * final: Creates the runtime image.
|
||||
FROM alpine:3.7 as builder
|
||||
|
||||
ARG DEFAULT_TARGETPLATFORM="linux/amd64"
|
||||
ARG BASE_DISTRO="debian:bookworm-slim"
|
||||
|
||||
FROM --platform=$BUILDPLATFORM ${BASE_DISTRO} AS base-downloader
|
||||
RUN set -ex \
|
||||
&& apt-get update \
|
||||
&& apt-get install -qq --no-install-recommends ca-certificates dirmngr wget qemu-user-static binfmt-support
|
||||
|
||||
FROM base-downloader AS base-downloader-linux-amd64
|
||||
ENV TARBALL_ARCH_FINAL=x86_64-linux-gnu
|
||||
ENV DESCHASHPLUGIN_ARCH=linux-amd64
|
||||
ENV DESCHASHPLUGIN_HASH=deadc00c68fac80b2718d92f69bf06acd8fff646228d497bbb76a4f0a12ca217
|
||||
|
||||
FROM base-downloader AS base-downloader-linux-arm64
|
||||
ENV TARBALL_ARCH_FINAL=aarch64-linux-gnu
|
||||
ENV DESCHASHPLUGIN_ARCH=linux-arm64
|
||||
ENV DESCHASHPLUGIN_HASH=d48c3e5aede77bd9cb72d78689ce12c0327f624435cb0496b3eacb92df416363
|
||||
|
||||
FROM base-downloader AS base-downloader-linux-arm
|
||||
ENV TARBALL_ARCH_FINAL=arm-linux-gnueabihf
|
||||
ENV DESCHASHPLUGIN_ARCH=linux-arm
|
||||
ENV DESCHASHPLUGIN_HASH=f7df336c72dd1674bd18ff23862a410b6a9691a3e13752264dcffa0950e21c74
|
||||
|
||||
FROM base-downloader-${TARGETOS}-${TARGETARCH} AS downloader
|
||||
|
||||
RUN set -ex \
|
||||
&& apt-get update \
|
||||
&& apt-get install -qq --no-install-recommends ca-certificates dirmngr wget
|
||||
RUN apk add --no-cache \
|
||||
ca-certificates \
|
||||
autoconf \
|
||||
automake \
|
||||
build-base \
|
||||
libressl \
|
||||
libtool \
|
||||
gmp-dev \
|
||||
python \
|
||||
python-dev \
|
||||
python3 \
|
||||
sqlite-dev \
|
||||
wget \
|
||||
git \
|
||||
file \
|
||||
gnupg \
|
||||
swig \
|
||||
zlib-dev
|
||||
|
||||
WORKDIR /opt
|
||||
|
||||
|
||||
ENV BITCOIN_VERSION=27.1
|
||||
ENV BITCOIN_TARBALL bitcoin-${BITCOIN_VERSION}-${TARBALL_ARCH_FINAL}.tar.gz
|
||||
ARG BITCOIN_VERSION=0.17.0
|
||||
ENV BITCOIN_TARBALL bitcoin-${BITCOIN_VERSION}-x86_64-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
|
||||
ENV BITCOIN_ASC_URL https://bitcoincore.org/bin/bitcoin-core-$BITCOIN_VERSION/SHA256SUMS.asc
|
||||
ENV BITCOIN_PGP_KEY 01EA5486DE18A882D4C2684590C8019E36C2E964
|
||||
|
||||
RUN mkdir /opt/bitcoin && cd /opt/bitcoin \
|
||||
&& wget -qO $BITCOIN_TARBALL "$BITCOIN_URL" \
|
||||
&& wget -qO bitcoin "$BITCOIN_ASC_URL" \
|
||||
&& grep $BITCOIN_TARBALL bitcoin | tee SHA256SUMS \
|
||||
&& sha256sum -c SHA256SUMS \
|
||||
&& gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys "$BITCOIN_PGP_KEY" \
|
||||
&& wget -qO bitcoin.asc "$BITCOIN_ASC_URL" \
|
||||
&& gpg --verify bitcoin.asc \
|
||||
&& grep $BITCOIN_TARBALL bitcoin.asc | tee SHA256SUMS.asc \
|
||||
&& sha256sum -c SHA256SUMS.asc \
|
||||
&& BD=bitcoin-$BITCOIN_VERSION/bin \
|
||||
&& tar -xzvf $BITCOIN_TARBALL $BD/ --strip-components=1 \
|
||||
&& 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}-${TARBALL_ARCH_FINAL}.tar.gz
|
||||
ENV LITECOIN_PGP_KEY FE3348877809386C
|
||||
ENV LITECOIN_URL https://download.litecoin.org/litecoin-${LITECOIN_VERSION}/linux/litecoin-${LITECOIN_VERSION}-x86_64-linux-gnu.tar.gz
|
||||
ENV LITECOIN_ASC_URL https://download.litecoin.org/litecoin-${LITECOIN_VERSION}/linux/litecoin-${LITECOIN_VERSION}-linux-signatures.asc
|
||||
|
||||
# install litecoin binaries
|
||||
RUN mkdir /opt/litecoin && cd /opt/litecoin \
|
||||
&& wget -qO litecoin.tar.gz "$LITECOIN_URL" \
|
||||
&& tar -xzvf litecoin.tar.gz litecoin-$LITECOIN_VERSION/bin/litecoin-cli --strip-components=1 --exclude=*-qt \
|
||||
&& gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys "$LITECOIN_PGP_KEY" \
|
||||
&& wget -qO litecoin.asc "$LITECOIN_ASC_URL" \
|
||||
&& gpg --verify litecoin.asc \
|
||||
&& BD=litecoin-$LITECOIN_VERSION/bin \
|
||||
&& tar -xzvf litecoin.tar.gz $BD/litecoin-cli --strip-components=1 --exclude=*-qt \
|
||||
&& rm litecoin.tar.gz
|
||||
|
||||
ENV DESCHASHPLUGIN_URL https://github.com/nbd-wtf/invoicewithdescriptionhash/releases/download/v1.4/invoicewithdescriptionhash-v1.4-${DESCHASHPLUGIN_ARCH}.tar.gz
|
||||
ENV DESCHASHPLUGIN_SHA256 ${DESCHASHPLUGIN_HASH}
|
||||
RUN mkdir /opt/deschashplugin && cd /opt/deschashplugin \
|
||||
&& wget -qO invoicewithdescriptionhash.tar.gz "$DESCHASHPLUGIN_URL" \
|
||||
&& echo "$DESCHASHPLUGIN_SHA256 invoicewithdescriptionhash.tar.gz" | sha256sum -c - \
|
||||
&& tar -xzvf invoicewithdescriptionhash.tar.gz && rm invoicewithdescriptionhash.tar.gz \
|
||||
&& chmod a+x invoicewithdescriptionhash
|
||||
|
||||
FROM --platform=${DEFAULT_TARGETPLATFORM} ${BASE_DISTRO} AS base-builder
|
||||
RUN apt-get update -qq && \
|
||||
apt-get install -qq -y --no-install-recommends \
|
||||
autoconf \
|
||||
automake \
|
||||
bison \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
curl \
|
||||
dirmngr \
|
||||
flex \
|
||||
gettext \
|
||||
git \
|
||||
gnupg \
|
||||
jq \
|
||||
libicu-dev \
|
||||
libtool \
|
||||
libffi-dev \
|
||||
pkg-config \
|
||||
libssl-dev \
|
||||
protobuf-compiler \
|
||||
python3 \
|
||||
python3-dev \
|
||||
python3-mako \
|
||||
python3-pip \
|
||||
python3-venv \
|
||||
python3-setuptools \
|
||||
libev-dev \
|
||||
libevent-dev \
|
||||
qemu-user-static \
|
||||
wget \
|
||||
unzip \
|
||||
tclsh
|
||||
|
||||
ENV PATH="/root/.local/bin:$PATH" \
|
||||
PYTHON_VERSION=3 \
|
||||
POETRY_VERSION=2.0.1
|
||||
RUN curl -sSL https://install.python-poetry.org | python3 - && \
|
||||
poetry self add poetry-plugin-export
|
||||
RUN mkdir -p /root/.venvs && \
|
||||
python3 -m venv /root/.venvs/cln && \
|
||||
. /root/.venvs/cln/bin/activate && \
|
||||
pip3 install --upgrade pip setuptools wheel
|
||||
|
||||
RUN wget -q https://zlib.net/fossils/zlib-1.2.13.tar.gz -O zlib.tar.gz && \
|
||||
wget -q https://www.sqlite.org/2019/sqlite-src-3290000.zip -O sqlite.zip && \
|
||||
wget -q https://ftp.postgresql.org/pub/source/v17.1/postgresql-17.1.tar.gz -O postgres.tar.gz
|
||||
ENV LIGHTNINGD_VERSION=master
|
||||
|
||||
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)
|
||||
|
||||
# Do not build python plugins (wss-proxy) here, python doesn't support cross compilation.
|
||||
RUN sed -i '/^wss-proxy/d' pyproject.toml && \
|
||||
poetry lock && \
|
||||
poetry export -o requirements.txt --without-hashes
|
||||
RUN mkdir -p /root/.venvs && \
|
||||
python3 -m venv /root/.venvs/cln && \
|
||||
. /root/.venvs/cln/bin/activate && \
|
||||
pip3 install -r requirements.txt && \
|
||||
pip3 cache purge
|
||||
WORKDIR /
|
||||
ARG DEVELOPER=0
|
||||
RUN ./configure && make -j3 DEVELOPER=${DEVELOPER} && cp lightningd/lightning* cli/lightning-cli /usr/bin/
|
||||
|
||||
FROM base-builder AS base-builder-linux-amd64
|
||||
FROM alpine:3.7
|
||||
|
||||
ENV POSTGRES_CONFIG="--without-readline" \
|
||||
PG_CONFIG=/usr/local/pgsql/bin/pg_config
|
||||
RUN apk add --no-cache \
|
||||
gmp-dev \
|
||||
sqlite-dev \
|
||||
inotify-tools \
|
||||
socat \
|
||||
bash \
|
||||
zlib-dev
|
||||
|
||||
FROM base-builder AS base-builder-linux-arm64
|
||||
ENV target_host=aarch64-linux-gnu \
|
||||
target_host_rust=aarch64-unknown-linux-gnu \
|
||||
target_host_qemu=qemu-aarch64-static
|
||||
ENV GLIBC_VERSION 2.27-r0
|
||||
ENV GLIBC_SHA256 938bceae3b83c53e7fa9cc4135ce45e04aae99256c5e74cf186c794b97473bc7
|
||||
ENV GLIBCBIN_SHA256 3a87874e57b9d92e223f3e90356aaea994af67fb76b71bb72abfb809e948d0d6
|
||||
# Download and install glibc (https://github.com/jeanblanchard/docker-alpine-glibc/blob/master/Dockerfile)
|
||||
RUN apk add --update curl && \
|
||||
curl -Lo /etc/apk/keys/sgerrand.rsa.pub https://github.com/sgerrand/alpine-pkg-glibc/releases/download/$GLIBC_VERSION/sgerrand.rsa.pub && \
|
||||
curl -Lo glibc.apk "https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-${GLIBC_VERSION}.apk" && \
|
||||
echo "$GLIBC_SHA256 glibc.apk" | sha256sum -c - && \
|
||||
curl -Lo glibc-bin.apk "https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-bin-${GLIBC_VERSION}.apk" && \
|
||||
echo "$GLIBCBIN_SHA256 glibc-bin.apk" | sha256sum -c - && \
|
||||
apk add glibc-bin.apk glibc.apk && \
|
||||
/usr/glibc-compat/sbin/ldconfig /lib /usr/glibc-compat/lib && \
|
||||
echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf && \
|
||||
apk del curl && \
|
||||
rm -rf glibc.apk glibc-bin.apk /var/cache/apk/*
|
||||
|
||||
RUN apt-get install -qq -y --no-install-recommends \
|
||||
libc6-arm64-cross \
|
||||
gcc-${target_host} \
|
||||
g++-${target_host}
|
||||
ENV LIGHTNINGD_DATA=/root/.lightning
|
||||
ENV LIGHTNINGD_RPC_PORT=9835
|
||||
|
||||
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} \
|
||||
TARGET=${target_host_rust} \
|
||||
RUSTUP_INSTALL_OPTS="--target ${target_host_rust} --default-host ${target_host_rust}" \
|
||||
PKG_CONFIG_PATH="/usr/${target_host}/lib/pkgconfig"
|
||||
|
||||
ENV ZLIB_CONFIG="--prefix=${QEMU_LD_PREFIX}" \
|
||||
SQLITE_CONFIG="--host=${target_host} --prefix=${QEMU_LD_PREFIX}" \
|
||||
POSTGRES_CONFIG="--without-readline --prefix=${QEMU_LD_PREFIX}" \
|
||||
PG_CONFIG="${QEMU_LD_PREFIX}/bin/pg_config"
|
||||
|
||||
FROM base-builder AS base-builder-linux-arm
|
||||
|
||||
ENV target_host=arm-linux-gnueabihf \
|
||||
target_host_rust=armv7-unknown-linux-gnueabihf \
|
||||
target_host_qemu=qemu-arm-static
|
||||
|
||||
RUN apt-get install -qq -y --no-install-recommends \
|
||||
libc6-armhf-cross \
|
||||
gcc-${target_host} \
|
||||
g++-${target_host}
|
||||
|
||||
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} \
|
||||
TARGET=${target_host_rust} \
|
||||
RUSTUP_INSTALL_OPTS="--target ${target_host_rust} --default-host ${target_host_rust}" \
|
||||
PKG_CONFIG_PATH="/usr/${target_host}/lib/pkgconfig"
|
||||
|
||||
ENV ZLIB_CONFIG="--prefix=${QEMU_LD_PREFIX}" \
|
||||
SQLITE_CONFIG="--host=${target_host} --prefix=${QEMU_LD_PREFIX}" \
|
||||
POSTGRES_CONFIG="--without-readline --prefix=${QEMU_LD_PREFIX}" \
|
||||
PG_CONFIG="${QEMU_LD_PREFIX}/bin/pg_config"
|
||||
|
||||
FROM base-builder-${TARGETOS}-${TARGETARCH} AS builder
|
||||
|
||||
ENV LIGHTNINGD_VERSION=master
|
||||
|
||||
RUN mkdir zlib && tar xvf zlib.tar.gz -C zlib --strip-components=1 \
|
||||
&& cd zlib \
|
||||
&& ./configure ${ZLIB_CONFIG} \
|
||||
&& make \
|
||||
&& make install && cd .. && \
|
||||
rm zlib.tar.gz && \
|
||||
rm -rf zlib
|
||||
|
||||
RUN unzip sqlite.zip \
|
||||
&& cd sqlite-* \
|
||||
&& ./configure --enable-static --disable-readline --disable-threadsafe --disable-load-extension ${SQLITE_CONFIG} \
|
||||
&& make \
|
||||
&& make install && cd .. && rm sqlite.zip && rm -rf sqlite-*
|
||||
|
||||
RUN mkdir postgres && tar xvf postgres.tar.gz -C postgres --strip-components=1 \
|
||||
&& cd postgres \
|
||||
&& ./configure ${POSTGRES_CONFIG} \
|
||||
&& cd src/include \
|
||||
&& make install \
|
||||
&& cd ../interfaces/libpq \
|
||||
&& make install \
|
||||
&& cd ../../bin/pg_config \
|
||||
&& make install \
|
||||
&& cd ../../../../ && \
|
||||
rm postgres.tar.gz && \
|
||||
rm -rf postgres && \
|
||||
ldconfig "$(${PG_CONFIG} --libdir)"
|
||||
|
||||
# Save libpq to a specific location to copy it into the final image.
|
||||
RUN mkdir /var/libpq && cp -a "$(${PG_CONFIG} --libdir)"/libpq.* /var/libpq
|
||||
|
||||
ENV RUST_PROFILE=release \
|
||||
PATH="/root/.cargo/bin:/root/.local/bin:$PATH"
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y ${RUSTUP_INSTALL_OPTS}
|
||||
RUN rustup toolchain install stable --component rustfmt --allow-downgrade
|
||||
|
||||
COPY --from=downloader /usr/bin/${target_host_qemu} /usr/bin/${target_host_qemu}
|
||||
WORKDIR /opt/lightningd
|
||||
|
||||
# If cross-compiling, need to tell it to cargo.
|
||||
RUN ( ! [ -n "${target_host}" ] ) || \
|
||||
(mkdir -p .cargo && echo "[target.${target_host_rust}]\nlinker = \"${target_host}-gcc\"" > .cargo/config)
|
||||
|
||||
# Weird errors with cargo for cln-grpc on arm7 https://github.com/ElementsProject/lightning/issues/6596
|
||||
RUN ( ! [ "${target_host}" = "arm-linux-gnueabihf" ] ) || \
|
||||
(sed -i '/documentation = "https:\/\/docs.rs\/cln-grpc"/a include = ["**\/*.*"]' cln-grpc/Cargo.toml)
|
||||
|
||||
# Ensure that the desired grpcio-tools & protobuf versions are installed
|
||||
# https://github.com/ElementsProject/lightning/pull/7376#issuecomment-2161102381
|
||||
RUN poetry lock && poetry install && \
|
||||
poetry self add poetry-plugin-export
|
||||
|
||||
# Ensure that git differences are removed before making bineries, to avoid `-modded` suffix
|
||||
# poetry.lock changed due to pyln-client, pyln-proto and pyln-testing version updates
|
||||
# pyproject.toml was updated to exclude wss-proxy plugins in base-builder stage
|
||||
RUN git reset --hard HEAD
|
||||
|
||||
RUN ./configure --prefix=/tmp/lightning_install --enable-static && poetry run make install
|
||||
|
||||
# Export the requirements for the plugins so we can install them in builder-python stage
|
||||
WORKDIR /opt/lightningd/plugins/wss-proxy
|
||||
RUN poetry lock && poetry export -o requirements.txt --without-hashes
|
||||
WORKDIR /opt/lightningd
|
||||
RUN echo 'RUSTUP_INSTALL_OPTS="${RUSTUP_INSTALL_OPTS}"' > /tmp/rustup_install_opts.txt
|
||||
|
||||
# We need to build python plugins on the target's arch because python doesn't support cross build
|
||||
FROM ${BASE_DISTRO} AS builder-python
|
||||
RUN apt-get update -qq && \
|
||||
apt-get install -qq -y --no-install-recommends \
|
||||
git \
|
||||
curl \
|
||||
libtool \
|
||||
pkg-config \
|
||||
autoconf \
|
||||
automake \
|
||||
build-essential \
|
||||
libffi-dev \
|
||||
libssl-dev \
|
||||
python3 \
|
||||
python3-dev \
|
||||
python3-pip \
|
||||
python3-venv && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV PYTHON_VERSION=3
|
||||
RUN mkdir -p /root/.venvs && \
|
||||
python3 -m venv /root/.venvs/cln && \
|
||||
. /root/.venvs/cln/bin/activate && \
|
||||
pip3 install --upgrade pip setuptools wheel
|
||||
|
||||
# Copy rustup_install_opts.txt file from builder
|
||||
COPY --from=builder /tmp/rustup_install_opts.txt /tmp/rustup_install_opts.txt
|
||||
# Setup ENV $RUSTUP_INSTALL_OPTS for this stage
|
||||
RUN export $(cat /tmp/rustup_install_opts.txt)
|
||||
ENV PATH="/root/.cargo/bin:/root/.venvs/cln/bin:$PATH"
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y ${RUSTUP_INSTALL_OPTS}
|
||||
|
||||
WORKDIR /opt/lightningd/plugins/wss-proxy
|
||||
COPY --from=builder /opt/lightningd/plugins/wss-proxy/requirements.txt .
|
||||
RUN pip3 install -r requirements.txt
|
||||
RUN pip3 cache purge
|
||||
|
||||
WORKDIR /opt/lightningd
|
||||
|
||||
FROM ${BASE_DISTRO} AS final
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
tini \
|
||||
socat \
|
||||
inotify-tools \
|
||||
jq \
|
||||
python3 \
|
||||
python3-pip && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV LIGHTNINGD_DATA=/root/.lightning \
|
||||
LIGHTNINGD_RPC_PORT=9835 \
|
||||
LIGHTNINGD_PORT=9735 \
|
||||
LIGHTNINGD_NETWORK=bitcoin
|
||||
|
||||
RUN mkdir $LIGHTNINGD_DATA && \
|
||||
mkdir /etc/bundledplugins && \
|
||||
mkdir $LIGHTNINGD_DATA/plugins && \
|
||||
touch $LIGHTNINGD_DATA/config
|
||||
VOLUME [ "/root/.lightning" ]
|
||||
|
||||
# Take libpq directly from builder.
|
||||
RUN mkdir /var/libpq && mkdir -p /usr/local/pgsql/lib
|
||||
RUN --mount=type=bind,from=builder,source=/var/libpq,target=/var/libpq,rw \
|
||||
cp -a /var/libpq/libpq.* /usr/local/pgsql/lib && \
|
||||
echo "/usr/local/pgsql/lib" > /etc/ld.so.conf.d/libpq.conf && \
|
||||
ldconfig
|
||||
|
||||
COPY --from=builder /tmp/lightning_install/ /usr/local/
|
||||
COPY --from=builder-python /root/.venvs/cln/lib/python3.11/site-packages /usr/local/lib/python3.11/dist-packages/
|
||||
COPY --from=downloader /opt/bitcoin/bin /usr/bin
|
||||
COPY --from=downloader /opt/litecoin/bin /usr/bin
|
||||
COPY --from=downloader /opt/deschashplugin $LIGHTNINGD_DATA/plugins
|
||||
COPY --from=downloader /opt/deschashplugin /etc/bundledplugins
|
||||
COPY --from=builder /opt/lightningd/cli/lightning-cli /usr/bin
|
||||
COPY --from=builder /opt/lightningd/lightningd/lightning* /usr/bin/
|
||||
COPY --from=builder /opt/lightningd/plugins/pay /usr/libexec/c-lightning/plugins/
|
||||
COPY --from=builder /opt/bitcoin/bin /usr/bin
|
||||
COPY --from=builder /opt/litecoin/bin /usr/bin
|
||||
COPY tools/docker-entrypoint.sh entrypoint.sh
|
||||
|
||||
EXPOSE 9735 9835
|
||||
ENTRYPOINT [ "/usr/bin/tini", "-g", "--", "./entrypoint.sh" ]
|
||||
ENTRYPOINT [ "./entrypoint.sh" ]
|
||||
|
||||
2
LICENSE
2
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-2024.
|
||||
Copyright Rusty Russell (Blockstream) 2015.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
381
README.md
381
README.md
@ -1,232 +1,291 @@
|
||||
# Core Lightning (CLN): A specification compliant Lightning Network implementation in C
|
||||
# c-lightning: A specification compliant Lightning Network implementation in C
|
||||
|
||||
Core Lightning (previously c-lightning) is a lightweight, highly customizable and [standard compliant][std] implementation of the Lightning Network protocol.
|
||||
c-lightning is a [standard compliant][std] implementation of the Lightning
|
||||
Network protocol.
|
||||
The Lightning Network is a scalability solution for Bitcoin, enabling
|
||||
secure and instant transfer of funds between any two parties for any
|
||||
amount.
|
||||
|
||||
* [Getting Started](#getting-started)
|
||||
* [Installation](#installation)
|
||||
* [Starting lightningd](#starting-lightningd)
|
||||
* [Using the JSON-RPC Interface](#using-the-json-rpc-interface)
|
||||
* [Care And Feeding Of Your New Lightning Node](#care-and-feeding-of-your-new-lightning-node)
|
||||
* [Opening A Channel](#opening-a-channel)
|
||||
* [Sending and Receiving Payments](#sending-and-receiving-payments)
|
||||
* [Configuration File](#configuration-file)
|
||||
* [Further Information](#further-information)
|
||||
* [FAQ](doc/FAQ.md)
|
||||
* [Pruning](#pruning)
|
||||
* [HD wallet encryption](#hd-wallet-encryption)
|
||||
* [Developers](#developers)
|
||||
* [Documentation](https://docs.corelightning.org/docs)
|
||||
[std]: https://github.com/lightningnetwork/lightning-rfc
|
||||
|
||||
For more information about the Lightning Network please refer to
|
||||
http://lightning.network.
|
||||
|
||||
## Project Status
|
||||
|
||||
[![Continuous Integration][actions-badge]][actions]
|
||||
[![Pull Requests Welcome][prs-badge]][prs]
|
||||
[![Documentation Status][docs-badge]][docs]
|
||||
[![BoL2][bol2-badge]][bol2]
|
||||
[![Telegram][telegram-badge]][telegram]
|
||||
[![Discord][discord-badge]][discord]
|
||||
[![Irc][IRC-badge]][IRC]
|
||||
[![Build Status][travis-ci]][travis-ci-link]
|
||||
[![Pull Requests Welcome][prs]][prs-link]
|
||||
[![Irc][IRC]][IRC-link]
|
||||
[](https://lightning.readthedocs.io/)
|
||||
|
||||
This implementation has been in production use on the Bitcoin mainnet since early 2018, with the launch of the [Blockstream Store][blockstream-store-blog].
|
||||
We recommend getting started by experimenting on `testnet` (`testnet4` or `regtest`), but the implementation is considered stable and can be safely used on mainnet.
|
||||
[travis-ci]: https://travis-ci.org/ElementsProject/lightning.svg?branch=master
|
||||
[travis-ci-link]: https://travis-ci.org/ElementsProject/lightning
|
||||
[prs]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat
|
||||
[prs-link]: http://makeapullrequest.com
|
||||
[IRC]: https://img.shields.io/badge/chat-on%20freenode-brightgreen.svg
|
||||
[IRC-link]: https://webchat.freenode.net/?channels=c-lightning
|
||||
|
||||
## Reach Out to Us
|
||||
This implementation is still very much a work in progress.
|
||||
It can be used for testing, but __it should not be used for real funds__.
|
||||
We do our best to identify and fix problems, and implement missing
|
||||
features.
|
||||
|
||||
Any help testing the implementation, reporting bugs, or helping with outstanding issues is very welcome.
|
||||
Don't hesitate to reach out to us on [Build-on-L2][bol2], or on the implementation-specific [mailing list][ml1], or on [CLN Discord][discord], or on [CLN Telegram][telegram], or on IRC at [dev][irc1]/[gen][irc2] channel.
|
||||
Any help testing the implementation, reporting bugs, or helping with
|
||||
outstanding issues is very welcome.
|
||||
Don't hesitate to reach out to us on IRC at
|
||||
[#lightning-dev @ freenode.net][irc1], [#c-lightning @
|
||||
freenode.net][irc2], or on the implementation-specific mailing list
|
||||
[c-lightning@lists.ozlabs.org][ml1], or on the Lightning Network-wide
|
||||
mailing list [lightning-dev@lists.linuxfoundation.org][ml2].
|
||||
|
||||
[irc1]: http://webchat.freenode.net/?channels=%23lightning-dev
|
||||
[irc2]: http://webchat.freenode.net/?channels=%23c-lightning
|
||||
[ml1]: https://lists.ozlabs.org/listinfo/c-lightning
|
||||
[ml2]: https://lists.linuxfoundation.org/mailman/listinfo/lightning-dev
|
||||
|
||||
## Getting Started
|
||||
|
||||
Core Lightning only works on Linux and macOS, and requires a locally (or remotely) running `bitcoind` (version 25.0 or above) that is fully caught up with the network you're running on, and relays transactions (ie with `blocksonly=0`).
|
||||
Pruning (`prune=n` option in `bitcoin.conf`) is partially supported, see [here](#pruning) for more details.
|
||||
c-lightning currently only works on Linux (and possibly Mac OS with some
|
||||
tweaking), and requires a locally (or remotely) running `bitcoind` (version 0.15 or
|
||||
above) that is fully caught up with the network you're testing on.
|
||||
Pruning (prune=n option in bitcoin.conf) is not currently supported.
|
||||
|
||||
### Installation
|
||||
|
||||
There are 3 supported installation options:
|
||||
Please refer to the [installation documentation](doc/INSTALL.md) for
|
||||
detailed instructions.
|
||||
For the impatient here's the gist of it for Ubuntu and Debian:
|
||||
|
||||
- Installation of a pre-compiled binary from the [release page][releases] on GitHub.
|
||||
- Using one of the [provided docker images][dockerhub] on the Docker Hub.
|
||||
- Compiling the source code yourself as described in the [installation documentation](doc/getting-started/getting-started/installation.md).
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
autoconf automake build-essential git libtool libgmp-dev \
|
||||
libsqlite3-dev python python3 net-tools zlib1g-dev libsodium-dev
|
||||
git clone https://github.com/ElementsProject/lightning.git
|
||||
cd lightning
|
||||
./configure
|
||||
make
|
||||
|
||||
Or if you like to throw `docker` into the mix, you can use the official docker image either directly or as a base layer for more complex images.
|
||||
The docker image is [elementsproject/lightningd](https://hub.docker.com/r/elementsproject/lightningd/) (from this [Dockerfile](Dockerfile)).
|
||||
Image tags with `-dev` at the end are images built with `DEVELOPER=1`.
|
||||
If you build the image yourself, you can use the build arg `DEVELOPER=1` to build c-lightning in developer mode.
|
||||
|
||||
It has the following environment variable:
|
||||
|
||||
* `EXPOSE_TCP` default to false, if true, use expose c-lightning RPC on port 9835. (Use this only for testing)
|
||||
|
||||
Here is an example of a docker-compose file with bitcoind and c-lightning on `testnet` which expose bitcoind's RPC interface on default ports `18332` and c-lightning API on port `9735`:
|
||||
|
||||
```
|
||||
version: "3"
|
||||
services:
|
||||
bitcoind:
|
||||
image: nicolasdorier/docker-bitcoin:0.16.3
|
||||
container_name: bitcoind
|
||||
environment:
|
||||
BITCOIN_EXTRA_ARGS: |
|
||||
testnet=1
|
||||
whitelist=0.0.0.0/0
|
||||
server=1
|
||||
rpcuser=rpcuser
|
||||
rpcpassword=rpcpass
|
||||
expose:
|
||||
- "18332"
|
||||
ports:
|
||||
- "0.0.0.0:18333:18333"
|
||||
volumes:
|
||||
- "bitcoin_datadir:/data"
|
||||
|
||||
clightning_bitcoin:
|
||||
image: elementsproject/lightningd
|
||||
container_name: lightningd
|
||||
command:
|
||||
- --bitcoin-rpcconnect=bitcoind
|
||||
- --bitcoin-rpcuser=rpcuser
|
||||
- --bitcoin-rpcpassword=rpcpass
|
||||
- --plugin-dir=/usr/libexec/c-lightning/plugins
|
||||
- --network=testnet
|
||||
- --alias=myawesomenode
|
||||
- --log-level=debug
|
||||
environment:
|
||||
EXPOSE_TCP: "true"
|
||||
expose:
|
||||
- "9735"
|
||||
ports:
|
||||
- "0.0.0.0:9735:9735"
|
||||
volumes:
|
||||
- "clightning_bitcoin_datadir:/root/.lightning"
|
||||
- "bitcoin_datadir:/etc/bitcoin"
|
||||
links:
|
||||
- bitcoind
|
||||
|
||||
volumes:
|
||||
bitcoin_datadir:
|
||||
clightning_bitcoin_datadir:
|
||||
```
|
||||
|
||||
### 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.
|
||||
In order to start `lightningd` you will need to have a local `bitcoind`
|
||||
node running in either testnet or regtest mode:
|
||||
|
||||
```bash
|
||||
. contrib/startup_regtest.sh
|
||||
```
|
||||
bitcoind -daemon -testnet
|
||||
|
||||
#### Mainnet Option
|
||||
To test with real bitcoin, you will need to have a local `bitcoind` node running:
|
||||
Wait until `bitcoind` has synchronized with the testnet network.
|
||||
|
||||
```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 [below](#pruning) for more information.
|
||||
Make sure that you do not have `walletbroadcast=0` in your
|
||||
`~/.bitcoin/bitcoin.conf`, or you may run into trouble.
|
||||
Notice that currently pruned nodes are not supported and may result in
|
||||
`lightningd` being unable to synchronize with the blockchain.
|
||||
|
||||
You can start `lightningd` with the following command:
|
||||
|
||||
```bash
|
||||
lightningd --network=bitcoin --log-level=debug
|
||||
```
|
||||
lightningd/lightningd --network=testnet --log-level=debug
|
||||
|
||||
This creates a `.lightning/` subdirectory in your home directory: see `man -l doc/lightningd.8` (or https://docs.corelightning.org/docs) for more runtime options.
|
||||
### Listing all commands:
|
||||
`cli/lightning-cli help` will print a table of the API and lists the
|
||||
following commands
|
||||
|
||||
### Using The JSON-RPC Interface
|
||||
|
||||
Core Lightning exposes a [JSON-RPC 2.0][jsonrpcspec] interface over a Unix Domain socket; the `lightning-cli` tool can be used to access it, or there is a [python client library](contrib/pyln-client).
|
||||
|
||||
You can use `lightning-cli help` to print a table of RPC methods; `lightning-cli help <command>`
|
||||
will offer specific information on that command.
|
||||
|
||||
Useful commands:
|
||||
|
||||
* [newaddr](doc/lightning-newaddr.7.md): get a bitcoin address to deposit funds into your lightning node.
|
||||
* [listfunds](doc/lightning-listfunds.7.md): see where your funds are.
|
||||
* [connect](doc/lightning-connect.7.md): connect to another lightning node.
|
||||
* [fundchannel](doc/lightning-fundchannel.7.md): create a channel to another connected node.
|
||||
* [invoice](doc/lightning-invoice.7.md): create an invoice to get paid by another node.
|
||||
* [pay](doc/lightning-pay.7.md): pay someone else's invoice.
|
||||
* [plugin](doc/lightning-plugin.7.md): 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: in particular there's a collection at: https://github.com/lightningd/plugins
|
||||
|
||||
For a less reckless experience, you can encrypt the HD wallet seed:
|
||||
see [HD wallet encryption](#hd-wallet-encryption).
|
||||
|
||||
You can also chat to other users at Discord [core-lightning][discord];
|
||||
we are always happy to help you get started!
|
||||
|
||||
|
||||
### Opening A Channel
|
||||
### Opening a channel on the Bitcoin testnet
|
||||
|
||||
First you need to transfer some funds to `lightningd` so that it can
|
||||
open a channel:
|
||||
|
||||
```bash
|
||||
# Returns an address <address>
|
||||
lightning-cli newaddr
|
||||
```
|
||||
# Returns an address <address>
|
||||
cli/lightning-cli newaddr
|
||||
|
||||
# Returns a transaction id <txid>
|
||||
bitcoin-cli -testnet sendtoaddress <address> <amount_in_bitcoins>
|
||||
|
||||
`lightningd` will register the funds once the transaction is confirmed.
|
||||
|
||||
Alternatively you can generate a taproot address should your source of funds support it:
|
||||
You can obtain testcoins from a faucet such as [coinfaucet.eu][cfeu].
|
||||
You can send them directly to the `lightningd` address.
|
||||
|
||||
```bash
|
||||
# Return a taproot address
|
||||
lightning-cli newaddr p2tr
|
||||
```
|
||||
You may need to generate a p2sh-segwit address if the faucet does not support
|
||||
bech32:
|
||||
|
||||
# Return a p2sh-segwit address
|
||||
cli/lightning-cli newaddr p2sh-segwit
|
||||
|
||||
[cfeu]: https://coinfaucet.eu/en/btc-testnet
|
||||
|
||||
Confirm `lightningd` got funds by:
|
||||
|
||||
```bash
|
||||
# Returns an array of on-chain funds.
|
||||
lightning-cli listfunds
|
||||
```
|
||||
# Returns an array of on-chain funds.
|
||||
cli/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 `<ip>`
|
||||
(and optional `<port>`, if not 9735) and has the node ID `<node_id>`:
|
||||
|
||||
```bash
|
||||
lightning-cli connect <node_id> <ip> [<port>]
|
||||
lightning-cli fundchannel <node_id> <amount_in_satoshis>
|
||||
```
|
||||
cli/lightning-cli connect <node_id> <ip> [<port>]
|
||||
cli/lightning-cli fundchannel <node_id> <amount_in_satoshis>
|
||||
```
|
||||
|
||||
This opens a connection and, on top of that connection, then opens a channel.
|
||||
The funding transaction needs 3 confirmation 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`.
|
||||
This opens a connection and, on top of that connection, then opens
|
||||
a channel.
|
||||
The funding transaction needs 1 confirmation in order for the channel
|
||||
to be usable, and 6 to be broadcast for others to use.
|
||||
You can check the status of the channel using `cli/lightning-cli
|
||||
listpeers`, which after 3 confirmations (1 on testnet) should say
|
||||
that `state` is `CHANNELD_NORMAL`; after 6 confirmations you can use
|
||||
`cli/lightning-cli listchannels` to verify that the `public` field is now
|
||||
`true`.
|
||||
|
||||
### Sending and Receiving Payments
|
||||
### Different states
|
||||
* `OPENINGD` means that `lightning_openingd` is negotiating channel
|
||||
opening.
|
||||
* `CHANNELD_AWAITING_LOCKIN` means that `lightning_channeld` is waiting
|
||||
until the minimum number of confirmation on the channel funding
|
||||
transaction.
|
||||
* `CHANNELD_NORMAL` means your channel is operating normally.
|
||||
* `CHANNELD_SHUTTING_DOWN` means one or both sides have asked to shut
|
||||
down the channel, and we're waiting for existing HTLCs to clear.
|
||||
* `CLOSINGD_SIGEXCHANGE` means we're trying to negotiate the fee for
|
||||
the mutual close transaction.
|
||||
* `CLOSINGD_COMPLETE` means we've broadcast our mutual close
|
||||
transaction (which spends the funding transaction) , but haven't seen
|
||||
it in a block yet.
|
||||
* `FUNDING_SPEND_SEEN` means we've seen the funding transaction spent.
|
||||
* `ONCHAIN` means that the `lightning_onchaind` is tracking the onchain
|
||||
closing of the channel.
|
||||
* `AWAITING_UNILATERAL` means that we're waiting for a unilateral close to hit the blockchain.
|
||||
|
||||
All these states have more information about what's going on in the
|
||||
`status` field in `listpeers`.
|
||||
|
||||
### Sending and receiving payments
|
||||
|
||||
Payments in Lightning are invoice based.
|
||||
The recipient creates an invoice with the expected `<amount>` in
|
||||
millisatoshi (or `"any"` for a donation), a unique `<label>` and a
|
||||
`<description>` the payer will see:
|
||||
|
||||
```bash
|
||||
lightning-cli invoice <amount> <label> <description>
|
||||
```
|
||||
cli/lightning-cli invoice <amount> <label> <description>
|
||||
```
|
||||
|
||||
This returns some internal details, and a standard invoice string called `bolt11` (named after the [BOLT #11 lightning spec][BOLT11]).
|
||||
This returns some internal details, and a standard invoice
|
||||
string called `bolt11` (named after the [BOLT #11 lightning
|
||||
spec][BOLT11]).
|
||||
|
||||
[BOLT11]: https://github.com/lightning/bolts/blob/master/11-payment-encoding.md
|
||||
[BOLT11]: https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md
|
||||
|
||||
The sender can feed this `bolt11` string to the `decodepay` command to see what it is, and pay it simply using the `pay` command:
|
||||
The sender can feed this `bolt11` string to the `decodepay` command to
|
||||
see what it is, and pay it simply using the `pay` command:
|
||||
|
||||
```bash
|
||||
lightning-cli pay <bolt11>
|
||||
```
|
||||
cli/lightning-cli pay <bolt11>
|
||||
```
|
||||
|
||||
Note that there are lower-level interfaces (and more options to these
|
||||
interfaces) for more sophisticated use.
|
||||
|
||||
## Configuration File
|
||||
lightningd can be configured either by passing options via the command
|
||||
line, or via a configuration file.
|
||||
Command line options will always override the values in the configuration
|
||||
file.
|
||||
|
||||
`lightningd` can be configured either by passing options via the command line, or via a configuration file.
|
||||
Command line options will always override the values in the configuration file.
|
||||
To use a configuration file, create a file named "config" within your
|
||||
".lightning" directory. Usually, this will be ~/.lightning/config
|
||||
|
||||
To use a configuration file, create a file named `config` within your top-level lightning directory or network subdirectory
|
||||
(eg. `~/.lightning/config` or `~/.lightning/bitcoin/config`). See `man -l doc/lightningd-config.5`.
|
||||
Configuration options are set using a key=value pair on each line of
|
||||
the file, for example:
|
||||
|
||||
A sample configuration file is available at `contrib/config-example`.
|
||||
```
|
||||
alias=SLEEPYDRAGON
|
||||
rgb=008000
|
||||
port=9735
|
||||
network=testnet
|
||||
```
|
||||
|
||||
For a full list of possible lightningd configuration options, run:
|
||||
```
|
||||
lightningd/lightningd --help
|
||||
```
|
||||
|
||||
## Further information
|
||||
|
||||
### Pruning
|
||||
|
||||
Core Lightning requires JSON-RPC access to a fully synchronized `bitcoind` in order to synchronize with the Bitcoin network.
|
||||
Access to ZeroMQ is not required and `bitcoind` does not need to be run with `txindex` like other implementations.
|
||||
The lightning daemon will poll `bitcoind` for new blocks that it hasn't processed yet, thus synchronizing itself with `bitcoind`.
|
||||
If `bitcoind` prunes a block that Core Lightning has not processed yet, e.g., Core Lightning was not running for a prolonged period, then `bitcoind` will not be able to serve the missing blocks, hence Core Lightning will not be able to synchronize anymore and will be stuck.
|
||||
In order to avoid this situation you should be monitoring the gap between Core Lightning's blockheight using `lightning-cli getinfo` and `bitcoind`'s blockheight using `bitcoin-cli getblockchaininfo`.
|
||||
If the two blockheights drift apart it might be necessary to intervene.
|
||||
|
||||
### HD wallet encryption
|
||||
|
||||
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 this repo) 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.
|
||||
|
||||
### Developers
|
||||
Developers wishing to contribute should start with the developer guide [here](doc/HACKING.md).
|
||||
|
||||
Developers wishing to contribute should start with the developer guide [here](doc/contribute-to-core-lightning/coding-style-guidelines.md).
|
||||
|
||||
[blockstream-store-blog]: https://blockstream.com/2018/01/16/en-lightning-charge/
|
||||
[std]: https://github.com/lightning/bolts
|
||||
[prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat
|
||||
[prs]: http://makeapullrequest.com
|
||||
[bol2-badge]: https://badgen.net/badge/BoL2/chat/blue
|
||||
[bol2]: https://community.corelightning.org
|
||||
[ml1]: https://lists.ozlabs.org/listinfo/c-lightning
|
||||
[discord-badge]: https://badgen.net/badge/Discord/chat/blue
|
||||
[discord]: https://discord.gg/mE9s4rc5un
|
||||
[telegram-badge]: https://badgen.net/badge/Telegram/chat/blue
|
||||
[telegram]: https://t.me/lightningd
|
||||
[IRC-badge]: https://img.shields.io/badge/IRC-chat-blue.svg
|
||||
[IRC]: https://web.libera.chat/#c-lightning
|
||||
[irc1]: https://web.libera.chat/#lightning-dev
|
||||
[irc2]: https://web.libera.chat/#c-lightning
|
||||
[docs-badge]: https://readthedocs.org/projects/lightning/badge/?version=docs
|
||||
[docs]: https://docs.corelightning.org/docs
|
||||
[releases]: https://github.com/ElementsProject/lightning/releases
|
||||
[dockerhub]: https://hub.docker.com/r/elementsproject/lightningd/
|
||||
[jsonrpcspec]: https://www.jsonrpc.org/specification
|
||||
[helpme-github]: https://github.com/lightningd/plugins/tree/master/helpme
|
||||
[actions-badge]: https://github.com/ElementsProject/lightning/workflows/Continuous%20Integration/badge.svg
|
||||
[actions]: https://github.com/ElementsProject/lightning/actions
|
||||
### JSON RPC
|
||||
JSON-RPC interface is documented in the following manual pages:
|
||||
|
||||
* [invoice](doc/lightning-invoice.7.txt)
|
||||
* [listinvoices](doc/lightning-listinvoices.7.txt)
|
||||
* [waitinvoice](doc/lightning-waitinvoice.7.txt)
|
||||
* [waitanyinvoice](doc/lightning-waitanyinvoice.7.txt)
|
||||
* [delinvoice](doc/lightning-delinvoice.7.txt)
|
||||
* [getroute](doc/lightning-getroute.7.txt)
|
||||
* [sendpay](doc/lightning-sendpay.7.txt)
|
||||
* [pay](doc/lightning-pay.7.txt)
|
||||
* [listpays](doc/lightning-listpays.7.txt)
|
||||
* [decodepay](doc/lightning-decodepay.7.txt)
|
||||
|
||||
For simple access to the JSON-RPC interface you can use the
|
||||
`cli/lightning-cli` tool, or the [python API client](contrib/pylightning).
|
||||
|
||||
35
SECURITY.md
35
SECURITY.md
@ -1,35 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
We have a 3 month release cycle, and the last two versions are supported.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
To report security vulnerabilities, please send an email to one of the following addresses:
|
||||
- `rusty@rustcorp.com.au`
|
||||
- `security@blockstream.com`
|
||||
|
||||
Note: These email addresses are exclusively for vulnerability reporting.
|
||||
|
||||
For all other inquiries/communication, please refer to the [Reach Out to Us](https://github.com/ElementsProject/lightning?tab=readme-ov-file#reach-out-to-us) section in our README.
|
||||
|
||||
## Signatures For Releases
|
||||
|
||||
The following keys may be used to communicate sensitive information to
|
||||
developers, and to validate signatures on releases:
|
||||
|
||||
| Name | Email | Fingerprint |
|
||||
|------|-------|-------------|
|
||||
| Blockstream Security Reporting | `security@blockstream.com` | 1176 542D A98E 71E1 3372 2EF7 4AC8 CC88 6844 A2D6 |
|
||||
| Rusty Russell | `rusty@rustcorp.com.au` | 15EE 8D6C AB0E 7F0C F999 BFCB D920 0E6C D1AD B8F1 |
|
||||
| Christian Decker | `decker@blockstream.com` | B731 AAC5 21B0 1385 9313 F674 A26D 6D9F E088 ED58 |
|
||||
| Lisa Neigut | `niftynei@gmail.com` | 30DE 693A E0DE 9E37 B3E7 EB6B BFF0 F678 10C1 EED1 |
|
||||
| Alex Myers | `alex@endothermic.dev` | 0437 4E42 789B BBA9 462E 4767 F3BF 63F2 7474 36AB |
|
||||
| Peter Neuroth | `pet.v.ne@gmail.com` | 653B 19F3 3DF7 EFF3 E9D1 C94C C3F2 1EE3 87FF 4CD2 |
|
||||
| Shahana Farooqui | `sfarooqui@blockstream.com` | FE13 58EB 7793 51DB 24E5 555A A327 573C 9758 9BF5 |
|
||||
| Blockstream CLN Release | `cln@blockstream.com` | 616C 52F9 9D06 12B2 A151 B107 4129 A994 AA7E 9852 |
|
||||
|
||||
You can import a key by running the following command with that individual’s fingerprint:
|
||||
`gpg --keyserver hkps://keys.openpgp.org --recv-keys "<fingerprint>"`.
|
||||
Ensure that you put quotes around fingerprints containing spaces.
|
||||
@ -4,18 +4,15 @@ BITCOIN_SRC := \
|
||||
bitcoin/base58.c \
|
||||
bitcoin/block.c \
|
||||
bitcoin/chainparams.c \
|
||||
bitcoin/feerate.c \
|
||||
bitcoin/locktime.c \
|
||||
bitcoin/preimage.c \
|
||||
bitcoin/privkey.c \
|
||||
bitcoin/psbt.c \
|
||||
bitcoin/pubkey.c \
|
||||
bitcoin/pullpush.c \
|
||||
bitcoin/script.c \
|
||||
bitcoin/shadouble.c \
|
||||
bitcoin/short_channel_id.c \
|
||||
bitcoin/signature.c \
|
||||
bitcoin/tx.c \
|
||||
bitcoin/tx_parts.c \
|
||||
bitcoin/varint.c
|
||||
|
||||
BITCOIN_OBJS := $(BITCOIN_SRC:.c=.o)
|
||||
@ -28,28 +25,29 @@ BITCOIN_HEADERS := bitcoin/address.h \
|
||||
bitcoin/locktime.h \
|
||||
bitcoin/preimage.h \
|
||||
bitcoin/privkey.h \
|
||||
bitcoin/psbt.h \
|
||||
bitcoin/pubkey.h \
|
||||
bitcoin/pullpush.h \
|
||||
bitcoin/script.h \
|
||||
bitcoin/shadouble.h \
|
||||
bitcoin/short_channel_id.h \
|
||||
bitcoin/signature.h \
|
||||
bitcoin/tx.h \
|
||||
bitcoin/tx_parts.h \
|
||||
bitcoin/varint.h
|
||||
|
||||
check-source: $(BITCOIN_SRC:%=check-src-include-order/%) \
|
||||
$(BITCOIN_HEADERS:%=check-hdr-include-order/%)
|
||||
|
||||
# Bitcoin objects depends on bitcoin/ external/ and ccan
|
||||
$(BITCOIN_OBJS): $(CCAN_HEADERS) $(BITCOIN_HEADERS) $(EXTERNAL_HEADERS)
|
||||
|
||||
ALL_C_HEADERS += $(BITCOIN_HEADERS)
|
||||
ALL_C_SOURCES += $(BITCOIN_SRC)
|
||||
check-source-bolt: $(BITCOIN_SRC:%=bolt-check/%) $(BITCOIN_HEADERS:%=bolt-check/%)
|
||||
|
||||
check-makefile: check-bitcoin-makefile
|
||||
|
||||
check-bitcoin-makefile:
|
||||
@if [ "`echo bitcoin/*.h`" != "$(BITCOIN_HEADERS)" ]; then echo BITCOIN_HEADERS incorrect; exit 1; fi
|
||||
|
||||
check-whitespace: check-whitespace/bitcoin/Makefile
|
||||
check-whitespace: $(BITCOIN_SRC:%=check-whitespace/%) $(BITCOIN_HEADERS:%=check-whitespace/%) check-whitespace/bitcoin/Makefile
|
||||
|
||||
clean: bitcoin-clean
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#define LIGHTNING_BITCOIN_ADDRESS_H
|
||||
#include "config.h"
|
||||
#include <ccan/crypto/ripemd160/ripemd160.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
|
||||
/* An address is the RIPEMD160 of the SHA of the public key. */
|
||||
struct bitcoin_address {
|
||||
|
||||
143
bitcoin/base58.c
143
bitcoin/base58.c
@ -3,68 +3,137 @@
|
||||
// Copyright (c) 2009-2012 The Bitcoin Developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#include "config.h"
|
||||
#include <bitcoin/address.h>
|
||||
#include <bitcoin/base58.h>
|
||||
#include <bitcoin/privkey.h>
|
||||
#include <bitcoin/pubkey.h>
|
||||
#include <bitcoin/shadouble.h>
|
||||
#include "address.h"
|
||||
#include "base58.h"
|
||||
#include "privkey.h"
|
||||
#include "pubkey.h"
|
||||
#include "shadouble.h"
|
||||
#include <assert.h>
|
||||
#include <ccan/build_assert/build_assert.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/utils.h>
|
||||
#include <wally_core.h>
|
||||
#include <libbase58.h>
|
||||
#include <string.h>
|
||||
|
||||
static bool my_sha256(void *digest, const void *data, size_t datasz)
|
||||
{
|
||||
sha256(digest, data, datasz);
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *to_base58(const tal_t *ctx, u8 version,
|
||||
const struct ripemd160 *rmd)
|
||||
{
|
||||
char *out;
|
||||
size_t total_length = sizeof(*rmd) + 1;
|
||||
u8 buf[total_length];
|
||||
buf[0] = version;
|
||||
memcpy(buf + 1, rmd, sizeof(*rmd));
|
||||
char out[BASE58_ADDR_MAX_LEN + 1];
|
||||
size_t outlen = sizeof(out);
|
||||
|
||||
tal_wally_start();
|
||||
if (wally_base58_from_bytes((const unsigned char *) buf,
|
||||
total_length, BASE58_FLAG_CHECKSUM, &out)
|
||||
!= WALLY_OK)
|
||||
out = NULL;
|
||||
tal_wally_end_onto(ctx, out, char);
|
||||
|
||||
return out;
|
||||
b58_sha256_impl = my_sha256;
|
||||
if (!b58check_enc(out, &outlen, version, rmd, sizeof(*rmd))) {
|
||||
return NULL;
|
||||
}else{
|
||||
return tal_strdup(ctx, out);
|
||||
}
|
||||
}
|
||||
|
||||
char *bitcoin_to_base58(const tal_t *ctx, const struct chainparams *chainparams,
|
||||
char *bitcoin_to_base58(const tal_t *ctx, bool test_net,
|
||||
const struct bitcoin_address *addr)
|
||||
{
|
||||
return to_base58(ctx, chainparams->p2pkh_version, &addr->addr);
|
||||
return to_base58(ctx, test_net ? 111 : 0, &addr->addr);
|
||||
}
|
||||
|
||||
char *p2sh_to_base58(const tal_t *ctx, const struct chainparams *chainparams,
|
||||
char *p2sh_to_base58(const tal_t *ctx, bool test_net,
|
||||
const struct ripemd160 *p2sh)
|
||||
{
|
||||
return to_base58(ctx, chainparams->p2sh_version, p2sh);
|
||||
return to_base58(ctx, test_net ? 196 : 5, p2sh);
|
||||
}
|
||||
|
||||
static bool from_base58(u8 *version,
|
||||
struct ripemd160 *rmd,
|
||||
const char *base58, size_t base58_len)
|
||||
{
|
||||
/* Initialize to avoid memcheck complaining if decoding a short value */
|
||||
u8 buf[1 + sizeof(*rmd) + 4] = { 0 };
|
||||
const size_t buflen = sizeof(buf);
|
||||
const uint32_t flags = BASE58_FLAG_CHECKSUM;
|
||||
u8 buf[1 + sizeof(*rmd) + 4];
|
||||
/* Avoid memcheck complaining if decoding resulted in a short value */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
b58_sha256_impl = my_sha256;
|
||||
|
||||
size_t written = 0;
|
||||
int r = wally_base58_n_to_bytes(base58, base58_len, flags,
|
||||
buf, buflen, &written);
|
||||
if (r != WALLY_OK || written > buflen) {
|
||||
return false;
|
||||
}
|
||||
size_t buflen = sizeof(buf);
|
||||
b58tobin(buf, &buflen, base58, base58_len);
|
||||
|
||||
int r = b58check(buf, buflen, base58, base58_len);
|
||||
*version = buf[0];
|
||||
memcpy(rmd, buf + 1, sizeof(*rmd));
|
||||
return r >= 0;
|
||||
}
|
||||
|
||||
bool bitcoin_from_base58(bool *test_net,
|
||||
struct bitcoin_address *addr,
|
||||
const char *base58, size_t len)
|
||||
{
|
||||
u8 version;
|
||||
|
||||
if (!from_base58(&version, &addr->addr, base58, len))
|
||||
return false;
|
||||
|
||||
if (version == 111)
|
||||
*test_net = true;
|
||||
else if (version == 0)
|
||||
*test_net = false;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ripemd160_from_base58(u8 *version, struct ripemd160 *rmd,
|
||||
const char *base58, size_t base58_len)
|
||||
bool p2sh_from_base58(bool *test_net,
|
||||
struct ripemd160 *p2sh,
|
||||
const char *base58, size_t len)
|
||||
{
|
||||
return from_base58(version, rmd, base58, base58_len);
|
||||
u8 version;
|
||||
|
||||
if (!from_base58(&version, p2sh, base58, len))
|
||||
return false;
|
||||
|
||||
if (version == 196)
|
||||
*test_net = true;
|
||||
else if (version == 5)
|
||||
*test_net = false;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool key_from_base58(const char *base58, size_t base58_len,
|
||||
bool *test_net, struct privkey *priv, struct pubkey *key)
|
||||
{
|
||||
// 1 byte version, 32 byte private key, 1 byte compressed, 4 byte checksum
|
||||
u8 keybuf[1 + 32 + 1 + 4];
|
||||
size_t keybuflen = sizeof(keybuf);
|
||||
|
||||
b58_sha256_impl = my_sha256;
|
||||
|
||||
b58tobin(keybuf, &keybuflen, base58, base58_len);
|
||||
if (b58check(keybuf, sizeof(keybuf), base58, base58_len) < 0)
|
||||
return false;
|
||||
|
||||
/* Byte after key should be 1 to represent a compressed key. */
|
||||
if (keybuf[1 + 32] != 1)
|
||||
return false;
|
||||
|
||||
if (keybuf[0] == 128)
|
||||
*test_net = false;
|
||||
else if (keybuf[0] == 239)
|
||||
*test_net = true;
|
||||
else
|
||||
return false;
|
||||
|
||||
/* Copy out secret. */
|
||||
memcpy(priv->secret.data, keybuf + 1, sizeof(priv->secret.data));
|
||||
|
||||
if (!secp256k1_ec_seckey_verify(secp256k1_ctx, priv->secret.data))
|
||||
return false;
|
||||
|
||||
/* Get public key, too. */
|
||||
if (!pubkey_from_privkey(priv, key))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2,23 +2,48 @@
|
||||
#define LIGHTNING_BITCOIN_BASE58_H
|
||||
#include "config.h"
|
||||
|
||||
#include <bitcoin/chainparams.h>
|
||||
#include <ccan/crypto/ripemd160/ripemd160.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <secp256k1.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct pubkey;
|
||||
struct privkey;
|
||||
struct bitcoin_address;
|
||||
|
||||
/* Encoding is version byte + ripemd160 + 4-byte checksum == 200 bits => 2^200.
|
||||
*
|
||||
* Now, 58^34 < 2^200, but 58^35 > 2^200. So 35 digits is sufficient,
|
||||
* plus 1 terminator.
|
||||
*/
|
||||
#define BASE58_ADDR_MAX_LEN 36
|
||||
|
||||
/* For encoding private keys, it's 302 bits.
|
||||
* 58^51 < 2^302, but 58^52 > 2^302. So 52 digits, plus one terminator. */
|
||||
#define BASE58_KEY_MAX_LEN 53
|
||||
|
||||
/* Bitcoin address encoded in base58, with version and checksum */
|
||||
char *bitcoin_to_base58(const tal_t *ctx, const struct chainparams *chainparams,
|
||||
char *bitcoin_to_base58(const tal_t *ctx, bool test_net,
|
||||
const struct bitcoin_address *addr);
|
||||
bool bitcoin_from_base58(bool *test_net,
|
||||
struct bitcoin_address *addr,
|
||||
const char *base58, size_t len);
|
||||
|
||||
/* P2SH address encoded as base58, with version and checksum */
|
||||
char *p2sh_to_base58(const tal_t *ctx, const struct chainparams *chainparams,
|
||||
char *p2sh_to_base58(const tal_t *ctx, bool test_net,
|
||||
const struct ripemd160 *p2sh);
|
||||
bool p2sh_from_base58(bool *test_net,
|
||||
struct ripemd160 *p2sh,
|
||||
const char *base58, size_t len);
|
||||
|
||||
/* Decode a p2pkh or p2sh into the ripemd160 hash */
|
||||
bool ripemd160_from_base58(u8 *version, struct ripemd160 *rmd,
|
||||
const char *base58, size_t base58_len);
|
||||
char *base58_with_check(char dest[BASE58_ADDR_MAX_LEN],
|
||||
u8 buf[1 + sizeof(struct ripemd160) + 4]);
|
||||
|
||||
bool key_from_base58(const char *base58, size_t base58_len,
|
||||
bool *test_net, struct privkey *priv, struct pubkey *key);
|
||||
|
||||
void base58_get_checksum(u8 csum[4], const u8 buf[], size_t buflen);
|
||||
|
||||
#endif /* LIGHTNING_BITCOIN_BASE58_H */
|
||||
|
||||
249
bitcoin/block.c
249
bitcoin/block.c
@ -1,152 +1,17 @@
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <bitcoin/block.h>
|
||||
#include <bitcoin/chainparams.h>
|
||||
#include <bitcoin/tx.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
#include "bitcoin/block.h"
|
||||
#include "bitcoin/pullpush.h"
|
||||
#include "bitcoin/tx.h"
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <common/utils.h>
|
||||
|
||||
/* Sets *cursor to NULL and returns NULL when a pull fails. */
|
||||
static const u8 *pull(const u8 **cursor, size_t *max, void *copy, size_t n)
|
||||
{
|
||||
const u8 *p = *cursor;
|
||||
|
||||
if (*max < n) {
|
||||
*cursor = NULL;
|
||||
*max = 0;
|
||||
/* Just make sure we don't leak uninitialized mem! */
|
||||
if (copy)
|
||||
memset(copy, 0, n);
|
||||
return NULL;
|
||||
}
|
||||
*cursor += n;
|
||||
*max -= n;
|
||||
assert(p);
|
||||
if (copy)
|
||||
memcpy(copy, p, n);
|
||||
return memcheck(p, n);
|
||||
}
|
||||
|
||||
static u32 pull_le32(const u8 **cursor, size_t *max)
|
||||
{
|
||||
le32 ret;
|
||||
|
||||
if (!pull(cursor, max, &ret, sizeof(ret)))
|
||||
return 0;
|
||||
return le32_to_cpu(ret);
|
||||
}
|
||||
|
||||
static u64 pull_varint(const u8 **cursor, size_t *max)
|
||||
{
|
||||
u64 ret;
|
||||
size_t len;
|
||||
|
||||
len = varint_get(*cursor, *max, &ret);
|
||||
if (len == 0) {
|
||||
*cursor = NULL;
|
||||
*max = 0;
|
||||
return 0;
|
||||
}
|
||||
pull(cursor, max, NULL, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void sha256_varint(struct sha256_ctx *ctx, u64 val)
|
||||
{
|
||||
u8 vt[VARINT_MAX_LEN];
|
||||
size_t vtlen;
|
||||
vtlen = varint_put(vt, val);
|
||||
sha256_update(ctx, vt, vtlen);
|
||||
}
|
||||
|
||||
static void bitcoin_block_pull_dynafed_params(const u8 **cursor, size_t *len, struct sha256_ctx *shactx)
|
||||
{
|
||||
u8 type;
|
||||
u64 l1, l2;
|
||||
pull(cursor, len, &type, 1);
|
||||
sha256_update(shactx, &type, 1);
|
||||
switch ((enum dynafed_params_type)type) {
|
||||
case DYNAFED_PARAMS_NULL:
|
||||
break;
|
||||
case DYNAFED_PARAMS_COMPACT:
|
||||
/* "scriptPubKey" used for block signing */
|
||||
l1 = pull_varint(cursor, len);
|
||||
sha256_varint(shactx, l1);
|
||||
sha256_update(shactx, *cursor, l1);
|
||||
pull(cursor, len, NULL, l1);
|
||||
|
||||
/* signblock_witness_limit */
|
||||
sha256_update(shactx, *cursor, 4);
|
||||
pull(cursor, len, NULL, 4);
|
||||
|
||||
/* Skip elided_root */
|
||||
sha256_update(shactx, *cursor, 32);
|
||||
pull(cursor, len, NULL, 32);
|
||||
break;
|
||||
|
||||
case DYNAFED_PARAMS_FULL:
|
||||
/* "scriptPubKey" used for block signing */
|
||||
l1 = pull_varint(cursor, len);
|
||||
sha256_varint(shactx, l1);
|
||||
sha256_update(shactx, *cursor, l1);
|
||||
pull(cursor, len, NULL, l1);
|
||||
|
||||
/* signblock_witness_limit */
|
||||
sha256_update(shactx, *cursor, 4);
|
||||
pull(cursor, len, NULL, 4);
|
||||
|
||||
/* fedpeg_program */
|
||||
l1 = pull_varint(cursor, len);
|
||||
sha256_varint(shactx, l1);
|
||||
sha256_update(shactx, *cursor, l1);
|
||||
pull(cursor, len, NULL, l1);
|
||||
|
||||
/* fedpegscript */
|
||||
l1 = pull_varint(cursor, len);
|
||||
sha256_varint(shactx, l1);
|
||||
sha256_update(shactx, *cursor, l1);
|
||||
pull(cursor, len, NULL, l1);
|
||||
|
||||
/* extension space */
|
||||
l2 = pull_varint(cursor, len);
|
||||
sha256_varint(shactx, l2);
|
||||
for (size_t i = 0; i < l2; i++) {
|
||||
l1 = pull_varint(cursor, len);
|
||||
sha256_varint(shactx, l1);
|
||||
sha256_update(shactx, *cursor, l1);
|
||||
pull(cursor, len, NULL, l1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void bitcoin_block_pull_dynafed_details(const u8 **cursor, size_t *len, struct sha256_ctx *shactx)
|
||||
{
|
||||
bitcoin_block_pull_dynafed_params(cursor, len, shactx);
|
||||
bitcoin_block_pull_dynafed_params(cursor, len, shactx);
|
||||
|
||||
/* Consume the signblock_witness */
|
||||
u64 numwitnesses = pull_varint(cursor, len);
|
||||
for (size_t i=0; i<numwitnesses; i++) {
|
||||
u64 witsize = pull_varint(cursor, len);
|
||||
pull(cursor, len, NULL, witsize);
|
||||
}
|
||||
}
|
||||
#include <common/type_to_string.h>
|
||||
|
||||
/* Encoding is <blockhdr> <varint-num-txs> <tx>... */
|
||||
struct bitcoin_block *
|
||||
bitcoin_block_from_hex(const tal_t *ctx, const struct chainparams *chainparams,
|
||||
const char *hex, size_t hexlen)
|
||||
struct bitcoin_block *bitcoin_block_from_hex(const tal_t *ctx,
|
||||
const char *hex, size_t hexlen)
|
||||
{
|
||||
struct bitcoin_block *b;
|
||||
u8 *linear_tx;
|
||||
const u8 *p;
|
||||
size_t len, i, num, templen;
|
||||
struct sha256_ctx shactx;
|
||||
bool is_dynafed;
|
||||
u32 height;
|
||||
size_t len, i, num;
|
||||
|
||||
if (hexlen && hex[hexlen-1] == '\n')
|
||||
hexlen--;
|
||||
@ -160,60 +25,11 @@ bitcoin_block_from_hex(const tal_t *ctx, const struct chainparams *chainparams,
|
||||
if (!hex_decode(hex, hexlen, linear_tx, len))
|
||||
return tal_free(b);
|
||||
|
||||
sha256_init(&shactx);
|
||||
|
||||
b->hdr.version = pull_le32(&p, &len);
|
||||
sha256_le32(&shactx, b->hdr.version);
|
||||
|
||||
pull(&p, &len, &b->hdr.prev_hash, sizeof(b->hdr.prev_hash));
|
||||
sha256_update(&shactx, &b->hdr.prev_hash, sizeof(b->hdr.prev_hash));
|
||||
|
||||
pull(&p, &len, &b->hdr.merkle_hash, sizeof(b->hdr.merkle_hash));
|
||||
sha256_update(&shactx, &b->hdr.merkle_hash, sizeof(b->hdr.merkle_hash));
|
||||
|
||||
b->hdr.timestamp = pull_le32(&p, &len);
|
||||
sha256_le32(&shactx, b->hdr.timestamp);
|
||||
|
||||
if (is_elements(chainparams)) {
|
||||
/* A dynafed block is signalled by setting the MSB of the version. */
|
||||
is_dynafed = (b->hdr.version >> 31 == 1);
|
||||
|
||||
/* elements_header.height */
|
||||
height = pull_le32(&p, &len);
|
||||
sha256_le32(&shactx, height);
|
||||
|
||||
if (is_dynafed) {
|
||||
bitcoin_block_pull_dynafed_details(&p, &len, &shactx);
|
||||
} else {
|
||||
/* elemens_header.challenge */
|
||||
templen = pull_varint(&p, &len);
|
||||
sha256_varint(&shactx, templen);
|
||||
sha256_update(&shactx, p, templen);
|
||||
pull(&p, &len, NULL, templen);
|
||||
|
||||
/* elements_header.solution. Not hashed since it'd be
|
||||
* a circular dependency. */
|
||||
templen = pull_varint(&p, &len);
|
||||
pull(&p, &len, NULL, templen);
|
||||
}
|
||||
|
||||
} else {
|
||||
b->hdr.target = pull_le32(&p, &len);
|
||||
sha256_le32(&shactx, b->hdr.target);
|
||||
|
||||
b->hdr.nonce = pull_le32(&p, &len);
|
||||
sha256_le32(&shactx, b->hdr.nonce);
|
||||
}
|
||||
sha256_double_done(&shactx, &b->hdr.hash.shad);
|
||||
|
||||
pull(&p, &len, &b->hdr, sizeof(b->hdr));
|
||||
num = pull_varint(&p, &len);
|
||||
b->tx = tal_arr(b, struct bitcoin_tx *, num);
|
||||
b->txids = tal_arr(b, struct bitcoin_txid, num);
|
||||
for (i = 0; i < num; i++) {
|
||||
b->tx[i] = pull_bitcoin_tx_only(b->tx, &p, &len);
|
||||
b->tx[i]->chainparams = chainparams;
|
||||
bitcoin_txid(b->tx[i], &b->txids[i]);
|
||||
}
|
||||
for (i = 0; i < num; i++)
|
||||
b->tx[i] = pull_bitcoin_tx(b->tx, &p, &len);
|
||||
|
||||
/* We should end up not overrunning, nor have extra */
|
||||
if (!p || len)
|
||||
@ -223,50 +39,31 @@ bitcoin_block_from_hex(const tal_t *ctx, const struct chainparams *chainparams,
|
||||
return b;
|
||||
}
|
||||
|
||||
void bitcoin_block_blkid(const struct bitcoin_block *b,
|
||||
struct bitcoin_blkid *out)
|
||||
/* We do the same hex-reversing crud as txids. */
|
||||
bool bitcoin_blkid_from_hex(const char *hexstr, size_t hexstr_len,
|
||||
struct bitcoin_blkid *blockid)
|
||||
{
|
||||
*out = b->hdr.hash;
|
||||
struct bitcoin_txid fake_txid;
|
||||
if (!bitcoin_txid_from_hex(hexstr, hexstr_len, &fake_txid))
|
||||
return false;
|
||||
blockid->shad = fake_txid.shad;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool bitcoin_blkid_to_hex(const struct bitcoin_blkid *blockid,
|
||||
char *hexstr, size_t hexstr_len)
|
||||
bool bitcoin_blkid_to_hex(const struct bitcoin_blkid *blockid,
|
||||
char *hexstr, size_t hexstr_len)
|
||||
{
|
||||
struct bitcoin_txid fake_txid;
|
||||
fake_txid.shad = blockid->shad;
|
||||
return bitcoin_txid_to_hex(&fake_txid, hexstr, hexstr_len);
|
||||
}
|
||||
|
||||
char *fmt_bitcoin_blkid(const tal_t *ctx,
|
||||
const struct bitcoin_blkid *blkid)
|
||||
static char *fmt_bitcoin_blkid(const tal_t *ctx,
|
||||
const struct bitcoin_blkid *blkid)
|
||||
{
|
||||
char *hexstr = tal_arr(ctx, char, hex_str_size(sizeof(*blkid)));
|
||||
|
||||
bitcoin_blkid_to_hex(blkid, hexstr, hex_str_size(sizeof(*blkid)));
|
||||
return hexstr;
|
||||
}
|
||||
|
||||
void fromwire_bitcoin_blkid(const u8 **cursor, size_t *max,
|
||||
struct bitcoin_blkid *blkid)
|
||||
{
|
||||
fromwire_sha256_double(cursor, max, &blkid->shad);
|
||||
}
|
||||
|
||||
void towire_bitcoin_blkid(u8 **pptr, const struct bitcoin_blkid *blkid)
|
||||
{
|
||||
towire_sha256_double(pptr, &blkid->shad);
|
||||
}
|
||||
|
||||
|
||||
void towire_chainparams(u8 **cursor, const struct chainparams *chainparams)
|
||||
{
|
||||
towire_bitcoin_blkid(cursor, &chainparams->genesis_blockhash);
|
||||
}
|
||||
|
||||
void fromwire_chainparams(const u8 **cursor, size_t *max,
|
||||
const struct chainparams **chainparams)
|
||||
{
|
||||
struct bitcoin_blkid genesis;
|
||||
fromwire_bitcoin_blkid(cursor, max, &genesis);
|
||||
*chainparams = chainparams_by_chainhash(&genesis);
|
||||
}
|
||||
REGISTER_TYPE_TO_STRING(bitcoin_blkid, fmt_bitcoin_blkid);
|
||||
|
||||
@ -3,16 +3,10 @@
|
||||
#include "config.h"
|
||||
#include "bitcoin/shadouble.h"
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
|
||||
struct chainparams;
|
||||
|
||||
enum dynafed_params_type {
|
||||
DYNAFED_PARAMS_NULL,
|
||||
DYNAFED_PARAMS_COMPACT,
|
||||
DYNAFED_PARAMS_FULL,
|
||||
};
|
||||
#include <stdbool.h>
|
||||
|
||||
struct bitcoin_blkid {
|
||||
struct sha256_double shad;
|
||||
@ -27,33 +21,22 @@ struct bitcoin_block_hdr {
|
||||
le32 timestamp;
|
||||
le32 target;
|
||||
le32 nonce;
|
||||
struct bitcoin_blkid hash;
|
||||
};
|
||||
|
||||
struct bitcoin_block {
|
||||
struct bitcoin_block_hdr hdr;
|
||||
/* tal_count shows now many */
|
||||
struct bitcoin_tx **tx;
|
||||
struct bitcoin_txid *txids;
|
||||
};
|
||||
|
||||
struct bitcoin_block *
|
||||
bitcoin_block_from_hex(const tal_t *ctx, const struct chainparams *chainparams,
|
||||
const char *hex, size_t hexlen);
|
||||
struct bitcoin_block *bitcoin_block_from_hex(const tal_t *ctx,
|
||||
const char *hex, size_t hexlen);
|
||||
|
||||
/* Compute the double SHA block ID from the block header. */
|
||||
void bitcoin_block_blkid(const struct bitcoin_block *block,
|
||||
struct bitcoin_blkid *out);
|
||||
|
||||
/* Marshalling/unmarshaling over the wire */
|
||||
void towire_bitcoin_blkid(u8 **pptr, const struct bitcoin_blkid *blkid);
|
||||
void fromwire_bitcoin_blkid(const u8 **cursor, size_t *max,
|
||||
struct bitcoin_blkid *blkid);
|
||||
void fromwire_chainparams(const u8 **cursor, size_t *max,
|
||||
const struct chainparams **chainparams);
|
||||
void towire_chainparams(u8 **cursor, const struct chainparams *chainparams);
|
||||
|
||||
char *fmt_bitcoin_blkid(const tal_t *ctx,
|
||||
const struct bitcoin_blkid *blkid);
|
||||
/* Parse hex string to get blockid (reversed, a-la bitcoind). */
|
||||
bool bitcoin_blkid_from_hex(const char *hexstr, size_t hexstr_len,
|
||||
struct bitcoin_blkid *blockid);
|
||||
|
||||
/* Get hex string of blockid (reversed, a-la bitcoind). */
|
||||
bool bitcoin_blkid_to_hex(const struct bitcoin_blkid *blockid,
|
||||
char *hexstr, size_t hexstr_len);
|
||||
#endif /* LIGHTNING_BITCOIN_BLOCK_H */
|
||||
|
||||
@ -1,46 +1,15 @@
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <bitcoin/chainparams.h>
|
||||
#include "chainparams.h"
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/utils.h>
|
||||
|
||||
/* Version codes for BIP32 extended keys in libwally-core.
|
||||
* Stolen from wally_bip32.h in libwally-core*/
|
||||
#define BIP32_VER_MAIN_PUBLIC 0x0488B21E
|
||||
#define BIP32_VER_MAIN_PRIVATE 0x0488ADE4
|
||||
#define BIP32_VER_TEST_PUBLIC 0x043587CF
|
||||
#define BIP32_VER_TEST_PRIVATE 0x04358394
|
||||
#define BIP32_VER_SIGT_PUBLIC 0x043587CF
|
||||
#define BIP32_VER_SIGT_PRIVATE 0x04358394
|
||||
|
||||
static u8 liquid_fee_asset[] = {
|
||||
0x01, 0x6d, 0x52, 0x1c, 0x38, 0xec, 0x1e, 0xa1, 0x57, 0x34, 0xae,
|
||||
0x22, 0xb7, 0xc4, 0x60, 0x64, 0x41, 0x28, 0x29, 0xc0, 0xd0, 0x57,
|
||||
0x9f, 0x0a, 0x71, 0x3d, 0x1c, 0x04, 0xed, 0xe9, 0x79, 0x02, 0x6f,
|
||||
};
|
||||
|
||||
static u8 liquid_regtest_fee_asset[] = {
|
||||
0x01, 0x5c, 0xe7, 0xb9, 0x63, 0xd3, 0x7f, 0x8f, 0x2d, 0x51, 0xca,
|
||||
0xfb, 0xba, 0x92, 0x8a, 0xaa, 0x9e, 0x22, 0x0b, 0x8b, 0xbc, 0x66,
|
||||
0x05, 0x71, 0x49, 0x9c, 0x03, 0x62, 0x8a, 0x38, 0x51, 0xb8, 0xce,
|
||||
};
|
||||
#include <ccan/str/str.h>
|
||||
#include <string.h>
|
||||
|
||||
const struct chainparams networks[] = {
|
||||
{.network_name = "bitcoin",
|
||||
.onchain_hrp = "bc",
|
||||
.lightning_hrp = "bc",
|
||||
.bip70_name = "main",
|
||||
.genesis_blockhash = {{{.u.u8 = {0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3,
|
||||
0x72, 0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63,
|
||||
0xf7, 0x4f, 0x93, 0x1e, 0x83, 0x65, 0xe1,
|
||||
0x5a, 0x08, 0x9c, 0x68, 0xd6, 0x19, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00}}}},
|
||||
.bip173_name = "bc",
|
||||
.genesis_blockhash = {{{.u.u8 = {0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, 0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f, 0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c, 0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00}}}},
|
||||
.rpc_port = 8332,
|
||||
.ln_port = 9735,
|
||||
.cli = "bitcoin-cli",
|
||||
.cli_args = NULL,
|
||||
.cli_min_supported_version = 150000,
|
||||
.dust_limit = { 546 },
|
||||
/* BOLT #2:
|
||||
*
|
||||
@ -50,221 +19,52 @@ const struct chainparams networks[] = {
|
||||
*/
|
||||
.max_funding = AMOUNT_SAT_INIT((1 << 24) - 1),
|
||||
.max_payment = AMOUNT_MSAT_INIT(0xFFFFFFFFULL),
|
||||
.max_supply = AMOUNT_SAT_INIT(2100000000000000),
|
||||
/* "Lightning Charge Powers Developers & Blockstream Store" */
|
||||
.when_lightning_became_cool = 504500,
|
||||
.p2pkh_version = 0,
|
||||
.p2sh_version = 5,
|
||||
.testnet = false,
|
||||
.fee_asset_tag = NULL,
|
||||
.bip32_key_version = {.bip32_pubkey_version = BIP32_VER_MAIN_PUBLIC,
|
||||
.bip32_privkey_version = BIP32_VER_MAIN_PRIVATE},
|
||||
.is_elements = false},
|
||||
.testnet = false},
|
||||
{.network_name = "regtest",
|
||||
.onchain_hrp = "bcrt",
|
||||
.lightning_hrp = "bcrt",
|
||||
.bip70_name = "regtest",
|
||||
.genesis_blockhash = {{{.u.u8 = {0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b,
|
||||
0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb,
|
||||
0x5b, 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e,
|
||||
0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c,
|
||||
0xf1, 0x88, 0x91, 0x0f}}}},
|
||||
.rpc_port = 18443,
|
||||
.ln_port = 19846,
|
||||
.bip173_name = "bcrt",
|
||||
.genesis_blockhash = {{{.u.u8 = {0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f}}}},
|
||||
.rpc_port = 18332,
|
||||
.cli = "bitcoin-cli",
|
||||
.cli_args = "-regtest",
|
||||
.cli_min_supported_version = 150000,
|
||||
.dust_limit = { 546 },
|
||||
.max_funding = AMOUNT_SAT_INIT((1 << 24) - 1),
|
||||
.max_payment = AMOUNT_MSAT_INIT(0xFFFFFFFFULL),
|
||||
.max_supply = AMOUNT_SAT_INIT(2100000000000000),
|
||||
.when_lightning_became_cool = 1,
|
||||
.p2pkh_version = 111,
|
||||
.p2sh_version = 196,
|
||||
.testnet = true,
|
||||
.fee_asset_tag = NULL,
|
||||
.bip32_key_version = {.bip32_pubkey_version = BIP32_VER_TEST_PUBLIC,
|
||||
.bip32_privkey_version = BIP32_VER_TEST_PRIVATE},
|
||||
.is_elements = false},
|
||||
{.network_name = "signet",
|
||||
.onchain_hrp = "tb",
|
||||
.lightning_hrp = "tbs",
|
||||
.bip70_name = "signet",
|
||||
// 00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6
|
||||
.genesis_blockhash = {{{.u.u8 = {0xf6, 0x1e, 0xee, 0x3b, 0x63, 0xa3, 0x80,
|
||||
0xa4, 0x77, 0xa0, 0x63, 0xaf, 0x32, 0xb2,
|
||||
0xbb, 0xc9, 0x7c, 0x9f, 0xf9, 0xf0, 0x1f,
|
||||
0x2c, 0x42, 0x25, 0xe9, 0x73, 0x98, 0x81,
|
||||
0x08, 0x00, 0x00, 0x00}}}},
|
||||
.rpc_port = 38332,
|
||||
.ln_port = 39735,
|
||||
.cli = "bitcoin-cli",
|
||||
.cli_args = "-signet",
|
||||
.cli_min_supported_version = 150000,
|
||||
.dust_limit = { 546 },
|
||||
.max_funding = AMOUNT_SAT_INIT((1 << 24) - 1),
|
||||
.max_payment = AMOUNT_MSAT_INIT(0xFFFFFFFFULL),
|
||||
.max_supply = AMOUNT_SAT_INIT(2100000000000000),
|
||||
.when_lightning_became_cool = 1,
|
||||
.p2pkh_version = 111,
|
||||
.p2sh_version = 196,
|
||||
.testnet = true,
|
||||
.bip32_key_version = {.bip32_pubkey_version = BIP32_VER_SIGT_PUBLIC, .bip32_privkey_version = BIP32_VER_SIGT_PRIVATE},
|
||||
.is_elements = false,
|
||||
},
|
||||
.testnet = true},
|
||||
{.network_name = "testnet",
|
||||
.onchain_hrp = "tb",
|
||||
.lightning_hrp = "tb",
|
||||
.bip70_name = "test",
|
||||
.genesis_blockhash = {{{.u.u8 = {0x43, 0x49, 0x7f, 0xd7, 0xf8, 0x26, 0x95,
|
||||
0x71, 0x08, 0xf4, 0xa3, 0x0f, 0xd9, 0xce,
|
||||
0xc3, 0xae, 0xba, 0x79, 0x97, 0x20, 0x84,
|
||||
0xe9, 0x0e, 0xad, 0x01, 0xea, 0x33, 0x09,
|
||||
0x00, 0x00, 0x00, 0x00}}}},
|
||||
.bip173_name = "tb",
|
||||
.genesis_blockhash = {{{.u.u8 = {0x43, 0x49, 0x7f, 0xd7, 0xf8, 0x26, 0x95, 0x71, 0x08, 0xf4, 0xa3, 0x0f, 0xd9, 0xce, 0xc3, 0xae, 0xba, 0x79, 0x97, 0x20, 0x84, 0xe9, 0x0e, 0xad, 0x01, 0xea, 0x33, 0x09, 0x00, 0x00, 0x00, 0x00}}}},
|
||||
.rpc_port = 18332,
|
||||
.ln_port = 19735,
|
||||
.cli = "bitcoin-cli",
|
||||
.cli_args = "-testnet",
|
||||
.cli_min_supported_version = 150000,
|
||||
.dust_limit = { 546 },
|
||||
.max_funding = AMOUNT_SAT_INIT((1 << 24) - 1),
|
||||
.max_payment = AMOUNT_MSAT_INIT(0xFFFFFFFFULL),
|
||||
.max_supply = AMOUNT_SAT_INIT(2100000000000000),
|
||||
.p2pkh_version = 111,
|
||||
.p2sh_version = 196,
|
||||
.testnet = true,
|
||||
.fee_asset_tag = NULL,
|
||||
.bip32_key_version = {.bip32_pubkey_version = BIP32_VER_TEST_PUBLIC,
|
||||
.bip32_privkey_version = BIP32_VER_TEST_PRIVATE},
|
||||
.is_elements = false},
|
||||
{.network_name = "testnet4",
|
||||
.onchain_hrp = "tb",
|
||||
.lightning_hrp = "tb",
|
||||
.bip70_name = "testnet4",
|
||||
// 00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043
|
||||
.genesis_blockhash = {{{.u.u8 = {0x43, 0xf0, 0x8b, 0xda, 0xb0, 0x50, 0xe3,
|
||||
0x5b, 0x56, 0x7c, 0x86, 0x4b, 0x91, 0xf4,
|
||||
0x7f, 0x50, 0xae, 0x72, 0x5a, 0xe2, 0xde,
|
||||
0x53, 0xbc, 0xfb, 0xba, 0xf2, 0x84, 0xda,
|
||||
0x00, 0x00, 0x00, 0x00}}}},
|
||||
.rpc_port = 48332,
|
||||
.ln_port = 49735,
|
||||
.cli = "bitcoin-cli",
|
||||
.cli_args = "-testnet4",
|
||||
.cli_min_supported_version = 150000,
|
||||
.dust_limit = { 546 },
|
||||
.max_funding = AMOUNT_SAT_INIT((1 << 24) - 1),
|
||||
.max_payment = AMOUNT_MSAT_INIT(0xFFFFFFFFULL),
|
||||
.max_supply = AMOUNT_SAT_INIT(2100000000000000),
|
||||
.p2pkh_version = 111,
|
||||
.p2sh_version = 196,
|
||||
.testnet = true,
|
||||
.fee_asset_tag = NULL,
|
||||
.bip32_key_version = {.bip32_pubkey_version = BIP32_VER_TEST_PUBLIC,
|
||||
.bip32_privkey_version = BIP32_VER_TEST_PRIVATE},
|
||||
.is_elements = false},
|
||||
.testnet = true},
|
||||
{.network_name = "litecoin",
|
||||
.onchain_hrp = "ltc",
|
||||
.lightning_hrp = "ltc",
|
||||
.bip70_name = "main",
|
||||
.genesis_blockhash = {{{.u.u8 = {0xe2, 0xbf, 0x04, 0x7e, 0x7e, 0x5a, 0x19,
|
||||
0x1a, 0xa4, 0xef, 0x34, 0xd3, 0x14, 0x97,
|
||||
0x9d, 0xc9, 0x98, 0x6e, 0x0f, 0x19, 0x25,
|
||||
0x1e, 0xda, 0xba, 0x59, 0x40, 0xfd, 0x1f,
|
||||
0xe3, 0x65, 0xa7, 0x12}}}},
|
||||
.bip173_name = "ltc",
|
||||
.genesis_blockhash = {{{.u.u8 = {0xe2, 0xbf, 0x04, 0x7e, 0x7e, 0x5a, 0x19, 0x1a, 0xa4, 0xef, 0x34, 0xd3, 0x14, 0x97, 0x9d, 0xc9, 0x98, 0x6e, 0x0f, 0x19, 0x25, 0x1e, 0xda, 0xba, 0x59, 0x40, 0xfd, 0x1f, 0xe3, 0x65, 0xa7, 0x12 }}}},
|
||||
.rpc_port = 9332,
|
||||
.ln_port = 9735,
|
||||
.cli = "litecoin-cli",
|
||||
.cli_args = NULL,
|
||||
.cli_min_supported_version = 150000,
|
||||
.dust_limit = { 100000 },
|
||||
.max_funding = AMOUNT_SAT_INIT(60 * ((1 << 24) - 1)),
|
||||
.max_payment = AMOUNT_MSAT_INIT(60 * 0xFFFFFFFFULL),
|
||||
.max_supply = AMOUNT_SAT_INIT(2100000000000000),
|
||||
.when_lightning_became_cool = 1320000,
|
||||
.p2pkh_version = 48,
|
||||
.p2sh_version = 50,
|
||||
.testnet = false,
|
||||
.fee_asset_tag = NULL,
|
||||
.bip32_key_version = {.bip32_pubkey_version = BIP32_VER_MAIN_PUBLIC,
|
||||
.bip32_privkey_version = BIP32_VER_MAIN_PRIVATE},
|
||||
.is_elements = false},
|
||||
.testnet = false},
|
||||
{.network_name = "litecoin-testnet",
|
||||
.onchain_hrp = "tltc",
|
||||
.lightning_hrp = "tltc",
|
||||
.bip70_name = "test",
|
||||
.genesis_blockhash = {{{.u.u8 = {0xa0, 0x29, 0x3e, 0x4e, 0xeb, 0x3d, 0xa6,
|
||||
0xe6, 0xf5, 0x6f, 0x81, 0xed, 0x59, 0x5f,
|
||||
0x57, 0x88, 0x0d, 0x1a, 0x21, 0x56, 0x9e,
|
||||
0x13, 0xee, 0xfd, 0xd9, 0x51, 0x28, 0x4b,
|
||||
0x5a, 0x62, 0x66, 0x49}}}},
|
||||
.bip173_name = "tltc",
|
||||
.genesis_blockhash = {{{.u.u8 = { 0xa0, 0x29, 0x3e, 0x4e, 0xeb, 0x3d, 0xa6, 0xe6, 0xf5, 0x6f, 0x81, 0xed, 0x59, 0x5f, 0x57, 0x88, 0x0d, 0x1a, 0x21, 0x56, 0x9e, 0x13, 0xee, 0xfd, 0xd9, 0x51, 0x28, 0x4b, 0x5a, 0x62, 0x66, 0x49 }}}},
|
||||
.rpc_port = 19332,
|
||||
.ln_port = 9735,
|
||||
.cli = "litecoin-cli",
|
||||
.cli_args = "-testnet",
|
||||
.cli_min_supported_version = 150000,
|
||||
.dust_limit = { 100000 },
|
||||
.max_funding = AMOUNT_SAT_INIT(60 * ((1 << 24) - 1)),
|
||||
.max_payment = AMOUNT_MSAT_INIT(60 * 0xFFFFFFFFULL),
|
||||
.max_supply = AMOUNT_SAT_INIT(2100000000000000),
|
||||
.when_lightning_became_cool = 1,
|
||||
.p2pkh_version = 111,
|
||||
.p2sh_version = 58,
|
||||
.testnet = true,
|
||||
.fee_asset_tag = NULL,
|
||||
.bip32_key_version = {.bip32_pubkey_version = BIP32_VER_TEST_PUBLIC,
|
||||
.bip32_privkey_version = BIP32_VER_TEST_PRIVATE},
|
||||
.is_elements = false},
|
||||
{.network_name = "liquid-regtest",
|
||||
.onchain_hrp = "ert",
|
||||
.lightning_hrp = "ert",
|
||||
.bip70_name = "liquid-regtest",
|
||||
.genesis_blockhash = {{{.u.u8 = {0x9f, 0x87, 0xeb, 0x58, 0x0b, 0x9e, 0x5f,
|
||||
0x11, 0xdc, 0x21, 0x1e, 0x9f, 0xb6, 0x6a,
|
||||
0xbb, 0x36, 0x99, 0x99, 0x90, 0x44, 0xf8,
|
||||
0xfe, 0x14, 0x68, 0x01, 0x16, 0x23, 0x93,
|
||||
0x36, 0x42, 0x86, 0xc6}}}},
|
||||
.rpc_port = 19332,
|
||||
.ln_port = 20735,
|
||||
.cli = "elements-cli",
|
||||
.cli_args = "-chain=liquid-regtest",
|
||||
.dust_limit = {546},
|
||||
.max_funding = AMOUNT_SAT_INIT((1 << 24) - 1),
|
||||
.max_payment = AMOUNT_MSAT_INIT(0xFFFFFFFFULL),
|
||||
.max_supply = AMOUNT_SAT_INIT(2100000000000000),
|
||||
.when_lightning_became_cool = 1,
|
||||
.p2pkh_version = 91,
|
||||
.p2sh_version = 75,
|
||||
.testnet = true,
|
||||
.fee_asset_tag = liquid_regtest_fee_asset,
|
||||
.bip32_key_version = {.bip32_pubkey_version = BIP32_VER_TEST_PUBLIC,
|
||||
.bip32_privkey_version = BIP32_VER_TEST_PRIVATE},
|
||||
.is_elements = true},
|
||||
{.network_name = "liquid",
|
||||
.onchain_hrp = "ex",
|
||||
.lightning_hrp = "ex",
|
||||
.bip70_name = "liquidv1",
|
||||
.genesis_blockhash = {{{.u.u8 = {0x14, 0x66, 0x27, 0x58, 0x36, 0x22, 0x0d,
|
||||
0xb2, 0x94, 0x4c, 0xa0, 0x59, 0xa3, 0xa1,
|
||||
0x0e, 0xf6, 0xfd, 0x2e, 0xa6, 0x84, 0xb0,
|
||||
0x68, 0x8d, 0x2c, 0x37, 0x92, 0x96, 0x88,
|
||||
0x8a, 0x20, 0x60, 0x03}}}},
|
||||
.rpc_port = 7041,
|
||||
.ln_port = 9735,
|
||||
.cli = "elements-cli",
|
||||
.cli_args = "-chain=liquidv1",
|
||||
.dust_limit = {546},
|
||||
.max_funding = AMOUNT_SAT_INIT((1 << 24) - 1),
|
||||
.max_payment = AMOUNT_MSAT_INIT(0xFFFFFFFFULL),
|
||||
.max_supply = AMOUNT_SAT_INIT(2100000000000000),
|
||||
.when_lightning_became_cool = 1,
|
||||
.p2pkh_version = 57,
|
||||
.p2sh_version = 39,
|
||||
.testnet = false,
|
||||
.fee_asset_tag = liquid_fee_asset,
|
||||
.bip32_key_version = {.bip32_pubkey_version = BIP32_VER_MAIN_PUBLIC,
|
||||
.bip32_privkey_version = BIP32_VER_MAIN_PRIVATE},
|
||||
.is_elements = true},
|
||||
.testnet = true}
|
||||
};
|
||||
|
||||
const struct chainparams *chainparams_for_network(const char *network_name)
|
||||
@ -287,26 +87,12 @@ const struct chainparams *chainparams_by_chainhash(const struct bitcoin_blkid *c
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct chainparams *chainparams_by_lightning_hrp(const char *lightning_hrp)
|
||||
const struct chainparams *chainparams_by_bip173(const char *bip173_name)
|
||||
{
|
||||
for (size_t i = 0; i < ARRAY_SIZE(networks); i++) {
|
||||
if (streq(lightning_hrp, networks[i].lightning_hrp)) {
|
||||
if (streq(bip173_name, networks[i].bip173_name)) {
|
||||
return &networks[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *chainparams_get_network_names(const tal_t *ctx)
|
||||
{
|
||||
char *networks_string = tal_strdup(ctx, networks[0].network_name);
|
||||
for (size_t i = 1; i < ARRAY_SIZE(networks); ++i)
|
||||
tal_append_fmt(&networks_string, ", %s", networks[i].network_name);
|
||||
return networks_string;
|
||||
}
|
||||
|
||||
int chainparams_get_ln_port(const struct chainparams *params)
|
||||
{
|
||||
assert(params);
|
||||
return params->ln_port;
|
||||
}
|
||||
|
||||
@ -3,55 +3,24 @@
|
||||
|
||||
#include "config.h"
|
||||
#include <bitcoin/block.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <common/amount.h>
|
||||
#include <common/bip32.h>
|
||||
|
||||
#define ELEMENTS_ASSET_LEN 33
|
||||
#include <stdbool.h>
|
||||
|
||||
struct chainparams {
|
||||
const char *network_name;
|
||||
/* Unfortunately starting with signet, we now have diverging
|
||||
* conventions for the "BIP173" Human Readable Part (HRP).
|
||||
* On onchain signet, the HRP is `tb` , but on Lightning
|
||||
* signet the HRP is `tbs`.
|
||||
*/
|
||||
const char *onchain_hrp;
|
||||
const char *lightning_hrp;
|
||||
/*'bip70_name' is corresponding to the 'chain' field of
|
||||
* the API 'getblockchaininfo' */
|
||||
const char *bip70_name;
|
||||
const char *bip173_name;
|
||||
const struct bitcoin_blkid genesis_blockhash;
|
||||
const int rpc_port;
|
||||
/**
|
||||
* BOLT 1:
|
||||
*
|
||||
* The default TCP port depends on the network used. The most common networks are:
|
||||
*
|
||||
* - Bitcoin mainet with port number 9735 or the corresponding hexadecimal `0x2607`;
|
||||
* - Bitcoin testnet with port number 19735 (`0x4D17`);
|
||||
* - Bitcoin signet with port number 39735 (`0x9B37`).
|
||||
*/
|
||||
const int ln_port;
|
||||
const char *cli;
|
||||
const char *cli_args;
|
||||
/* The min numeric version of cli supported */
|
||||
const u64 cli_min_supported_version;
|
||||
const struct amount_sat dust_limit;
|
||||
const struct amount_sat max_funding;
|
||||
const struct amount_msat max_payment;
|
||||
/* Total coins in network */
|
||||
const struct amount_sat max_supply;
|
||||
const u32 when_lightning_became_cool;
|
||||
const u8 p2pkh_version;
|
||||
const u8 p2sh_version;
|
||||
|
||||
/* Whether this is a test network or not */
|
||||
const bool testnet;
|
||||
|
||||
/* Version codes for BIP32 extended keys in libwally-core*/
|
||||
const struct bip32_key_version bip32_key_version;
|
||||
const bool is_elements;
|
||||
const u8 *fee_asset_tag;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -64,21 +33,11 @@ const struct chainparams *chainparams_for_network(const char *network_name);
|
||||
*
|
||||
* This lets us decode BOLT11 addresses.
|
||||
*/
|
||||
const struct chainparams *chainparams_by_lightning_hrp(const char *lightning_hrp);
|
||||
const struct chainparams *chainparams_by_bip173(const char *bip173_name);
|
||||
|
||||
/**
|
||||
* chainparams_by_chainhash - Helper to get a network by its genesis blockhash
|
||||
*/
|
||||
const struct chainparams *chainparams_by_chainhash(const struct bitcoin_blkid *chain_hash);
|
||||
|
||||
/**
|
||||
* chainparams_get_network_names - Produce a comma-separated list of network names
|
||||
*/
|
||||
const char *chainparams_get_network_names(const tal_t *ctx);
|
||||
|
||||
/**
|
||||
* chainparams_get_ln_port - Return the lightning network default port by
|
||||
* network if the chainparams is initialized, otherwise 9735 as mock port
|
||||
*/
|
||||
int chainparams_get_ln_port(const struct chainparams *params);
|
||||
#endif /* LIGHTNING_BITCOIN_CHAINPARAMS_H */
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <bitcoin/feerate.h>
|
||||
|
||||
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;
|
||||
case FEERATE_PER_KBYTE:
|
||||
/* Everyone uses satoshi per kbyte, but we use satoshi per ksipa
|
||||
* (don't round down to zero though)! */
|
||||
return (feerate + 3) / 4;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
u32 feerate_to_style(u32 feerate_perkw, enum feerate_style style)
|
||||
{
|
||||
switch (style) {
|
||||
case FEERATE_PER_KSIPA:
|
||||
return feerate_perkw;
|
||||
case FEERATE_PER_KBYTE:
|
||||
if ((u64)feerate_perkw * 4 > UINT_MAX)
|
||||
return UINT_MAX;
|
||||
return feerate_perkw * 4;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
const char *feerate_style_name(enum feerate_style style)
|
||||
{
|
||||
switch (style) {
|
||||
case FEERATE_PER_KBYTE:
|
||||
return "perkb";
|
||||
case FEERATE_PER_KSIPA:
|
||||
return "perkw";
|
||||
}
|
||||
abort();
|
||||
}
|
||||
@ -3,7 +3,6 @@
|
||||
#include "config.h"
|
||||
#include <ccan/build_assert/build_assert.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <common/amount.h>
|
||||
|
||||
/* bitcoind considers 250 satoshi per kw to be the minimum acceptable fee:
|
||||
* less than this won't even relay.
|
||||
@ -34,12 +33,7 @@
|
||||
*/
|
||||
#define FEERATE_FLOOR 253
|
||||
|
||||
enum feerate_style {
|
||||
FEERATE_PER_KSIPA,
|
||||
FEERATE_PER_KBYTE
|
||||
};
|
||||
|
||||
static inline u32 feerate_floor_check(void)
|
||||
static inline u32 feerate_floor(void)
|
||||
{
|
||||
/* Assert that bitcoind will see this as above minRelayTxFee */
|
||||
BUILD_ASSERT(FEERATE_BITCOIND_SEES(FEERATE_FLOOR, MINIMUM_TX_WEIGHT)
|
||||
@ -53,9 +47,4 @@ static inline u32 feerate_floor_check(void)
|
||||
|
||||
return FEERATE_FLOOR;
|
||||
}
|
||||
|
||||
u32 feerate_from_style(u32 feerate, enum feerate_style style);
|
||||
u32 feerate_to_style(u32 feerate_perkw, enum feerate_style style);
|
||||
const char *feerate_style_name(enum feerate_style style);
|
||||
|
||||
#endif /* LIGHTNING_BITCOIN_FEERATE_H */
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <bitcoin/locktime.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/type_to_string.h>
|
||||
|
||||
#define SECONDS_POINT 500000000
|
||||
|
||||
@ -22,13 +22,60 @@ static bool abs_is_seconds(u32 locktime)
|
||||
return locktime >= SECONDS_POINT;
|
||||
}
|
||||
|
||||
bool rel_locktime_is_seconds(const struct rel_locktime *rel)
|
||||
{
|
||||
return rel->locktime & BIP68_SECONDS_FLAG;
|
||||
}
|
||||
|
||||
u32 rel_locktime_to_seconds(const struct rel_locktime *rel)
|
||||
{
|
||||
assert(rel_locktime_is_seconds(rel));
|
||||
return (rel->locktime & BIP68_LOCKTIME_MASK) << BIP68_SECONDS_SHIFT;
|
||||
}
|
||||
|
||||
u32 rel_locktime_to_blocks(const struct rel_locktime *rel)
|
||||
{
|
||||
assert(!rel_locktime_is_seconds(rel));
|
||||
return rel->locktime & BIP68_LOCKTIME_MASK;
|
||||
}
|
||||
|
||||
bool blocks_to_abs_locktime(u32 blocks, struct abs_locktime *abs)
|
||||
{
|
||||
return abs_blocks_to_locktime(blocks, &abs->locktime);
|
||||
}
|
||||
|
||||
u32 abs_locktime_to_blocks(const struct abs_locktime *abs)
|
||||
bool abs_locktime_is_seconds(const struct abs_locktime *abs)
|
||||
{
|
||||
assert(!abs_is_seconds(abs->locktime));
|
||||
return abs_is_seconds(abs->locktime);
|
||||
}
|
||||
|
||||
u32 abs_locktime_to_seconds(const struct abs_locktime *abs)
|
||||
{
|
||||
assert(abs_locktime_is_seconds(abs));
|
||||
return abs->locktime;
|
||||
}
|
||||
|
||||
u32 abs_locktime_to_blocks(const struct abs_locktime *abs)
|
||||
{
|
||||
assert(!abs_locktime_is_seconds(abs));
|
||||
return abs->locktime;
|
||||
}
|
||||
|
||||
static char *fmt_rel_locktime(const tal_t *ctx, const struct rel_locktime *rl)
|
||||
{
|
||||
if (rel_locktime_is_seconds(rl))
|
||||
return tal_fmt(ctx, "+%usec", rel_locktime_to_seconds(rl));
|
||||
else
|
||||
return tal_fmt(ctx, "+%ublocks", rel_locktime_to_blocks(rl));
|
||||
}
|
||||
|
||||
static char *fmt_abs_locktime(const tal_t *ctx, const struct abs_locktime *al)
|
||||
{
|
||||
if (abs_locktime_is_seconds(al))
|
||||
return tal_fmt(ctx, "%usec", abs_locktime_to_seconds(al));
|
||||
else
|
||||
return tal_fmt(ctx, "%ublocks", abs_locktime_to_blocks(al));
|
||||
}
|
||||
|
||||
REGISTER_TYPE_TO_STRING(rel_locktime, fmt_rel_locktime);
|
||||
REGISTER_TYPE_TO_STRING(abs_locktime, fmt_abs_locktime);
|
||||
|
||||
@ -4,12 +4,23 @@
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* As used by nSequence and OP_CHECKSEQUENCEVERIFY (BIP68) */
|
||||
struct rel_locktime {
|
||||
u32 locktime;
|
||||
};
|
||||
|
||||
bool rel_locktime_is_seconds(const struct rel_locktime *rel);
|
||||
u32 rel_locktime_to_seconds(const struct rel_locktime *rel);
|
||||
u32 rel_locktime_to_blocks(const struct rel_locktime *rel);
|
||||
|
||||
/* As used by nLocktime and OP_CHECKLOCKTIMEVERIFY (BIP65) */
|
||||
struct abs_locktime {
|
||||
u32 locktime;
|
||||
};
|
||||
|
||||
bool blocks_to_abs_locktime(u32 blocks, struct abs_locktime *abs);
|
||||
bool abs_locktime_is_seconds(const struct abs_locktime *abs);
|
||||
u32 abs_locktime_to_seconds(const struct abs_locktime *abs);
|
||||
u32 abs_locktime_to_blocks(const struct abs_locktime *abs);
|
||||
|
||||
#endif /* LIGHTNING_BITCOIN_LOCKTIME_H */
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
#include "config.h"
|
||||
#include <bitcoin/preimage.h>
|
||||
#include <common/utils.h>
|
||||
#include <wire/wire.h>
|
||||
|
||||
void fromwire_preimage(const u8 **cursor, size_t *max, struct preimage *preimage)
|
||||
{
|
||||
fromwire(cursor, max, preimage, sizeof(*preimage));
|
||||
}
|
||||
|
||||
void towire_preimage(u8 **pptr, const struct preimage *preimage)
|
||||
{
|
||||
towire(pptr, preimage, sizeof(*preimage));
|
||||
}
|
||||
|
||||
char *fmt_preimage(const tal_t *ctx, const struct preimage *preimage)
|
||||
{
|
||||
return tal_hexstr(ctx, preimage, sizeof(*preimage));
|
||||
}
|
||||
@ -3,7 +3,6 @@
|
||||
#include "config.h"
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
|
||||
struct preimage {
|
||||
u8 r[32];
|
||||
@ -11,8 +10,4 @@ struct preimage {
|
||||
/* Define preimage_eq */
|
||||
STRUCTEQ_DEF(preimage, 0, r);
|
||||
|
||||
void fromwire_preimage(const u8 **cursor, size_t *max, struct preimage *preimage);
|
||||
void towire_preimage(u8 **pptr, const struct preimage *preimage);
|
||||
|
||||
char *fmt_preimage(const tal_t *ctx, const struct preimage *preimage);
|
||||
#endif /* LIGHTNING_BITCOIN_PREIMAGE_H */
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
#include "config.h"
|
||||
#include <bitcoin/privkey.h>
|
||||
#include "privkey.h"
|
||||
#include <assert.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <common/utils.h>
|
||||
#include <wire/wire.h>
|
||||
#include <common/type_to_string.h>
|
||||
|
||||
char *fmt_privkey(const tal_t *ctx, const struct privkey *secret)
|
||||
static char *privkey_to_hexstr(const tal_t *ctx, const struct privkey *secret)
|
||||
{
|
||||
/* Bitcoin appends "01" to indicate the pubkey is compressed. */
|
||||
char *str = tal_arr(ctx, char, hex_str_size(sizeof(*secret) + 1));
|
||||
@ -12,11 +12,8 @@ char *fmt_privkey(const tal_t *ctx, const struct privkey *secret)
|
||||
strcat(str, "01");
|
||||
return str;
|
||||
}
|
||||
|
||||
char *fmt_secret(const tal_t *ctx, const struct secret *secret)
|
||||
{
|
||||
return tal_hexstr(ctx, secret, sizeof(*secret));
|
||||
}
|
||||
REGISTER_TYPE_TO_STRING(privkey, privkey_to_hexstr);
|
||||
REGISTER_TYPE_TO_HEXSTR(secret);
|
||||
|
||||
bool secret_eq_consttime(const struct secret *a, const struct secret *b)
|
||||
{
|
||||
@ -25,23 +22,3 @@ bool secret_eq_consttime(const struct secret *a, const struct secret *b)
|
||||
result |= a->data[i] ^ b->data[i];
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
void towire_privkey(u8 **pptr, const struct privkey *privkey)
|
||||
{
|
||||
towire_secret(pptr, &privkey->secret);
|
||||
}
|
||||
|
||||
void towire_secret(u8 **pptr, const struct secret *secret)
|
||||
{
|
||||
towire(pptr, secret->data, sizeof(secret->data));
|
||||
}
|
||||
|
||||
void fromwire_secret(const u8 **cursor, size_t *max, struct secret *secret)
|
||||
{
|
||||
fromwire(cursor, max, secret->data, sizeof(secret->data));
|
||||
}
|
||||
|
||||
void fromwire_privkey(const u8 **cursor, size_t *max, struct privkey *privkey)
|
||||
{
|
||||
fromwire_secret(cursor, max, &privkey->secret);
|
||||
}
|
||||
|
||||
@ -3,9 +3,6 @@
|
||||
#include "config.h"
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
|
||||
#define PRIVKEY_LEN 32
|
||||
|
||||
/* General 256-bit secret, which must be private. Used in various places. */
|
||||
struct secret {
|
||||
@ -19,14 +16,4 @@ bool secret_eq_consttime(const struct secret *a, const struct secret *b);
|
||||
struct privkey {
|
||||
struct secret secret;
|
||||
};
|
||||
|
||||
/* marshal/unmarshal functions */
|
||||
void fromwire_secret(const u8 **cursor, size_t *max, struct secret *secret);
|
||||
void fromwire_privkey(const u8 **cursor, size_t *max, struct privkey *privkey);
|
||||
void towire_privkey(u8 **pptr, const struct privkey *privkey);
|
||||
void towire_secret(u8 **pptr, const struct secret *secret);
|
||||
|
||||
char *fmt_privkey(const tal_t *ctx, const struct privkey *privkey);
|
||||
char *fmt_secret(const tal_t *ctx, const struct secret *secret);
|
||||
|
||||
#endif /* LIGHTNING_BITCOIN_PRIVKEY_H */
|
||||
|
||||
1084
bitcoin/psbt.c
1084
bitcoin/psbt.c
File diff suppressed because it is too large
Load Diff
337
bitcoin/psbt.h
337
bitcoin/psbt.h
@ -1,337 +0,0 @@
|
||||
#ifndef LIGHTNING_BITCOIN_PSBT_H
|
||||
#define LIGHTNING_BITCOIN_PSBT_H
|
||||
#include "config.h"
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
|
||||
struct wally_psbt;
|
||||
struct wally_psbt_input;
|
||||
struct wally_tx;
|
||||
struct wally_tx_input;
|
||||
struct wally_tx_output;
|
||||
struct wally_map;
|
||||
struct amount_asset;
|
||||
struct amount_sat;
|
||||
struct bitcoin_outpoint;
|
||||
struct bitcoin_signature;
|
||||
struct bitcoin_txid;
|
||||
struct pubkey;
|
||||
|
||||
|
||||
/* Utility we need for psbt stuffs;
|
||||
* add the varint onto the given array */
|
||||
void add_varint(u8 **arr, size_t val);
|
||||
|
||||
/**
|
||||
* create_psbt - Create a new psbt object
|
||||
*
|
||||
* @ctx - allocation context
|
||||
* @num_inputs - number of inputs to allocate
|
||||
* @num_outputs - number of outputs to allocate
|
||||
* @locktime - locktime for the transaction
|
||||
*/
|
||||
struct wally_psbt *create_psbt(const tal_t *ctx, size_t num_inputs, size_t num_outputs, u32 locktime);
|
||||
|
||||
/*
|
||||
* new_psbt - Create a PSBT, using the passed in tx
|
||||
* as the locktime/inputs/output psbt fields
|
||||
*
|
||||
* @ctx - allocation context
|
||||
* @wtx - global_tx starter kit
|
||||
*/
|
||||
struct wally_psbt *new_psbt(const tal_t *ctx,
|
||||
const struct wally_tx *wtx);
|
||||
|
||||
/**
|
||||
* clone_psbt - Clone a PSBT onto passed in context
|
||||
*
|
||||
* @ctx - allocation context
|
||||
* @psbt - psbt to be cloned
|
||||
*/
|
||||
struct wally_psbt *clone_psbt(const tal_t *ctx, const struct wally_psbt *psbt);
|
||||
|
||||
/**
|
||||
* combine_psbt - Combine two PSBT into a cloned copy
|
||||
*
|
||||
* @ctx - allocation context
|
||||
* @psbt0 - one psbt
|
||||
* @psbt1 - other psbt
|
||||
*/
|
||||
struct wally_psbt *combine_psbt(const tal_t *ctx,
|
||||
const struct wally_psbt *psbt0,
|
||||
const struct wally_psbt *psbt1);
|
||||
|
||||
/**
|
||||
* audit_psbt - Audit the memory structure of the PSBT.
|
||||
*
|
||||
* This checks all known memory allocations in the PSBT and asserts that they
|
||||
* are all allocated with 'ctx' being it's parent.
|
||||
*
|
||||
* ctx - the ctx all memory *should* be attached to
|
||||
* psbt - the PSBT to audit.
|
||||
* */
|
||||
void audit_psbt(const tal_t *ctx, const struct wally_psbt *psbt);
|
||||
|
||||
/**
|
||||
* psbt_is_finalized - Check if tx is ready to be extracted
|
||||
*
|
||||
* The libwally library requires a transaction be *ready* for
|
||||
* extraction before it will add/append all of the sigs/witnesses
|
||||
* onto the global transaction. This check returns true if
|
||||
* a psbt has the finalized script sig and/or witness data populated
|
||||
* for such a call
|
||||
*/
|
||||
bool psbt_is_finalized(const struct wally_psbt *psbt);
|
||||
|
||||
/**
|
||||
* psbt_txid - get the txid of the psbt (what it would be after finalization)
|
||||
* @ctx: the context to allocate wtx off, if *@wtx isn't NULL.
|
||||
* @psbt: the psbt.
|
||||
* @txid: the transaction id (output)
|
||||
* @wtx: if non-NULL, returns a copy of the transaction (caller must wally_tx_free).
|
||||
*/
|
||||
void psbt_txid(const tal_t *ctx,
|
||||
const struct wally_psbt *psbt, struct bitcoin_txid *txid,
|
||||
struct wally_tx **wtx);
|
||||
|
||||
/* psbt_elements_normalize_fees - Figure out the fee output for a PSET
|
||||
*
|
||||
* Adds a fee output if not present, or updates it to include the diff
|
||||
* between inputs - outputs. Unlike bitcoin, elements requires every
|
||||
* satoshi to be accounted for in an output.
|
||||
*/
|
||||
void psbt_elements_normalize_fees(struct wally_psbt *psbt);
|
||||
|
||||
/**
|
||||
* psbt_finalize - finalize this psbt.
|
||||
*
|
||||
* Returns false if we can't, otherwise returns true and psbt_is_finalized()
|
||||
* is true.
|
||||
*/
|
||||
bool psbt_finalize(struct wally_psbt *psbt);
|
||||
|
||||
/**
|
||||
* psbt_final_tx - extract transaction from finalized psbt.
|
||||
* @ctx: context to tallocate return
|
||||
* @psbt: psbt to extract.
|
||||
*
|
||||
* If @psbt isn't final, or we can't extract tx, returns NULL.
|
||||
*/
|
||||
struct wally_tx *psbt_final_tx(const tal_t *ctx, const struct wally_psbt *psbt);
|
||||
|
||||
/* psbt_make_key - Create a new, proprietary Core Lightning key
|
||||
*
|
||||
* @ctx - allocation context
|
||||
* @key_subtype - type for this key
|
||||
* @key_data - any extra data to append to the key
|
||||
*
|
||||
* Returns a proprietary-prefixed key.
|
||||
*/
|
||||
u8 *psbt_make_key(const tal_t *ctx, u8 key_subtype, const u8 *key_data);
|
||||
|
||||
struct wally_psbt_input *psbt_add_input(struct wally_psbt *psbt,
|
||||
const struct wally_tx_input *input,
|
||||
size_t insert_at);
|
||||
|
||||
/* One stop shop for adding an input + metadata to a PSBT */
|
||||
struct wally_psbt_input *psbt_append_input(struct wally_psbt *psbt,
|
||||
const struct bitcoin_outpoint *outpoint,
|
||||
u32 sequence,
|
||||
const u8 *scriptSig,
|
||||
const u8 *input_wscript,
|
||||
const u8 *redeemscript);
|
||||
|
||||
/* psbt_input_set_wit_utxo - Set the witness_utxo field for this PSBT */
|
||||
void psbt_input_set_wit_utxo(struct wally_psbt *psbt, size_t in,
|
||||
const u8 *scriptPubkey, struct amount_sat amt);
|
||||
|
||||
/* psbt_input_set_utxo - Set the non-witness utxo field for this PSBT input */
|
||||
void psbt_input_set_utxo(struct wally_psbt *psbt, size_t in,
|
||||
const struct wally_tx *prev_tx);
|
||||
|
||||
void psbt_input_set_outpoint(struct wally_psbt *psbt, size_t in,
|
||||
struct bitcoin_outpoint outpoint);
|
||||
|
||||
/* psbt_elements_input_set_asset - Set the asset/value fields for an
|
||||
* Elements PSBT (PSET, technically */
|
||||
void psbt_elements_input_set_asset(struct wally_psbt *psbt, size_t in,
|
||||
struct amount_asset *asset);
|
||||
|
||||
void psbt_rm_input(struct wally_psbt *psbt,
|
||||
size_t remove_at);
|
||||
|
||||
struct wally_psbt_output *psbt_add_output(struct wally_psbt *psbt,
|
||||
struct wally_tx_output *output,
|
||||
size_t insert_at);
|
||||
|
||||
/**
|
||||
* wally_psbt_output - Append a new output to the PSBT
|
||||
*
|
||||
* @psbt - PSBT to append output to
|
||||
* @script - scriptPubKey of the output
|
||||
* @amount - value of the output
|
||||
*/
|
||||
struct wally_psbt_output *psbt_append_output(struct wally_psbt *psbt,
|
||||
const u8 *script,
|
||||
struct amount_sat amount);
|
||||
struct wally_psbt_output *psbt_insert_output(struct wally_psbt *psbt,
|
||||
const u8 *script,
|
||||
struct amount_sat amount,
|
||||
size_t insert_at);
|
||||
|
||||
void psbt_rm_output(struct wally_psbt *psbt,
|
||||
size_t remove_at);
|
||||
|
||||
void psbt_input_add_pubkey(struct wally_psbt *psbt, size_t in,
|
||||
const struct pubkey *pubkey, bool is_taproot);
|
||||
|
||||
WARN_UNUSED_RESULT bool psbt_input_set_signature(struct wally_psbt *psbt, size_t in,
|
||||
const struct pubkey *pubkey,
|
||||
const struct bitcoin_signature *sig);
|
||||
|
||||
/* Returns false on error. On success, *signature_found is set to true if the
|
||||
* input has a signature present for `pubkey` and false if if one was not found.
|
||||
* Only signature presence is checked, it is not validated. */
|
||||
WARN_UNUSED_RESULT bool psbt_input_have_signature(const struct wally_psbt *psbt,
|
||||
size_t in,
|
||||
const struct pubkey *pubkey,
|
||||
bool *signature_found);
|
||||
|
||||
/* Returns false on error. On success *sig is set to the signature otherwise
|
||||
* *sig is set to NULL. */
|
||||
WARN_UNUSED_RESULT bool psbt_input_get_ecdsa_sig(const tal_t *ctx,
|
||||
const struct wally_psbt *psbt,
|
||||
size_t in,
|
||||
const struct pubkey *pubkey,
|
||||
struct bitcoin_signature **sig);
|
||||
|
||||
void psbt_input_set_witscript(struct wally_psbt *psbt, size_t in, const u8 *wscript);
|
||||
|
||||
/* psbt_input_set_unknown - Set the given Key-Value in the psbt's input keymap
|
||||
* @ctx - tal context for allocations
|
||||
* @in - psbt input to set key-value on
|
||||
* @key - key for key-value pair
|
||||
* @value - value to set
|
||||
* @value_len - length of {@value}
|
||||
*/
|
||||
void psbt_input_set_unknown(const tal_t *ctx,
|
||||
struct wally_psbt_input *in,
|
||||
const u8 *key,
|
||||
const void *value,
|
||||
size_t value_len);
|
||||
|
||||
/* psbt_get_lightning - Fetch a proprietary lightning value from the given map
|
||||
*
|
||||
* @map - map of unknowns to search for key
|
||||
* @proprietary_type - type no. to look for
|
||||
* @val_len - (out) length of value (if found)
|
||||
*
|
||||
* Returns: value of type {proprietary_type}, or NULL if not found */
|
||||
void *psbt_get_lightning(const struct wally_map *map,
|
||||
const u8 proprietary_type,
|
||||
size_t *val_len);
|
||||
|
||||
/* psbt_set_lightning - Set a propreitary lightning value on the given map
|
||||
*
|
||||
* @map - map of unknowns to set the value
|
||||
* @proprietary_type - type no. to set
|
||||
* @value - the value to be set
|
||||
* @val_len - length of value
|
||||
*/
|
||||
void psbt_set_lightning(const tal_t *ctx,
|
||||
struct wally_map *map,
|
||||
const u8 proprietary_type,
|
||||
const void *value,
|
||||
size_t val_len);
|
||||
|
||||
/* psbt_output_set_unknown - Set the given Key-Value in the psbt's output keymap
|
||||
*
|
||||
* @ctx - tal context for allocations
|
||||
* @out - psbt output to set key-value on
|
||||
* @key - key for key-value pair
|
||||
* @value - value to set
|
||||
* @value_len - length of {@value}
|
||||
*/
|
||||
void psbt_output_set_unknown(const tal_t *ctx,
|
||||
struct wally_psbt_output *out,
|
||||
const u8 *key, const void *value,
|
||||
size_t value_len);
|
||||
|
||||
/* psbt_input_get_amount - Returns the value of this input
|
||||
*
|
||||
* @psbt - psbt
|
||||
* @in - index of input whose value you're returning
|
||||
* */
|
||||
struct amount_sat psbt_input_get_amount(const struct wally_psbt *psbt,
|
||||
size_t in);
|
||||
|
||||
/* psbt_input_get_weight - Calculate the tx weight for input index `in` */
|
||||
size_t psbt_input_get_weight(const struct wally_psbt *psbt,
|
||||
size_t in);
|
||||
|
||||
/* psbt_output_get_amount - Returns the value of this output
|
||||
*
|
||||
* @psbt - psbt
|
||||
* @out -index of output whose value you're returning
|
||||
*/
|
||||
struct amount_sat psbt_output_get_amount(const struct wally_psbt *psbt,
|
||||
size_t out);
|
||||
|
||||
/* psbt_output_get_weight - Calculate the tx weight for output index `outnum` */
|
||||
size_t psbt_output_get_weight(const struct wally_psbt *psbt,
|
||||
size_t outnum);
|
||||
|
||||
/* psbt_compute_fee - Returns value of fee for PSBT
|
||||
*
|
||||
* @psbt -psbt
|
||||
*/
|
||||
struct amount_sat psbt_compute_fee(const struct wally_psbt *psbt);
|
||||
|
||||
/* psbt_has_input - Is this input present on this psbt
|
||||
*
|
||||
* @psbt - psbt
|
||||
* @outpoint - txid/index spent by input
|
||||
*/
|
||||
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);
|
||||
char *fmt_wally_psbt(const tal_t *ctx, const struct wally_psbt *psbt);
|
||||
const u8 *psbt_get_bytes(const tal_t *ctx, const struct wally_psbt *psbt,
|
||||
size_t *bytes_written);
|
||||
bool validate_psbt(const struct wally_psbt *psbt);
|
||||
struct wally_psbt *psbt_from_bytes(const tal_t *ctx, const u8 *bytes,
|
||||
size_t byte_len);
|
||||
void towire_wally_psbt(u8 **pptr, const struct wally_psbt *psbt);
|
||||
struct wally_psbt *fromwire_wally_psbt(const tal_t *ctx,
|
||||
const u8 **cursor, size_t *max);
|
||||
#endif /* LIGHTNING_BITCOIN_PSBT_H */
|
||||
@ -1,19 +1,14 @@
|
||||
#include "config.h"
|
||||
#include "privkey.h"
|
||||
#include "pubkey.h"
|
||||
#include <assert.h>
|
||||
#include <bitcoin/privkey.h>
|
||||
#include <bitcoin/pubkey.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <common/type_to_string.h>
|
||||
#include <common/utils.h>
|
||||
#include <wire/wire.h>
|
||||
|
||||
#ifndef SUPERVERBOSE
|
||||
#define SUPERVERBOSE(...)
|
||||
#endif
|
||||
|
||||
bool pubkey_from_der(const u8 *der, size_t len, struct pubkey *key)
|
||||
{
|
||||
if (len != PUBKEY_CMPR_LEN)
|
||||
if (len != PUBKEY_DER_LEN)
|
||||
return false;
|
||||
|
||||
if (!secp256k1_ec_pubkey_parse(secp256k1_ctx, &key->pubkey,
|
||||
@ -23,14 +18,14 @@ bool pubkey_from_der(const u8 *der, size_t len, struct pubkey *key)
|
||||
return true;
|
||||
}
|
||||
|
||||
void pubkey_to_der(u8 der[PUBKEY_CMPR_LEN], const struct pubkey *key)
|
||||
void pubkey_to_der(u8 der[PUBKEY_DER_LEN], const struct pubkey *key)
|
||||
{
|
||||
size_t outlen = PUBKEY_CMPR_LEN;
|
||||
size_t outlen = PUBKEY_DER_LEN;
|
||||
if (!secp256k1_ec_pubkey_serialize(secp256k1_ctx, der, &outlen,
|
||||
&key->pubkey,
|
||||
SECP256K1_EC_COMPRESSED))
|
||||
abort();
|
||||
assert(outlen == PUBKEY_CMPR_LEN);
|
||||
assert(outlen == PUBKEY_DER_LEN);
|
||||
}
|
||||
|
||||
bool pubkey_from_secret(const struct secret *secret, struct pubkey *key)
|
||||
@ -50,7 +45,7 @@ bool pubkey_from_privkey(const struct privkey *privkey,
|
||||
bool pubkey_from_hexstr(const char *derstr, size_t slen, struct pubkey *key)
|
||||
{
|
||||
size_t dlen;
|
||||
unsigned char der[PUBKEY_CMPR_LEN];
|
||||
unsigned char der[PUBKEY_DER_LEN];
|
||||
|
||||
dlen = hex_data_size(slen);
|
||||
if (dlen != sizeof(der))
|
||||
@ -62,17 +57,18 @@ bool pubkey_from_hexstr(const char *derstr, size_t slen, struct pubkey *key)
|
||||
return pubkey_from_der(der, dlen, key);
|
||||
}
|
||||
|
||||
char *fmt_pubkey(const tal_t *ctx, const struct pubkey *key)
|
||||
char *pubkey_to_hexstr(const tal_t *ctx, const struct pubkey *key)
|
||||
{
|
||||
unsigned char der[PUBKEY_CMPR_LEN];
|
||||
unsigned char der[PUBKEY_DER_LEN];
|
||||
|
||||
pubkey_to_der(der, key);
|
||||
return tal_hexstr(ctx, der, sizeof(der));
|
||||
}
|
||||
REGISTER_TYPE_TO_STRING(pubkey, pubkey_to_hexstr);
|
||||
|
||||
char *fmt_secp256k1_pubkey(const tal_t *ctx, const secp256k1_pubkey *key)
|
||||
char *secp256k1_pubkey_to_hexstr(const tal_t *ctx, const secp256k1_pubkey *key)
|
||||
{
|
||||
unsigned char der[PUBKEY_CMPR_LEN];
|
||||
unsigned char der[PUBKEY_DER_LEN];
|
||||
size_t outlen = sizeof(der);
|
||||
if (!secp256k1_ec_pubkey_serialize(secp256k1_ctx, der, &outlen, key,
|
||||
SECP256K1_EC_COMPRESSED))
|
||||
@ -80,10 +76,11 @@ char *fmt_secp256k1_pubkey(const tal_t *ctx, const secp256k1_pubkey *key)
|
||||
assert(outlen == sizeof(der));
|
||||
return tal_hexstr(ctx, der, sizeof(der));
|
||||
}
|
||||
REGISTER_TYPE_TO_STRING(secp256k1_pubkey, secp256k1_pubkey_to_hexstr);
|
||||
|
||||
int pubkey_cmp(const struct pubkey *a, const struct pubkey *b)
|
||||
{
|
||||
u8 keya[PUBKEY_CMPR_LEN], keyb[PUBKEY_CMPR_LEN];
|
||||
u8 keya[33], keyb[33];
|
||||
pubkey_to_der(keya, a);
|
||||
pubkey_to_der(keyb, b);
|
||||
return memcmp(keya, keyb, sizeof(keya));
|
||||
@ -91,35 +88,10 @@ int pubkey_cmp(const struct pubkey *a, const struct pubkey *b)
|
||||
|
||||
void pubkey_to_hash160(const struct pubkey *pk, struct ripemd160 *hash)
|
||||
{
|
||||
u8 der[PUBKEY_CMPR_LEN];
|
||||
u8 der[PUBKEY_DER_LEN];
|
||||
struct sha256 h;
|
||||
|
||||
pubkey_to_der(der, pk);
|
||||
sha256(&h, der, sizeof(der));
|
||||
ripemd160(hash, h.u.u8, sizeof(h));
|
||||
}
|
||||
|
||||
void fromwire_pubkey(const u8 **cursor, size_t *max, struct pubkey *pubkey)
|
||||
{
|
||||
u8 der[PUBKEY_CMPR_LEN];
|
||||
|
||||
if (!fromwire(cursor, max, der, sizeof(der)))
|
||||
return;
|
||||
|
||||
if (!pubkey_from_der(der, sizeof(der), pubkey)) {
|
||||
SUPERVERBOSE("not a valid point");
|
||||
fromwire_fail(cursor, max);
|
||||
}
|
||||
}
|
||||
|
||||
void towire_pubkey(u8 **pptr, const struct pubkey *pubkey)
|
||||
{
|
||||
u8 output[PUBKEY_CMPR_LEN];
|
||||
size_t outputlen = sizeof(output);
|
||||
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_ctx, output, &outputlen,
|
||||
&pubkey->pubkey,
|
||||
SECP256K1_EC_COMPRESSED);
|
||||
|
||||
towire(pptr, output, outputlen);
|
||||
}
|
||||
|
||||
@ -2,15 +2,16 @@
|
||||
#define LIGHTNING_BITCOIN_PUBKEY_H
|
||||
#include "config.h"
|
||||
#include <ccan/crypto/ripemd160/ripemd160.h>
|
||||
#include <ccan/crypto/sha256/sha256.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <secp256k1_extrakeys.h>
|
||||
#include <secp256k1.h>
|
||||
|
||||
struct privkey;
|
||||
struct secret;
|
||||
|
||||
#define PUBKEY_CMPR_LEN 33
|
||||
#define PUBKEY_DER_LEN 33
|
||||
|
||||
struct pubkey {
|
||||
/* Unpacked pubkey (as used by libsecp256k1 internally) */
|
||||
@ -23,8 +24,10 @@ STRUCTEQ_DEF(pubkey, 0, pubkey.data);
|
||||
bool pubkey_from_hexstr(const char *derstr, size_t derlen, struct pubkey *key);
|
||||
|
||||
/* Convert from hex string of DER (scriptPubKey from validateaddress) */
|
||||
char *fmt_pubkey(const tal_t *ctx, const struct pubkey *key);
|
||||
char *fmt_secp256k1_pubkey(const tal_t *ctx, const secp256k1_pubkey *key);
|
||||
char *pubkey_to_hexstr(const tal_t *ctx, const struct pubkey *key);
|
||||
|
||||
/* Convenience wrapper for a raw secp256k1_pubkey */
|
||||
char *secp256k1_pubkey_to_hexstr(const tal_t *ctx, const secp256k1_pubkey *key);
|
||||
|
||||
/* Point from secret */
|
||||
bool pubkey_from_secret(const struct secret *secret, struct pubkey *key);
|
||||
@ -37,12 +40,12 @@ bool pubkey_from_privkey(const struct privkey *privkey,
|
||||
bool pubkey_from_der(const u8 *der, size_t len, struct pubkey *key);
|
||||
|
||||
/* Pubkey to DER encoding: must be valid pubkey. */
|
||||
void pubkey_to_der(u8 der[PUBKEY_CMPR_LEN], const struct pubkey *key);
|
||||
void pubkey_to_der(u8 der[PUBKEY_DER_LEN], const struct pubkey *key);
|
||||
|
||||
/* Compare the keys `a` and `b`. Return <0 if `a`<`b`, 0 if equal and >0 otherwise */
|
||||
int pubkey_cmp(const struct pubkey *a, const struct pubkey *b);
|
||||
|
||||
/* If the two pubkeys[] are id1 and id2, which index would id1 be? */
|
||||
/* If the two nodes[] are id1 and id2, which index would id1 be? */
|
||||
static inline int pubkey_idx(const struct pubkey *id1, const struct pubkey *id2)
|
||||
{
|
||||
return pubkey_cmp(id1, id2) > 0;
|
||||
@ -52,9 +55,4 @@ static inline int pubkey_idx(const struct pubkey *id1, const struct pubkey *id2)
|
||||
* pubkey_to_hash160 - Get the hash for p2pkh payments for a given pubkey
|
||||
*/
|
||||
void pubkey_to_hash160(const struct pubkey *pk, struct ripemd160 *hash);
|
||||
|
||||
/* marshal/unmarshal functions */
|
||||
void towire_pubkey(u8 **pptr, const struct pubkey *pubkey);
|
||||
void fromwire_pubkey(const u8 **cursor, size_t *max, struct pubkey *pubkey);
|
||||
|
||||
#endif /* LIGHTNING_BITCOIN_PUBKEY_H */
|
||||
|
||||
104
bitcoin/pullpush.c
Normal file
104
bitcoin/pullpush.c
Normal file
@ -0,0 +1,104 @@
|
||||
#include "pullpush.h"
|
||||
#include "varint.h"
|
||||
#include <assert.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
|
||||
void push_varint(varint_t v,
|
||||
void (*push)(const void *, size_t, void *), void *pushp)
|
||||
{
|
||||
u8 buf[VARINT_MAX_LEN];
|
||||
|
||||
push(buf, varint_put(buf, v), pushp);
|
||||
}
|
||||
|
||||
void push_le32(u32 v,
|
||||
void (*push)(const void *, size_t, void *), void *pushp)
|
||||
{
|
||||
le32 l = cpu_to_le32(v);
|
||||
push(&l, sizeof(l), pushp);
|
||||
}
|
||||
|
||||
void push_le64(u64 v,
|
||||
void (*push)(const void *, size_t, void *), void *pushp)
|
||||
{
|
||||
le64 l = cpu_to_le64(v);
|
||||
push(&l, sizeof(l), pushp);
|
||||
}
|
||||
|
||||
void push_amount_sat(struct amount_sat v,
|
||||
void (*push)(const void *, size_t, void *), void *pushp)
|
||||
{
|
||||
push_le64(v.satoshis, push, pushp); /* Raw: low-level helper */
|
||||
}
|
||||
|
||||
void push_varint_blob(const tal_t *blob,
|
||||
void (*push)(const void *, size_t, void *),
|
||||
void *pushp)
|
||||
{
|
||||
push_varint(tal_bytelen(blob), push, pushp);
|
||||
push(blob, tal_bytelen(blob), pushp);
|
||||
}
|
||||
|
||||
void push(const void *data, size_t len, void *pptr_)
|
||||
{
|
||||
u8 **pptr = pptr_;
|
||||
size_t oldsize = tal_count(*pptr);
|
||||
|
||||
tal_resize(pptr, oldsize + len);
|
||||
memcpy(*pptr + oldsize, memcheck(data, len), len);
|
||||
}
|
||||
|
||||
/* Sets *cursor to NULL and returns NULL when a pull fails. */
|
||||
const u8 *pull(const u8 **cursor, size_t *max, void *copy, size_t n)
|
||||
{
|
||||
const u8 *p = *cursor;
|
||||
|
||||
if (*max < n) {
|
||||
*cursor = NULL;
|
||||
*max = 0;
|
||||
/* Just make sure we don't leak uninitialized mem! */
|
||||
if (copy)
|
||||
memset(copy, 0, n);
|
||||
return NULL;
|
||||
}
|
||||
*cursor += n;
|
||||
*max -= n;
|
||||
assert(p);
|
||||
if (copy)
|
||||
memcpy(copy, p, n);
|
||||
return memcheck(p, n);
|
||||
}
|
||||
|
||||
u64 pull_varint(const u8 **cursor, size_t *max)
|
||||
{
|
||||
u64 ret;
|
||||
size_t len;
|
||||
|
||||
len = varint_get(*cursor, *max, &ret);
|
||||
if (len == 0) {
|
||||
*cursor = NULL;
|
||||
*max = 0;
|
||||
return 0;
|
||||
}
|
||||
pull(cursor, max, NULL, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 pull_le32(const u8 **cursor, size_t *max)
|
||||
{
|
||||
le32 ret;
|
||||
|
||||
if (!pull(cursor, max, &ret, sizeof(ret)))
|
||||
return 0;
|
||||
return le32_to_cpu(ret);
|
||||
}
|
||||
|
||||
u64 pull_le64(const u8 **cursor, size_t *max)
|
||||
{
|
||||
le64 ret;
|
||||
|
||||
if (!pull(cursor, max, &ret, sizeof(ret)))
|
||||
return 0;
|
||||
return le64_to_cpu(ret);
|
||||
}
|
||||
26
bitcoin/pullpush.h
Normal file
26
bitcoin/pullpush.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef LIGHTNING_BITCOIN_PULLPUSH_H
|
||||
#define LIGHTNING_BITCOIN_PULLPUSH_H
|
||||
#include "config.h"
|
||||
#include "bitcoin/varint.h"
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <common/amount.h>
|
||||
|
||||
void push_varint(varint_t v,
|
||||
void (*push)(const void *, size_t, void *), void *pushp);
|
||||
void push_le32(u32 v, void (*push)(const void *, size_t, void *), void *pushp);
|
||||
void push_le64(u64 v, void (*push)(const void *, size_t, void *), void *pushp);
|
||||
void push_amount_sat(struct amount_sat v,
|
||||
void (*push)(const void *, size_t, void *), void *pushp);
|
||||
void push_varint_blob(const tal_t *blob,
|
||||
void (*push)(const void *, size_t, void *),
|
||||
void *pushp);
|
||||
|
||||
u64 pull_varint(const u8 **cursor, size_t *max);
|
||||
u32 pull_le32(const u8 **cursor, size_t *max);
|
||||
u64 pull_le64(const u8 **cursor, size_t *max);
|
||||
|
||||
/* This extends **pptr by tal_resize */
|
||||
void push(const void *data, size_t len, void *pptr_);
|
||||
const u8 *pull(const u8 **cursor, size_t *max, void *copy, size_t n);
|
||||
|
||||
#endif /* LIGHTNING_BITCOIN_PULLPUSH_H */
|
||||
453
bitcoin/script.c
453
bitcoin/script.c
@ -1,17 +1,41 @@
|
||||
#include "config.h"
|
||||
#include "address.h"
|
||||
#include "locktime.h"
|
||||
#include "preimage.h"
|
||||
#include "pubkey.h"
|
||||
#include "script.h"
|
||||
#include <assert.h>
|
||||
#include <bitcoin/address.h>
|
||||
#include <bitcoin/locktime.h>
|
||||
#include <bitcoin/preimage.h>
|
||||
#include <bitcoin/pubkey.h>
|
||||
#include <bitcoin/script.h>
|
||||
#include <ccan/crypto/ripemd160/ripemd160.h>
|
||||
#include <ccan/crypto/sha256/sha256.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <common/utils.h>
|
||||
#include <sodium/randombytes.h>
|
||||
|
||||
/* To push 0-75 bytes onto stack. */
|
||||
/* Some standard ops */
|
||||
#define OP_0 0x00
|
||||
#define OP_PUSHBYTES(val) (val)
|
||||
#define OP_PUSHDATA1 0x4C
|
||||
#define OP_PUSHDATA2 0x4D
|
||||
#define OP_PUSHDATA4 0x4E
|
||||
#define OP_NOP 0x61
|
||||
#define OP_IF 0x63
|
||||
#define OP_NOTIF 0x64
|
||||
#define OP_ELSE 0x67
|
||||
#define OP_ENDIF 0x68
|
||||
#define OP_RETURN 0x6a
|
||||
#define OP_2DROP 0x6d
|
||||
#define OP_DEPTH 0x74
|
||||
#define OP_DROP 0x75
|
||||
#define OP_DUP 0x76
|
||||
#define OP_SWAP 0x7c
|
||||
#define OP_EQUAL 0x87
|
||||
#define OP_EQUALVERIFY 0x88
|
||||
#define OP_SIZE 0x82
|
||||
#define OP_1SUB 0x8C
|
||||
#define OP_ADD 0x93
|
||||
#define OP_CHECKSIG 0xAC
|
||||
#define OP_CHECKMULTISIG 0xAE
|
||||
#define OP_HASH160 0xA9
|
||||
#define OP_CHECKSEQUENCEVERIFY 0xB2
|
||||
#define OP_CHECKLOCKTIMEVERIFY 0xB1
|
||||
|
||||
/* Bitcoin's OP_HASH160 is RIPEMD(SHA256()) */
|
||||
static void hash160(struct ripemd160 *redeemhash, const void *mem, size_t len)
|
||||
@ -34,7 +58,7 @@ static void add_op(u8 **scriptp, u8 op)
|
||||
add(scriptp, &op, 1);
|
||||
}
|
||||
|
||||
void script_push_bytes(u8 **scriptp, const void *mem, size_t len)
|
||||
static void add_push_bytes(u8 **scriptp, const void *mem, size_t len)
|
||||
{
|
||||
if (len < 76)
|
||||
add_op(scriptp, OP_PUSHBYTES(len));
|
||||
@ -66,24 +90,24 @@ static void add_number(u8 **script, u32 num)
|
||||
|
||||
/* Beware: encoding is signed! */
|
||||
if (num <= 0x0000007F)
|
||||
script_push_bytes(script, &n, 1);
|
||||
add_push_bytes(script, &n, 1);
|
||||
else if (num <= 0x00007FFF)
|
||||
script_push_bytes(script, &n, 2);
|
||||
add_push_bytes(script, &n, 2);
|
||||
else if (num <= 0x007FFFFF)
|
||||
script_push_bytes(script, &n, 3);
|
||||
add_push_bytes(script, &n, 3);
|
||||
else if (num <= 0x7FFFFFFF)
|
||||
script_push_bytes(script, &n, 4);
|
||||
add_push_bytes(script, &n, 4);
|
||||
else
|
||||
script_push_bytes(script, &n, 5);
|
||||
add_push_bytes(script, &n, 5);
|
||||
}
|
||||
}
|
||||
|
||||
static void add_push_key(u8 **scriptp, const struct pubkey *key)
|
||||
{
|
||||
u8 der[PUBKEY_CMPR_LEN];
|
||||
u8 der[PUBKEY_DER_LEN];
|
||||
pubkey_to_der(der, key);
|
||||
|
||||
script_push_bytes(scriptp, der, sizeof(der));
|
||||
add_push_bytes(scriptp, der, sizeof(der));
|
||||
}
|
||||
|
||||
static void add_push_sig(u8 **scriptp, const struct bitcoin_signature *sig)
|
||||
@ -91,12 +115,12 @@ static void add_push_sig(u8 **scriptp, const struct bitcoin_signature *sig)
|
||||
u8 der[73];
|
||||
size_t len = signature_to_der(der, sig);
|
||||
|
||||
script_push_bytes(scriptp, der, len);
|
||||
add_push_bytes(scriptp, der, len);
|
||||
}
|
||||
|
||||
static u8 *stack_key(const tal_t *ctx, const struct pubkey *key)
|
||||
{
|
||||
u8 der[PUBKEY_CMPR_LEN];
|
||||
u8 der[PUBKEY_DER_LEN];
|
||||
pubkey_to_der(der, key);
|
||||
|
||||
return tal_dup_arr(ctx, u8, der, sizeof(der), 0);
|
||||
@ -158,7 +182,7 @@ u8 *scriptpubkey_p2sh_hash(const tal_t *ctx, const struct ripemd160 *redeemhash)
|
||||
u8 *script = tal_arr(ctx, u8, 0);
|
||||
|
||||
add_op(&script, OP_HASH160);
|
||||
script_push_bytes(&script, redeemhash->u.u8, sizeof(redeemhash->u.u8));
|
||||
add_push_bytes(&script, redeemhash->u.u8, sizeof(redeemhash->u.u8));
|
||||
add_op(&script, OP_EQUAL);
|
||||
assert(tal_count(script) == BITCOIN_SCRIPTPUBKEY_P2SH_LEN);
|
||||
return script;
|
||||
@ -180,21 +204,18 @@ u8 *scriptpubkey_p2pkh(const tal_t *ctx, const struct bitcoin_address *addr)
|
||||
|
||||
add_op(&script, OP_DUP);
|
||||
add_op(&script, OP_HASH160);
|
||||
script_push_bytes(&script, &addr->addr, sizeof(addr->addr));
|
||||
add_push_bytes(&script, &addr->addr, sizeof(addr->addr));
|
||||
add_op(&script, OP_EQUALVERIFY);
|
||||
add_op(&script, OP_CHECKSIG);
|
||||
assert(tal_count(script) == BITCOIN_SCRIPTPUBKEY_P2PKH_LEN);
|
||||
return script;
|
||||
}
|
||||
|
||||
u8 *scriptpubkey_opreturn_padded(const tal_t *ctx)
|
||||
u8 *scriptpubkey_opreturn(const tal_t *ctx)
|
||||
{
|
||||
u8 *script = tal_arr(ctx, u8, 0);
|
||||
u8 random[20];
|
||||
randombytes_buf(random, sizeof(random));
|
||||
|
||||
add_op(&script, OP_RETURN);
|
||||
script_push_bytes(&script, random, sizeof(random));
|
||||
return script;
|
||||
}
|
||||
|
||||
@ -220,36 +241,24 @@ u8 *bitcoin_redeem_p2sh_p2wpkh(const tal_t *ctx, const struct pubkey *key)
|
||||
* push of a version byte plus a push of a witness program. */
|
||||
add_number(&script, 0);
|
||||
pubkey_to_hash160(key, &keyhash);
|
||||
script_push_bytes(&script, &keyhash, sizeof(keyhash));
|
||||
add_push_bytes(&script, &keyhash, sizeof(keyhash));
|
||||
|
||||
assert(tal_count(script) == BITCOIN_SCRIPTPUBKEY_P2WPKH_LEN);
|
||||
return script;
|
||||
}
|
||||
|
||||
u8 *bitcoin_scriptsig_redeem(const tal_t *ctx,
|
||||
const u8 *redeemscript TAKES)
|
||||
u8 *bitcoin_scriptsig_p2sh_p2wpkh(const tal_t *ctx, const struct pubkey *key)
|
||||
{
|
||||
u8 *script;
|
||||
u8 *redeemscript = bitcoin_redeem_p2sh_p2wpkh(ctx, key), *script;
|
||||
|
||||
/* BIP141: The scriptSig must be exactly a push of the BIP16
|
||||
* redeemScript or validation fails. */
|
||||
script = tal_arr(ctx, u8, 0);
|
||||
script_push_bytes(&script, redeemscript,
|
||||
tal_count(redeemscript));
|
||||
|
||||
if (taken(redeemscript))
|
||||
tal_free(redeemscript);
|
||||
|
||||
add_push_bytes(&script, redeemscript, tal_count(redeemscript));
|
||||
tal_free(redeemscript);
|
||||
return script;
|
||||
}
|
||||
|
||||
u8 *bitcoin_scriptsig_p2sh_p2wpkh(const tal_t *ctx, const struct pubkey *key)
|
||||
{
|
||||
u8 *redeemscript =
|
||||
bitcoin_redeem_p2sh_p2wpkh(NULL, key);
|
||||
return bitcoin_scriptsig_redeem(ctx, take(redeemscript));
|
||||
}
|
||||
|
||||
u8 **bitcoin_witness_p2wpkh(const tal_t *ctx,
|
||||
const struct bitcoin_signature *sig,
|
||||
const struct pubkey *key)
|
||||
@ -273,7 +282,7 @@ u8 *scriptpubkey_p2wsh(const tal_t *ctx, const u8 *witnessscript)
|
||||
|
||||
add_op(&script, OP_0);
|
||||
sha256(&h, witnessscript, tal_count(witnessscript));
|
||||
script_push_bytes(&script, h.u.u8, sizeof(h.u.u8));
|
||||
add_push_bytes(&script, h.u.u8, sizeof(h.u.u8));
|
||||
assert(tal_count(script) == BITCOIN_SCRIPTPUBKEY_P2WSH_LEN);
|
||||
return script;
|
||||
}
|
||||
@ -286,7 +295,7 @@ u8 *scriptpubkey_p2wpkh(const tal_t *ctx, const struct pubkey *key)
|
||||
|
||||
add_op(&script, OP_0);
|
||||
pubkey_to_hash160(key, &h);
|
||||
script_push_bytes(&script, &h, sizeof(h));
|
||||
add_push_bytes(&script, &h, sizeof(h));
|
||||
return script;
|
||||
}
|
||||
|
||||
@ -296,8 +305,8 @@ u8 *scriptpubkey_p2wpkh_derkey(const tal_t *ctx, const u8 der[33])
|
||||
struct ripemd160 h;
|
||||
|
||||
add_op(&script, OP_0);
|
||||
hash160(&h, der, PUBKEY_CMPR_LEN);
|
||||
script_push_bytes(&script, &h, sizeof(h));
|
||||
hash160(&h, der, PUBKEY_DER_LEN);
|
||||
add_push_bytes(&script, &h, sizeof(h));
|
||||
return script;
|
||||
}
|
||||
|
||||
@ -306,127 +315,10 @@ u8 *scriptpubkey_witness_raw(const tal_t *ctx, u8 version,
|
||||
{
|
||||
u8 *script = tal_arr(ctx, u8, 0);
|
||||
add_number(&script, version);
|
||||
script_push_bytes(&script, wprog, wprog_size);
|
||||
add_push_bytes(&script, wprog, wprog_size);
|
||||
return script;
|
||||
}
|
||||
|
||||
u8 *scriptpubkey_raw_p2tr(const tal_t *ctx, const struct pubkey *output_pubkey)
|
||||
{
|
||||
int ok;
|
||||
secp256k1_xonly_pubkey x_key;
|
||||
unsigned char x_key_bytes[32];
|
||||
u8 *script = tal_arr(ctx, u8, 0);
|
||||
|
||||
add_op(&script, OP_1);
|
||||
|
||||
ok = secp256k1_xonly_pubkey_from_pubkey(secp256k1_ctx,
|
||||
&x_key,
|
||||
/* pk_parity */ NULL,
|
||||
&(output_pubkey->pubkey));
|
||||
assert(ok);
|
||||
|
||||
ok = secp256k1_xonly_pubkey_serialize(secp256k1_ctx,
|
||||
x_key_bytes,
|
||||
&x_key);
|
||||
assert(ok);
|
||||
|
||||
script_push_bytes(&script, x_key_bytes, sizeof(x_key_bytes));
|
||||
assert(tal_count(script) == BITCOIN_SCRIPTPUBKEY_P2TR_LEN);
|
||||
return script;
|
||||
}
|
||||
|
||||
u8 *scriptpubkey_raw_p2tr_derkey(const tal_t *ctx, const u8 output_der[33])
|
||||
{
|
||||
struct pubkey tr_key;
|
||||
if (!pubkey_from_der(output_der, 33, &tr_key)) {
|
||||
abort();
|
||||
}
|
||||
return scriptpubkey_raw_p2tr(ctx, &tr_key);
|
||||
}
|
||||
|
||||
u8 *scriptpubkey_p2tr(const tal_t *ctx, const struct pubkey *inner_pubkey)
|
||||
{
|
||||
unsigned char key_bytes[33];
|
||||
unsigned char tweaked_key_bytes[33];
|
||||
size_t out_len = sizeof(key_bytes);
|
||||
u8 *script = tal_arr(ctx, u8, 0);
|
||||
|
||||
add_op(&script, OP_1);
|
||||
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_ctx, key_bytes, &out_len, &inner_pubkey->pubkey, SECP256K1_EC_COMPRESSED);
|
||||
/* Only commit to inner pubkey in tweak */
|
||||
if (wally_ec_public_key_bip341_tweak(key_bytes, 33, /* merkle_root*/ NULL, 0, 0 /* flags */, tweaked_key_bytes, sizeof(tweaked_key_bytes)) != WALLY_OK)
|
||||
abort();
|
||||
|
||||
/* Cut off the first byte from the serialized compressed key */
|
||||
script_push_bytes(&script, tweaked_key_bytes + 1, sizeof(tweaked_key_bytes) - 1);
|
||||
assert(tal_count(script) == BITCOIN_SCRIPTPUBKEY_P2TR_LEN);
|
||||
return script;
|
||||
}
|
||||
|
||||
u8 *scriptpubkey_p2tr_derkey(const tal_t *ctx, const u8 inner_der[33])
|
||||
{
|
||||
struct pubkey tr_key;
|
||||
if (!pubkey_from_der(inner_der, 33, &tr_key)) {
|
||||
abort();
|
||||
}
|
||||
return scriptpubkey_p2tr(ctx, &tr_key);
|
||||
}
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* #### `to_remote` Output
|
||||
*
|
||||
* If `option_anchors` applies to the commitment
|
||||
* transaction, the `to_remote` output is encumbered by a one
|
||||
* block csv lock.
|
||||
* <remotepubkey> OP_CHECKSIGVERIFY 1 OP_CHECKSEQUENCEVERIFY
|
||||
*/
|
||||
/* BOLT- #3
|
||||
* ##### Leased channel (`option_will_fund`)
|
||||
*
|
||||
* If a `lease` applies to the channel, the `to_remote` output
|
||||
* of the `initiator` ensures the `leasor` funds are not
|
||||
* spendable until the lease expires.
|
||||
*
|
||||
* <remote_pubkey> OP_CHECKSIGVERIFY MAX(1, lease_end - blockheight) OP_CHECKSEQUENCEVERIFY
|
||||
*/
|
||||
|
||||
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);
|
||||
add_op(&script, OP_CHECKSIGVERIFY);
|
||||
add_number(&script, csv_lock);
|
||||
add_op(&script, OP_CHECKSEQUENCEVERIFY);
|
||||
|
||||
assert(is_to_remote_anchored_witness_script(script, tal_bytelen(script)));
|
||||
return script;
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
* <remote_pubkey> OP_CHECKSIGVERIFY
|
||||
* MAX(1, lease_end - blockheight)
|
||||
* OP_CHECKSEQUENCEVERIFY
|
||||
*/
|
||||
if (script_len < len || script_len > len + 2)
|
||||
return false;
|
||||
if (script[0] != OP_PUSHBYTES(33))
|
||||
return false;
|
||||
if (script[34] != OP_CHECKSIGVERIFY)
|
||||
return false;
|
||||
/* FIXME: check for push value */
|
||||
if (script[script_len - 1] != OP_CHECKSEQUENCEVERIFY)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Create a witness which spends the 2of2. */
|
||||
u8 **bitcoin_witness_2of2(const tal_t *ctx,
|
||||
const struct bitcoin_signature *sig1,
|
||||
@ -469,15 +361,17 @@ u8 *p2wpkh_scriptcode(const tal_t *ctx, const struct pubkey *key)
|
||||
* OP_EQUALVERIFY OP_CHECKSIG */
|
||||
add_op(&script, OP_DUP);
|
||||
add_op(&script, OP_HASH160);
|
||||
script_push_bytes(&script, &pkhash, sizeof(pkhash));
|
||||
add_push_bytes(&script, &pkhash, sizeof(pkhash));
|
||||
add_op(&script, OP_EQUALVERIFY);
|
||||
add_op(&script, OP_CHECKSIG);
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
bool is_p2pkh(const u8 *script, size_t script_len, struct bitcoin_address *addr)
|
||||
bool is_p2pkh(const u8 *script, struct bitcoin_address *addr)
|
||||
{
|
||||
size_t script_len = tal_count(script);
|
||||
|
||||
if (script_len != BITCOIN_SCRIPTPUBKEY_P2PKH_LEN)
|
||||
return false;
|
||||
if (script[0] != OP_DUP)
|
||||
@ -495,8 +389,10 @@ bool is_p2pkh(const u8 *script, size_t script_len, struct bitcoin_address *addr)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_p2sh(const u8 *script, size_t script_len, struct ripemd160 *addr)
|
||||
bool is_p2sh(const u8 *script, struct ripemd160 *addr)
|
||||
{
|
||||
size_t script_len = tal_count(script);
|
||||
|
||||
if (script_len != BITCOIN_SCRIPTPUBKEY_P2SH_LEN)
|
||||
return false;
|
||||
if (script[0] != OP_HASH160)
|
||||
@ -510,8 +406,10 @@ bool is_p2sh(const u8 *script, size_t script_len, struct ripemd160 *addr)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_p2wsh(const u8 *script, size_t script_len, struct sha256 *addr)
|
||||
bool is_p2wsh(const u8 *script, struct sha256 *addr)
|
||||
{
|
||||
size_t script_len = tal_count(script);
|
||||
|
||||
if (script_len != BITCOIN_SCRIPTPUBKEY_P2WSH_LEN)
|
||||
return false;
|
||||
if (script[0] != OP_0)
|
||||
@ -523,8 +421,10 @@ bool is_p2wsh(const u8 *script, size_t script_len, struct sha256 *addr)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_p2wpkh(const u8 *script, size_t script_len, struct bitcoin_address *addr)
|
||||
bool is_p2wpkh(const u8 *script, struct bitcoin_address *addr)
|
||||
{
|
||||
size_t script_len = tal_count(script);
|
||||
|
||||
if (script_len != BITCOIN_SCRIPTPUBKEY_P2WPKH_LEN)
|
||||
return false;
|
||||
if (script[0] != OP_0)
|
||||
@ -536,36 +436,6 @@ bool is_p2wpkh(const u8 *script, size_t script_len, struct bitcoin_address *addr
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_p2tr(const u8 *script, size_t script_len, u8 xonly_pubkey[32])
|
||||
{
|
||||
if (script_len != BITCOIN_SCRIPTPUBKEY_P2TR_LEN)
|
||||
return false;
|
||||
if (script[0] != OP_1)
|
||||
return false;
|
||||
/* x-only pubkey */
|
||||
if (script[1] != OP_PUSHBYTES(32))
|
||||
return false;
|
||||
if (xonly_pubkey)
|
||||
memcpy(xonly_pubkey, script+2, 32);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_known_scripttype(const u8 *script, size_t script_len)
|
||||
{
|
||||
return is_p2wpkh(script, script_len, NULL)
|
||||
|| is_p2wsh(script, script_len, NULL)
|
||||
|| is_p2sh(script, script_len, NULL)
|
||||
|| is_p2pkh(script, script_len, NULL)
|
||||
|| is_p2tr(script, script_len, NULL);
|
||||
}
|
||||
|
||||
bool is_known_segwit_scripttype(const u8 *script, size_t script_len)
|
||||
{
|
||||
return is_p2wpkh(script, script_len, NULL)
|
||||
|| is_p2wsh(script, script_len, NULL)
|
||||
|| is_p2tr(script, script_len, NULL);
|
||||
}
|
||||
|
||||
u8 **bitcoin_witness_sig_and_element(const tal_t *ctx,
|
||||
const struct bitcoin_signature *sig,
|
||||
const void *elem, size_t elemsize,
|
||||
@ -575,7 +445,8 @@ u8 **bitcoin_witness_sig_and_element(const tal_t *ctx,
|
||||
|
||||
witness[0] = stack_sig(witness, sig);
|
||||
witness[1] = tal_dup_arr(witness, u8, elem, elemsize, 0);
|
||||
witness[2] = tal_dup_talarr(witness, u8, witnessscript);
|
||||
witness[2] = tal_dup_arr(witness, u8,
|
||||
witnessscript, tal_count(witnessscript), 0);
|
||||
|
||||
return witness;
|
||||
}
|
||||
@ -583,7 +454,7 @@ u8 **bitcoin_witness_sig_and_element(const tal_t *ctx,
|
||||
/* BOLT #3:
|
||||
*
|
||||
* This output sends funds back to the owner of this commitment transaction and
|
||||
* thus must be timelocked using `OP_CHECKSEQUENCEVERIFY`. It can be claimed, without delay,
|
||||
* thus must be timelocked using `OP_CSV`. It can be claimed, without delay,
|
||||
* by the other party if they know the revocation private key. The output is a
|
||||
* version-0 P2WSH, with a witness script:
|
||||
*
|
||||
@ -592,34 +463,13 @@ u8 **bitcoin_witness_sig_and_element(const tal_t *ctx,
|
||||
* <revocationpubkey>
|
||||
* OP_ELSE
|
||||
* `to_self_delay`
|
||||
* OP_CHECKSEQUENCEVERIFY
|
||||
* OP_CSV
|
||||
* OP_DROP
|
||||
* <local_delayedpubkey>
|
||||
* OP_ENDIF
|
||||
* OP_CHECKSIG
|
||||
*/
|
||||
/* BOLT- #3
|
||||
* ##### Leased channel (`option_will_fund`)
|
||||
* If a `lease` applies to the channel, the `to_local` output of the `accepter`
|
||||
* ensures the `leasor` funds are not spendable until the lease expires.
|
||||
*
|
||||
* In a leased channel, the `to_local` output that pays the `accepter` node
|
||||
* is modified so that its CSV is equal to the greater of the
|
||||
* `to_self_delay` or the `lease_end` - `blockheight`.
|
||||
*
|
||||
* OP_IF
|
||||
* # Penalty transaction
|
||||
* <revocationpubkey>
|
||||
* OP_ELSE
|
||||
* MAX(`to_self_delay`, `lease_end` - `blockheight`)
|
||||
* OP_CHECKSEQUENCEVERIFY
|
||||
* OP_DROP
|
||||
* <local_delayedpubkey>
|
||||
* OP_ENDIF
|
||||
* OP_CHECKSIG
|
||||
*/
|
||||
u8 *bitcoin_wscript_to_local(const tal_t *ctx, u16 to_self_delay,
|
||||
u32 lease_remaining,
|
||||
const struct pubkey *revocation_pubkey,
|
||||
const struct pubkey *local_delayedkey)
|
||||
{
|
||||
@ -627,7 +477,7 @@ u8 *bitcoin_wscript_to_local(const tal_t *ctx, u16 to_self_delay,
|
||||
add_op(&script, OP_IF);
|
||||
add_push_key(&script, revocation_pubkey);
|
||||
add_op(&script, OP_ELSE);
|
||||
add_number(&script, max_unsigned(lease_remaining, to_self_delay));
|
||||
add_number(&script, to_self_delay);
|
||||
add_op(&script, OP_CHECKSEQUENCEVERIFY);
|
||||
add_op(&script, OP_DROP);
|
||||
add_push_key(&script, local_delayedkey);
|
||||
@ -642,8 +492,7 @@ u8 *bitcoin_wscript_to_local(const tal_t *ctx, u16 to_self_delay,
|
||||
*
|
||||
* This output sends funds to either an HTLC-timeout transaction after the
|
||||
* HTLC-timeout or to the remote node using the payment preimage or the
|
||||
* revocation key. The output is a P2WSH, with a witness script (no
|
||||
* option_anchors):
|
||||
* revocation key. The output is a P2WSH, with a witness script:
|
||||
*
|
||||
* # To remote node with revocation key
|
||||
* OP_DUP OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL
|
||||
@ -660,33 +509,12 @@ u8 *bitcoin_wscript_to_local(const tal_t *ctx, u16 to_self_delay,
|
||||
* OP_CHECKSIG
|
||||
* OP_ENDIF
|
||||
* OP_ENDIF
|
||||
*
|
||||
* Or, with `option_anchors`:
|
||||
*
|
||||
* # To remote node with revocation key
|
||||
* OP_DUP OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL
|
||||
* OP_IF
|
||||
* OP_CHECKSIG
|
||||
* OP_ELSE
|
||||
* <remote_htlcpubkey> OP_SWAP OP_SIZE 32 OP_EQUAL
|
||||
* OP_NOTIF
|
||||
* # To local node via HTLC-timeout transaction (timelocked).
|
||||
* OP_DROP 2 OP_SWAP <local_htlcpubkey> 2 OP_CHECKMULTISIG
|
||||
* OP_ELSE
|
||||
* # To remote node with preimage.
|
||||
* OP_HASH160 <RIPEMD160(payment_hash)> OP_EQUALVERIFY
|
||||
* OP_CHECKSIG
|
||||
* OP_ENDIF
|
||||
* 1 OP_CHECKSEQUENCEVERIFY OP_DROP
|
||||
* OP_ENDIF
|
||||
*/
|
||||
u8 *bitcoin_wscript_htlc_offer_ripemd160(const tal_t *ctx,
|
||||
const struct pubkey *localhtlckey,
|
||||
const struct pubkey *remotehtlckey,
|
||||
const struct ripemd160 *payment_ripemd,
|
||||
const struct pubkey *revocationkey,
|
||||
bool option_anchor_outputs,
|
||||
bool option_anchors_zero_fee_htlc_tx)
|
||||
const struct pubkey *revocationkey)
|
||||
{
|
||||
u8 *script = tal_arr(ctx, u8, 0);
|
||||
struct ripemd160 ripemd;
|
||||
@ -694,7 +522,7 @@ u8 *bitcoin_wscript_htlc_offer_ripemd160(const tal_t *ctx,
|
||||
add_op(&script, OP_DUP);
|
||||
add_op(&script, OP_HASH160);
|
||||
pubkey_to_hash160(revocationkey, &ripemd);
|
||||
script_push_bytes(&script, &ripemd, sizeof(ripemd));
|
||||
add_push_bytes(&script, &ripemd, sizeof(ripemd));
|
||||
add_op(&script, OP_EQUAL);
|
||||
add_op(&script, OP_IF);
|
||||
add_op(&script, OP_CHECKSIG);
|
||||
@ -713,16 +541,11 @@ u8 *bitcoin_wscript_htlc_offer_ripemd160(const tal_t *ctx,
|
||||
add_op(&script, OP_CHECKMULTISIG);
|
||||
add_op(&script, OP_ELSE);
|
||||
add_op(&script, OP_HASH160);
|
||||
script_push_bytes(&script,
|
||||
payment_ripemd->u.u8, sizeof(payment_ripemd->u.u8));
|
||||
add_push_bytes(&script,
|
||||
payment_ripemd->u.u8, sizeof(payment_ripemd->u.u8));
|
||||
add_op(&script, OP_EQUALVERIFY);
|
||||
add_op(&script, OP_CHECKSIG);
|
||||
add_op(&script, OP_ENDIF);
|
||||
if (option_anchor_outputs || option_anchors_zero_fee_htlc_tx) {
|
||||
add_number(&script, 1);
|
||||
add_op(&script, OP_CHECKSEQUENCEVERIFY);
|
||||
add_op(&script, OP_DROP);
|
||||
}
|
||||
add_op(&script, OP_ENDIF);
|
||||
|
||||
return script;
|
||||
@ -732,18 +555,14 @@ u8 *bitcoin_wscript_htlc_offer(const tal_t *ctx,
|
||||
const struct pubkey *localhtlckey,
|
||||
const struct pubkey *remotehtlckey,
|
||||
const struct sha256 *payment_hash,
|
||||
const struct pubkey *revocationkey,
|
||||
bool option_anchor_outputs,
|
||||
bool option_anchors_zero_fee_htlc_tx)
|
||||
const struct pubkey *revocationkey)
|
||||
{
|
||||
struct ripemd160 ripemd;
|
||||
|
||||
ripemd160(&ripemd, payment_hash->u.u8, sizeof(payment_hash->u));
|
||||
return bitcoin_wscript_htlc_offer_ripemd160(ctx, localhtlckey,
|
||||
remotehtlckey,
|
||||
&ripemd, revocationkey,
|
||||
option_anchor_outputs,
|
||||
option_anchors_zero_fee_htlc_tx);
|
||||
&ripemd, revocationkey);
|
||||
}
|
||||
|
||||
/* BOLT #3:
|
||||
@ -752,8 +571,7 @@ u8 *bitcoin_wscript_htlc_offer(const tal_t *ctx,
|
||||
*
|
||||
* This output sends funds to either the remote node after the HTLC-timeout or
|
||||
* using the revocation key, or to an HTLC-success transaction with a
|
||||
* successful payment preimage. The output is a P2WSH, with a witness script
|
||||
* (no `option_anchors`):
|
||||
* successful payment preimage. The output is a P2WSH, with a witness script:
|
||||
*
|
||||
* # To remote node with revocation key
|
||||
* OP_DUP OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL
|
||||
@ -772,35 +590,13 @@ u8 *bitcoin_wscript_htlc_offer(const tal_t *ctx,
|
||||
* OP_CHECKSIG
|
||||
* OP_ENDIF
|
||||
* OP_ENDIF
|
||||
*
|
||||
* Or, with `option_anchors`:
|
||||
*
|
||||
* # To remote node with revocation key
|
||||
* OP_DUP OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL
|
||||
* OP_IF
|
||||
* OP_CHECKSIG
|
||||
* OP_ELSE
|
||||
* <remote_htlcpubkey> OP_SWAP OP_SIZE 32 OP_EQUAL
|
||||
* OP_IF
|
||||
* # To local node via HTLC-success transaction.
|
||||
* OP_HASH160 <RIPEMD160(payment_hash)> OP_EQUALVERIFY
|
||||
* 2 OP_SWAP <local_htlcpubkey> 2 OP_CHECKMULTISIG
|
||||
* OP_ELSE
|
||||
* # To remote node after timeout.
|
||||
* OP_DROP <cltv_expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP
|
||||
* OP_CHECKSIG
|
||||
* OP_ENDIF
|
||||
* 1 OP_CHECKSEQUENCEVERIFY OP_DROP
|
||||
* OP_ENDIF
|
||||
*/
|
||||
u8 *bitcoin_wscript_htlc_receive_ripemd(const tal_t *ctx,
|
||||
const struct abs_locktime *htlc_abstimeout,
|
||||
const struct pubkey *localhtlckey,
|
||||
const struct pubkey *remotehtlckey,
|
||||
const struct ripemd160 *payment_ripemd,
|
||||
const struct pubkey *revocationkey,
|
||||
bool option_anchor_outputs,
|
||||
bool option_anchors_zero_fee_htlc_tx)
|
||||
const struct pubkey *revocationkey)
|
||||
{
|
||||
u8 *script = tal_arr(ctx, u8, 0);
|
||||
struct ripemd160 ripemd;
|
||||
@ -808,7 +604,7 @@ u8 *bitcoin_wscript_htlc_receive_ripemd(const tal_t *ctx,
|
||||
add_op(&script, OP_DUP);
|
||||
add_op(&script, OP_HASH160);
|
||||
pubkey_to_hash160(revocationkey, &ripemd);
|
||||
script_push_bytes(&script, &ripemd, sizeof(ripemd));
|
||||
add_push_bytes(&script, &ripemd, sizeof(ripemd));
|
||||
add_op(&script, OP_EQUAL);
|
||||
add_op(&script, OP_IF);
|
||||
add_op(&script, OP_CHECKSIG);
|
||||
@ -820,8 +616,8 @@ u8 *bitcoin_wscript_htlc_receive_ripemd(const tal_t *ctx,
|
||||
add_op(&script, OP_EQUAL);
|
||||
add_op(&script, OP_IF);
|
||||
add_op(&script, OP_HASH160);
|
||||
script_push_bytes(&script,
|
||||
payment_ripemd->u.u8, sizeof(payment_ripemd->u.u8));
|
||||
add_push_bytes(&script,
|
||||
payment_ripemd->u.u8, sizeof(payment_ripemd->u.u8));
|
||||
add_op(&script, OP_EQUALVERIFY);
|
||||
add_number(&script, 2);
|
||||
add_op(&script, OP_SWAP);
|
||||
@ -835,11 +631,6 @@ u8 *bitcoin_wscript_htlc_receive_ripemd(const tal_t *ctx,
|
||||
add_op(&script, OP_DROP);
|
||||
add_op(&script, OP_CHECKSIG);
|
||||
add_op(&script, OP_ENDIF);
|
||||
if (option_anchor_outputs || option_anchors_zero_fee_htlc_tx) {
|
||||
add_number(&script, 1);
|
||||
add_op(&script, OP_CHECKSEQUENCEVERIFY);
|
||||
add_op(&script, OP_DROP);
|
||||
}
|
||||
add_op(&script, OP_ENDIF);
|
||||
|
||||
return script;
|
||||
@ -850,18 +641,14 @@ u8 *bitcoin_wscript_htlc_receive(const tal_t *ctx,
|
||||
const struct pubkey *localhtlckey,
|
||||
const struct pubkey *remotehtlckey,
|
||||
const struct sha256 *payment_hash,
|
||||
const struct pubkey *revocationkey,
|
||||
bool option_anchor_outputs,
|
||||
bool option_anchors_zero_fee_htlc_tx)
|
||||
const struct pubkey *revocationkey)
|
||||
{
|
||||
struct ripemd160 ripemd;
|
||||
|
||||
ripemd160(&ripemd, payment_hash->u.u8, sizeof(payment_hash->u));
|
||||
return bitcoin_wscript_htlc_receive_ripemd(ctx, htlc_abstimeout,
|
||||
localhtlckey, remotehtlckey,
|
||||
&ripemd, revocationkey,
|
||||
option_anchor_outputs,
|
||||
option_anchors_zero_fee_htlc_tx);
|
||||
&ripemd, revocationkey);
|
||||
}
|
||||
|
||||
/* BOLT #3:
|
||||
@ -869,7 +656,7 @@ u8 *bitcoin_wscript_htlc_receive(const tal_t *ctx,
|
||||
* ## HTLC-Timeout and HTLC-Success Transactions
|
||||
*
|
||||
*...
|
||||
* * `txin[0]` witness stack: `0 <remotehtlcsig> <localhtlcsig> <payment_preimage>` for HTLC-success, `0 <remotehtlcsig> <localhtlcsig> <>` for HTLC-timeout
|
||||
* * `txin[0]` witness stack: `0 <remotehtlcsig> <localhtlcsig> <payment_preimage>` for HTLC-success, `0 <remotehtlcsig> <localhtlcsig> 0` for HTLC-timeout
|
||||
*/
|
||||
u8 **bitcoin_witness_htlc_timeout_tx(const tal_t *ctx,
|
||||
const struct bitcoin_signature *localhtlcsig,
|
||||
@ -882,7 +669,7 @@ u8 **bitcoin_witness_htlc_timeout_tx(const tal_t *ctx,
|
||||
witness[1] = stack_sig(witness, remotehtlcsig);
|
||||
witness[2] = stack_sig(witness, localhtlcsig);
|
||||
witness[3] = stack_number(witness, 0);
|
||||
witness[4] = tal_dup_talarr(witness, u8, wscript);
|
||||
witness[4] = tal_dup_arr(witness, u8, wscript, tal_count(wscript), 0);
|
||||
|
||||
return witness;
|
||||
}
|
||||
@ -899,7 +686,7 @@ u8 **bitcoin_witness_htlc_success_tx(const tal_t *ctx,
|
||||
witness[1] = stack_sig(witness, remotesig);
|
||||
witness[2] = stack_sig(witness, localhtlcsig);
|
||||
witness[3] = stack_preimage(witness, preimage);
|
||||
witness[4] = tal_dup_talarr(witness, u8, wscript);
|
||||
witness[4] = tal_dup_arr(witness, u8, wscript, tal_count(wscript), 0);
|
||||
|
||||
return witness;
|
||||
}
|
||||
@ -919,7 +706,7 @@ u8 *bitcoin_wscript_htlc_tx(const tal_t *ctx,
|
||||
* <revocationpubkey>
|
||||
* OP_ELSE
|
||||
* `to_self_delay`
|
||||
* OP_CHECKSEQUENCEVERIFY
|
||||
* OP_CSV
|
||||
* OP_DROP
|
||||
* <local_delayedpubkey>
|
||||
* OP_ENDIF
|
||||
@ -938,56 +725,12 @@ u8 *bitcoin_wscript_htlc_tx(const tal_t *ctx,
|
||||
return script;
|
||||
}
|
||||
|
||||
u8 *bitcoin_wscript_anchor(const tal_t *ctx,
|
||||
const struct pubkey *funding_pubkey)
|
||||
{
|
||||
u8 *script = tal_arr(ctx, u8, 0);
|
||||
|
||||
/* BOLT #3:
|
||||
* #### `to_local_anchor` and `to_remote_anchor` Output (option_anchors)
|
||||
*...
|
||||
* <local_funding_pubkey/remote_funding_pubkey> OP_CHECKSIG OP_IFDUP
|
||||
* OP_NOTIF
|
||||
* OP_16 OP_CHECKSEQUENCEVERIFY
|
||||
* OP_ENDIF
|
||||
*/
|
||||
add_push_key(&script, funding_pubkey);
|
||||
add_op(&script, OP_CHECKSIG);
|
||||
add_op(&script, OP_IFDUP);
|
||||
add_op(&script, OP_NOTIF);
|
||||
add_number(&script, 16);
|
||||
add_op(&script, OP_CHECKSEQUENCEVERIFY);
|
||||
add_op(&script, OP_ENDIF);
|
||||
|
||||
assert(is_anchor_witness_script(script, tal_bytelen(script)));
|
||||
return script;
|
||||
}
|
||||
|
||||
bool is_anchor_witness_script(const u8 *script, size_t script_len)
|
||||
{
|
||||
if (script_len != 34 + 1 + 1 + 1 + 1 + 1 + 1)
|
||||
return false;
|
||||
if (script[0] != OP_PUSHBYTES(33))
|
||||
return false;
|
||||
if (script[34] != OP_CHECKSIG)
|
||||
return false;
|
||||
if (script[35] != OP_IFDUP)
|
||||
return false;
|
||||
if (script[36] != OP_NOTIF)
|
||||
return false;
|
||||
if (script[37] != 0x50 + 16)
|
||||
return false;
|
||||
if (script[38] != OP_CHECKSEQUENCEVERIFY)
|
||||
return false;
|
||||
if (script[39] != OP_ENDIF)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool scripteq(const u8 *s1, const u8 *s2)
|
||||
{
|
||||
size_t s1_len = tal_count(s1), s2_len = tal_count(s2);
|
||||
memcheck(s1, s1_len);
|
||||
memcheck(s2, s2_len);
|
||||
return memeq(s1, s1_len, s2, s2_len);
|
||||
memcheck(s1, tal_count(s1));
|
||||
memcheck(s2, tal_count(s2));
|
||||
|
||||
if (tal_count(s1) != tal_count(s2))
|
||||
return false;
|
||||
return memcmp(s1, s2, tal_count(s1)) == 0;
|
||||
}
|
||||
|
||||
@ -3,9 +3,11 @@
|
||||
#include "config.h"
|
||||
#include "signature.h"
|
||||
#include "tx.h"
|
||||
#include <wally_script.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
|
||||
struct bitcoin_address;
|
||||
struct bitcoin_tx_input;
|
||||
struct preimage;
|
||||
struct pubkey;
|
||||
struct sha256;
|
||||
@ -27,11 +29,8 @@ u8 *scriptpubkey_p2sh_hash(const tal_t *ctx, const struct ripemd160 *redeemhash)
|
||||
/* Create an output script using p2pkh */
|
||||
u8 *scriptpubkey_p2pkh(const tal_t *ctx, const struct bitcoin_address *addr);
|
||||
|
||||
/* Create a prunable output script with 20 random bytes.
|
||||
* This is needed since a spend from a p2wpkh to an `OP_RETURN` without
|
||||
* any other outputs would result in a transaction smaller than the
|
||||
* minimum size. */
|
||||
u8 *scriptpubkey_opreturn_padded(const tal_t *ctx);
|
||||
/* Create a prunable output script */
|
||||
u8 *scriptpubkey_opreturn(const tal_t *ctx);
|
||||
|
||||
/* Create an input script which spends p2pkh */
|
||||
u8 *bitcoin_redeem_p2pkh(const tal_t *ctx, const struct pubkey *pubkey,
|
||||
@ -40,10 +39,6 @@ u8 *bitcoin_redeem_p2pkh(const tal_t *ctx, const struct pubkey *pubkey,
|
||||
/* Create the redeemscript for a P2SH + P2WPKH. */
|
||||
u8 *bitcoin_redeem_p2sh_p2wpkh(const tal_t *ctx, const struct pubkey *key);
|
||||
|
||||
/* Create the scriptsig for a redeemscript */
|
||||
u8 *bitcoin_scriptsig_redeem(const tal_t *ctx,
|
||||
const u8 *redeemscript TAKES);
|
||||
|
||||
/* Create scriptsig for p2sh-p2wpkh */
|
||||
u8 *bitcoin_scriptsig_p2sh_p2wpkh(const tal_t *ctx, const struct pubkey *key);
|
||||
|
||||
@ -63,24 +58,6 @@ u8 *scriptpubkey_p2wpkh_derkey(const tal_t *ctx, const u8 der[33]);
|
||||
u8 *scriptpubkey_witness_raw(const tal_t *ctx, u8 version,
|
||||
const u8 *wprog, size_t wprog_size);
|
||||
|
||||
/* Create an output script for a "raw"(perhaps already tweaked) taproot output pubkey */
|
||||
u8 *scriptpubkey_raw_p2tr(const tal_t *ctx, const struct pubkey *output_pubkey);
|
||||
|
||||
/* Same as above, but compressed key is DER-encoded. */
|
||||
u8 *scriptpubkey_raw_p2tr_derkey(const tal_t *ctx, const u8 output_der[33]);
|
||||
|
||||
/* Create an output script for an internal taproot pubkey. Results in different script than
|
||||
* scriptpubkey_raw_p2tr! TODO support merkle root tweaking */
|
||||
u8 *scriptpubkey_p2tr(const tal_t *ctx, const struct pubkey *inner_pubkey);
|
||||
|
||||
/* Same as above, but compressed key is DER-encoded. TODO support merkle root tweaking */
|
||||
u8 *scriptpubkey_p2tr_derkey(const tal_t *ctx, const u8 inner_der[33]);
|
||||
|
||||
/* To-remotekey with csv max(lease_expiry - blockheight, 1) delay. */
|
||||
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,
|
||||
const struct bitcoin_signature *sig1,
|
||||
@ -100,8 +77,8 @@ u8 **bitcoin_witness_sig_and_element(const tal_t *ctx,
|
||||
const u8 *witnessscript);
|
||||
|
||||
/* BOLT #3 to-local output */
|
||||
u8 *bitcoin_wscript_to_local(const tal_t *ctx, u16 to_self_delay,
|
||||
u32 lease_remaining,
|
||||
u8 *bitcoin_wscript_to_local(const tal_t *ctx,
|
||||
u16 to_self_delay,
|
||||
const struct pubkey *revocation_pubkey,
|
||||
const struct pubkey *local_delayedkey);
|
||||
|
||||
@ -110,9 +87,7 @@ u8 *bitcoin_wscript_htlc_offer(const tal_t *ctx,
|
||||
const struct pubkey *localhtlckey,
|
||||
const struct pubkey *remotehtlckey,
|
||||
const struct sha256 *payment_hash,
|
||||
const struct pubkey *revocationkey,
|
||||
bool option_anchor_outputs,
|
||||
bool option_anchors_zero_fee_htlc_tx);
|
||||
const struct pubkey *revocationkey);
|
||||
u8 **bitcoin_witness_htlc_timeout_tx(const tal_t *ctx,
|
||||
const struct bitcoin_signature *localsig,
|
||||
const struct bitcoin_signature *remotesig,
|
||||
@ -122,9 +97,7 @@ u8 *bitcoin_wscript_htlc_receive(const tal_t *ctx,
|
||||
const struct pubkey *localkey,
|
||||
const struct pubkey *remotekey,
|
||||
const struct sha256 *payment_hash,
|
||||
const struct pubkey *revocationkey,
|
||||
bool option_anchor_outputs,
|
||||
bool option_anchors_zero_fee_htlc_tx);
|
||||
const struct pubkey *revocationkey);
|
||||
u8 **bitcoin_witness_htlc_success_tx(const tal_t *ctx,
|
||||
const struct bitcoin_signature *localsig,
|
||||
const struct bitcoin_signature *remotesig,
|
||||
@ -136,17 +109,13 @@ u8 *bitcoin_wscript_htlc_offer_ripemd160(const tal_t *ctx,
|
||||
const struct pubkey *localhtlckey,
|
||||
const struct pubkey *remotehtlckey,
|
||||
const struct ripemd160 *payment_ripemd,
|
||||
const struct pubkey *revocationkey,
|
||||
bool option_anchor_outputs,
|
||||
bool option_anchors_zero_fee_htlc_tx);
|
||||
const struct pubkey *revocationkey);
|
||||
u8 *bitcoin_wscript_htlc_receive_ripemd(const tal_t *ctx,
|
||||
const struct abs_locktime *htlc_abstimeout,
|
||||
const struct pubkey *localkey,
|
||||
const struct pubkey *remotekey,
|
||||
const struct ripemd160 *payment_ripemd,
|
||||
const struct pubkey *revocationkey,
|
||||
bool option_anchor_outputs,
|
||||
bool option_anchors_zero_fee_htlc_tx);
|
||||
const struct pubkey *revocationkey);
|
||||
|
||||
/* BOLT #3 HTLC-success/HTLC-timeout output */
|
||||
u8 *bitcoin_wscript_htlc_tx(const tal_t *ctx,
|
||||
@ -154,43 +123,21 @@ u8 *bitcoin_wscript_htlc_tx(const tal_t *ctx,
|
||||
const struct pubkey *revocation_pubkey,
|
||||
const struct pubkey *local_delayedkey);
|
||||
|
||||
/* Anchor outputs */
|
||||
u8 *bitcoin_wscript_anchor(const tal_t *ctx,
|
||||
const struct pubkey *funding_pubkey);
|
||||
|
||||
/* Is this a pay to pubkey hash? (extract addr if not NULL) */
|
||||
bool is_p2pkh(const u8 *script, size_t script_len, struct bitcoin_address *addr);
|
||||
bool is_p2pkh(const u8 *script, struct bitcoin_address *addr);
|
||||
|
||||
/* Is this a pay to script hash? (extract addr if not NULL) */
|
||||
bool is_p2sh(const u8 *script, size_t script_len, struct ripemd160 *addr);
|
||||
bool is_p2sh(const u8 *script, struct ripemd160 *addr);
|
||||
|
||||
/* Is this (version 0) pay to witness script hash? (extract addr if not NULL) */
|
||||
bool is_p2wsh(const u8 *script, size_t script_len, struct sha256 *addr);
|
||||
bool is_p2wsh(const u8 *script, struct sha256 *addr);
|
||||
|
||||
/* Is this (version 0) pay to witness pubkey hash? (extract addr if not NULL) */
|
||||
bool is_p2wpkh(const u8 *script, size_t script_len, struct bitcoin_address *addr);
|
||||
|
||||
/* Is this a taproot output? (extract xonly_pubkey bytes if not NULL) */
|
||||
bool is_p2tr(const u8 *script, size_t script_len, u8 xonly_pubkey[32]);
|
||||
|
||||
/* Is this one of the above script types? */
|
||||
bool is_known_scripttype(const u8 *script, size_t script_len);
|
||||
|
||||
/* Is this a witness script type? */
|
||||
bool is_known_segwit_scripttype(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);
|
||||
|
||||
/* Is this an anchor witness script? */
|
||||
bool is_anchor_witness_script(const u8 *script, size_t script_len);
|
||||
bool is_p2wpkh(const u8 *script, struct bitcoin_address *addr);
|
||||
|
||||
/* Are these two scripts equal? */
|
||||
bool scripteq(const u8 *s1, const u8 *s2);
|
||||
|
||||
/* Raw "push these bytes" accessor. */
|
||||
void script_push_bytes(u8 **scriptp, const void *mem, size_t len);
|
||||
|
||||
/* OP_DUP + OP_HASH160 + PUSH(20-byte-hash) + OP_EQUALVERIFY + OP_CHECKSIG */
|
||||
#define BITCOIN_SCRIPTPUBKEY_P2PKH_LEN (1 + 1 + 1 + 20 + 1 + 1)
|
||||
|
||||
@ -203,7 +150,4 @@ void script_push_bytes(u8 **scriptp, const void *mem, size_t len);
|
||||
/* OP_0 + PUSH(32-byte-hash) */
|
||||
#define BITCOIN_SCRIPTPUBKEY_P2WSH_LEN (1 + 1 + 32)
|
||||
|
||||
/* OP_1 + PUSH(32-byte-key) */
|
||||
#define BITCOIN_SCRIPTPUBKEY_P2TR_LEN (1 + 1 + 32)
|
||||
|
||||
#endif /* LIGHTNING_BITCOIN_SCRIPT_H */
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
#include "config.h"
|
||||
#include <bitcoin/shadouble.h>
|
||||
#include "shadouble.h"
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <common/utils.h>
|
||||
#include <wire/wire.h>
|
||||
#include <common/type_to_string.h>
|
||||
|
||||
void sha256_double(struct sha256_double *shadouble, const void *p, size_t len)
|
||||
{
|
||||
@ -15,19 +13,4 @@ void sha256_double_done(struct sha256_ctx *shactx, struct sha256_double *res)
|
||||
sha256_done(shactx, &res->sha);
|
||||
sha256(&res->sha, &res->sha, sizeof(res->sha));
|
||||
}
|
||||
|
||||
char *fmt_sha256_double(const tal_t *ctx, const struct sha256_double *shad)
|
||||
{
|
||||
return tal_hexstr(ctx, shad, sizeof(*shad));
|
||||
}
|
||||
|
||||
void towire_sha256_double(u8 **pptr, const struct sha256_double *sha256d)
|
||||
{
|
||||
towire_sha256(pptr, &sha256d->sha);
|
||||
}
|
||||
|
||||
void fromwire_sha256_double(const u8 **cursor, size_t *max,
|
||||
struct sha256_double *sha256d)
|
||||
{
|
||||
fromwire_sha256(cursor, max, &sha256d->sha);
|
||||
}
|
||||
REGISTER_TYPE_TO_HEXSTR(sha256_double);
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
#define LIGHTNING_BITCOIN_SHADOUBLE_H
|
||||
#include "config.h"
|
||||
#include <ccan/crypto/sha256/sha256.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
|
||||
/* To explicitly distinguish between single sha and bitcoin's standard double */
|
||||
struct sha256_double {
|
||||
@ -13,11 +11,4 @@ struct sha256_double {
|
||||
void sha256_double(struct sha256_double *shadouble, const void *p, size_t len);
|
||||
|
||||
void sha256_double_done(struct sha256_ctx *sha256, struct sha256_double *res);
|
||||
|
||||
/* marshal/unmarshal functions */
|
||||
void fromwire_sha256_double(const u8 **cursor, size_t *max,
|
||||
struct sha256_double *sha256d);
|
||||
void towire_sha256_double(u8 **pptr, const struct sha256_double *sha256d);
|
||||
|
||||
char *fmt_sha256_double(const tal_t *ctx, const struct sha256_double *shad);
|
||||
#endif /* LIGHTNING_BITCOIN_SHADOUBLE_H */
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
#include "config.h"
|
||||
#include <bitcoin/short_channel_id.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/type_to_string.h>
|
||||
#include <stdio.h>
|
||||
#include <wire/wire.h>
|
||||
#include <string.h>
|
||||
|
||||
/* BOLT#07:
|
||||
*
|
||||
@ -37,7 +37,8 @@ bool mk_short_channel_id(struct short_channel_id *scid,
|
||||
}
|
||||
|
||||
bool short_channel_id_from_str(const char *str, size_t strlen,
|
||||
struct short_channel_id *dst)
|
||||
struct short_channel_id *dst,
|
||||
bool may_be_deprecated_form)
|
||||
{
|
||||
u32 blocknum, txnum;
|
||||
u16 outnum;
|
||||
@ -47,12 +48,20 @@ bool short_channel_id_from_str(const char *str, size_t strlen,
|
||||
memcpy(buf, str, strlen);
|
||||
buf[strlen] = 0;
|
||||
|
||||
#ifdef COMPAT_V062
|
||||
/* Pre-adelaide format vs. post-adelaide format */
|
||||
if (may_be_deprecated_form && strchr(buf, ':'))
|
||||
matches = sscanf(buf, "%u:%u:%hu", &blocknum, &txnum, &outnum);
|
||||
else
|
||||
matches = sscanf(buf, "%ux%ux%hu", &blocknum, &txnum, &outnum);
|
||||
#else
|
||||
matches = sscanf(buf, "%ux%ux%hu", &blocknum, &txnum, &outnum);
|
||||
#endif
|
||||
return matches == 3
|
||||
&& mk_short_channel_id(dst, blocknum, txnum, outnum);
|
||||
}
|
||||
|
||||
char *fmt_short_channel_id(const tal_t *ctx, struct short_channel_id scid)
|
||||
char *short_channel_id_to_str(const tal_t *ctx, const struct short_channel_id *scid)
|
||||
{
|
||||
return tal_fmt(ctx, "%dx%dx%d",
|
||||
short_channel_id_blocknum(scid),
|
||||
@ -61,12 +70,14 @@ char *fmt_short_channel_id(const tal_t *ctx, struct short_channel_id scid)
|
||||
}
|
||||
|
||||
bool short_channel_id_dir_from_str(const char *str, size_t strlen,
|
||||
struct short_channel_id_dir *scidd)
|
||||
struct short_channel_id_dir *scidd,
|
||||
bool may_be_deprecated_form)
|
||||
{
|
||||
const char *slash = memchr(str, '/', strlen);
|
||||
if (!slash || slash + 2 != str + strlen)
|
||||
return false;
|
||||
if (!short_channel_id_from_str(str, slash - str, &scidd->scid))
|
||||
if (!short_channel_id_from_str(str, slash - str, &scidd->scid,
|
||||
may_be_deprecated_form))
|
||||
return false;
|
||||
if (slash[1] == '0')
|
||||
scidd->dir = 0;
|
||||
@ -77,25 +88,15 @@ bool short_channel_id_dir_from_str(const char *str, size_t strlen,
|
||||
return true;
|
||||
}
|
||||
|
||||
char *fmt_short_channel_id_dir(const tal_t *ctx,
|
||||
const struct short_channel_id_dir *scidd)
|
||||
char *short_channel_id_dir_to_str(const tal_t *ctx,
|
||||
const struct short_channel_id_dir *scidd)
|
||||
{
|
||||
char *str, *scidstr = fmt_short_channel_id(NULL, scidd->scid);
|
||||
char *str, *scidstr = short_channel_id_to_str(NULL, &scidd->scid);
|
||||
str = tal_fmt(ctx, "%s/%u", scidstr, scidd->dir);
|
||||
tal_free(scidstr);
|
||||
return str;
|
||||
}
|
||||
|
||||
void towire_short_channel_id(u8 **pptr,
|
||||
struct short_channel_id short_channel_id)
|
||||
{
|
||||
towire_u64(pptr, short_channel_id.u64);
|
||||
}
|
||||
REGISTER_TYPE_TO_STRING(short_channel_id, short_channel_id_to_str);
|
||||
REGISTER_TYPE_TO_STRING(short_channel_id_dir, short_channel_id_dir_to_str);
|
||||
|
||||
struct short_channel_id fromwire_short_channel_id(const u8 **cursor, size_t *max)
|
||||
{
|
||||
struct short_channel_id scid;
|
||||
|
||||
scid.u64 = fromwire_u64(cursor, max);
|
||||
return scid;
|
||||
}
|
||||
|
||||
@ -1,34 +1,25 @@
|
||||
#ifndef LIGHTNING_BITCOIN_SHORT_CHANNEL_ID_H
|
||||
#define LIGHTNING_BITCOIN_SHORT_CHANNEL_ID_H
|
||||
#include "config.h"
|
||||
#include <ccan/compiler/compiler.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <common/gossip_constants.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* Short Channel ID is composed of 3 bytes for the block height, 3
|
||||
* bytes of tx index in block and 2 bytes of output index. */
|
||||
struct short_channel_id {
|
||||
u64 u64;
|
||||
};
|
||||
|
||||
static inline bool short_channel_id_eq(struct short_channel_id a,
|
||||
struct short_channel_id b)
|
||||
{
|
||||
return a.u64 == b.u64;
|
||||
}
|
||||
|
||||
static inline size_t short_channel_id_hash(struct short_channel_id scid)
|
||||
{
|
||||
/* scids cost money to generate, so simple hash works here */
|
||||
return (scid.u64 >> 32) ^ (scid.u64 >> 16) ^ scid.u64;
|
||||
}
|
||||
/* Define short_channel_id_eq (no padding) */
|
||||
STRUCTEQ_DEF(short_channel_id, 0, u64);
|
||||
|
||||
/* BOLT #7:
|
||||
*
|
||||
* - MUST set `node_id_1` and `node_id_2` to the public keys of the two nodes
|
||||
* operating the channel, such that `node_id_1` is the lexicographically-lesser of the
|
||||
* two compressed keys sorted in ascending lexicographic order.
|
||||
* operating the channel, such that `node_id_1` is the numerically-lesser of the
|
||||
* two DER-encoded keys sorted in ascending numerical order.
|
||||
*...
|
||||
* - if the origin node is `node_id_1` in the message:
|
||||
* - MUST set the `direction` bit of `channel_flags` to 0.
|
||||
@ -41,61 +32,37 @@ struct short_channel_id_dir {
|
||||
int dir;
|
||||
};
|
||||
|
||||
static inline bool short_channel_id_dir_eq(const struct short_channel_id_dir *a,
|
||||
const struct short_channel_id_dir *b)
|
||||
static inline u32 short_channel_id_blocknum(const struct short_channel_id *scid)
|
||||
{
|
||||
return short_channel_id_eq(a->scid, b->scid) && a->dir == b->dir;
|
||||
return scid->u64 >> 40;
|
||||
}
|
||||
|
||||
static inline u32 short_channel_id_blocknum(struct short_channel_id scid)
|
||||
static inline u32 short_channel_id_txnum(const struct short_channel_id *scid)
|
||||
{
|
||||
return scid.u64 >> 40;
|
||||
return (scid->u64 >> 16) & 0x00FFFFFF;
|
||||
}
|
||||
|
||||
static inline bool is_stub_scid(struct short_channel_id scid)
|
||||
static inline u16 short_channel_id_outnum(const struct short_channel_id *scid)
|
||||
{
|
||||
return scid.u64 >> 40 == 1 &&
|
||||
((scid.u64 >> 16) & 0x00FFFFFF) == 1 &&
|
||||
(scid.u64 & 0xFFFF) == 1;
|
||||
}
|
||||
|
||||
static inline u32 short_channel_id_txnum(struct short_channel_id scid)
|
||||
{
|
||||
return (scid.u64 >> 16) & 0x00FFFFFF;
|
||||
}
|
||||
|
||||
static inline u16 short_channel_id_outnum(struct short_channel_id scid)
|
||||
{
|
||||
return scid.u64 & 0xFFFF;
|
||||
}
|
||||
|
||||
/* Subtly, at block N, depth is 1, hence the -1 here. eg. 103x1x0 is announceable
|
||||
* when height is 108. */
|
||||
static inline bool
|
||||
is_scid_depth_announceable(struct short_channel_id scid,
|
||||
unsigned int height)
|
||||
{
|
||||
return short_channel_id_blocknum(scid) + ANNOUNCE_MIN_DEPTH - 1
|
||||
<= height;
|
||||
return scid->u64 & 0xFFFF;
|
||||
}
|
||||
|
||||
/* Returns false if blocknum, txnum or outnum require too many bits */
|
||||
bool WARN_UNUSED_RESULT mk_short_channel_id(struct short_channel_id *scid,
|
||||
u64 blocknum, u64 txnum, u64 outnum);
|
||||
|
||||
/* may_be_deprecated_form allows : separators if COMPAT defined */
|
||||
bool WARN_UNUSED_RESULT short_channel_id_from_str(const char *str, size_t strlen,
|
||||
struct short_channel_id *dst);
|
||||
struct short_channel_id *dst,
|
||||
bool may_be_deprecated_form);
|
||||
|
||||
char *short_channel_id_to_str(const tal_t *ctx, const struct short_channel_id *scid);
|
||||
|
||||
bool WARN_UNUSED_RESULT short_channel_id_dir_from_str(const char *str, size_t strlen,
|
||||
struct short_channel_id_dir *scidd);
|
||||
struct short_channel_id_dir *scidd,
|
||||
bool may_be_deprecated_form);
|
||||
|
||||
char *fmt_short_channel_id(const tal_t *ctx, struct short_channel_id scid);
|
||||
char *fmt_short_channel_id_dir(const tal_t *ctx,
|
||||
const struct short_channel_id_dir *scidd);
|
||||
|
||||
/* Marshal/unmarshal */
|
||||
void towire_short_channel_id(u8 **pptr,
|
||||
struct short_channel_id short_channel_id);
|
||||
struct short_channel_id fromwire_short_channel_id(const u8 **cursor, size_t *max);
|
||||
char *short_channel_id_dir_to_str(const tal_t *ctx,
|
||||
const struct short_channel_id_dir *scidd);
|
||||
|
||||
#endif /* LIGHTNING_BITCOIN_SHORT_CHANNEL_ID_H */
|
||||
|
||||
@ -1,16 +1,14 @@
|
||||
#include "config.h"
|
||||
#include "privkey.h"
|
||||
#include "pubkey.h"
|
||||
#include "script.h"
|
||||
#include "shadouble.h"
|
||||
#include "signature.h"
|
||||
#include "tx.h"
|
||||
#include <assert.h>
|
||||
#include <bitcoin/privkey.h>
|
||||
#include <bitcoin/psbt.h>
|
||||
#include <bitcoin/pubkey.h>
|
||||
#include <bitcoin/script.h>
|
||||
#include <bitcoin/shadouble.h>
|
||||
#include <bitcoin/signature.h>
|
||||
#include <bitcoin/tx.h>
|
||||
#include <ccan/cast/cast.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <common/type_to_string.h>
|
||||
#include <common/utils.h>
|
||||
#include <secp256k1_schnorrsig.h>
|
||||
#include <wire/wire.h>
|
||||
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
@ -36,19 +34,19 @@ static void dump_tx(const char *msg,
|
||||
{
|
||||
size_t i, j;
|
||||
warnx("%s tx version %u locktime %#x:",
|
||||
msg, tx->wtx->version, tx->wtx->locktime);
|
||||
for (i = 0; i < tx->wtx->num_inputs; i++) {
|
||||
msg, tx->version, tx->lock_time);
|
||||
for (i = 0; i < tal_count(tx->input); i++) {
|
||||
warnx("input[%zu].txid = "SHA_FMT, i,
|
||||
SHA_VALS(tx->wtx->inputs[i].txhash));
|
||||
warnx("input[%zu].index = %u", i, tx->wtx->inputs[i].index);
|
||||
SHA_VALS(tx->input[i].txid.sha.u.u8));
|
||||
warnx("input[%zu].index = %u", i, tx->input[i].index);
|
||||
}
|
||||
for (i = 0; i < tx->wtx->num_outputs; i++) {
|
||||
for (i = 0; i < tal_count(tx->output); i++) {
|
||||
warnx("output[%zu].amount = %llu",
|
||||
i, (long long)tx->wtx->outputs[i].satoshi);
|
||||
i, (long long)tx->output[i].amount);
|
||||
warnx("output[%zu].script = %zu",
|
||||
i, tx->wtx->outputs[i].script_len);
|
||||
for (j = 0; j < tx->wtx->outputs[i].script_len; j++)
|
||||
fprintf(stderr, "%02x", tx->wtx->outputs[i].script[j]);
|
||||
i, tal_count(tx->output[i].script));
|
||||
for (j = 0; j < tal_count(tx->output[i].script); j++)
|
||||
fprintf(stderr, "%02x", tx->output[i].script[j]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
warnx("input[%zu].script = %zu", inputnum, tal_count(script));
|
||||
@ -77,79 +75,30 @@ static void dump_tx(const char *msg UNUSED,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Taken from https://github.com/bitcoin/bitcoin/blob/master/src/key.cpp */
|
||||
/* Check that the sig has a low R value and will be less than 71 bytes */
|
||||
static bool sig_has_low_r(const secp256k1_ecdsa_signature* sig)
|
||||
{
|
||||
unsigned char compact_sig[64];
|
||||
secp256k1_ecdsa_signature_serialize_compact(secp256k1_ctx, compact_sig, sig);
|
||||
|
||||
/* In DER serialization, all values are interpreted as big-endian, signed
|
||||
* integers. The highest bit in the integer indicates its signed-ness; 0 is
|
||||
* positive, 1 is negative. When the value is interpreted as a negative
|
||||
* integer, it must be converted to a positive value by prepending a 0x00
|
||||
* byte so that the highest bit is 0. We can avoid this prepending by
|
||||
* ensuring that our highest bit is always 0, and thus we must check that
|
||||
* the first byte is less than 0x80. */
|
||||
return compact_sig[0] < 0x80;
|
||||
}
|
||||
|
||||
bool dev_no_signature_grind = false;
|
||||
|
||||
void sign_hash(const struct privkey *privkey,
|
||||
const struct sha256_double *h,
|
||||
secp256k1_ecdsa_signature *s)
|
||||
{
|
||||
bool ok;
|
||||
unsigned char extra_entropy[32] = {0};
|
||||
|
||||
/* Grind for low R */
|
||||
do {
|
||||
ok = secp256k1_ecdsa_sign(secp256k1_ctx,
|
||||
s,
|
||||
h->sha.u.u8,
|
||||
privkey->secret.data, NULL,
|
||||
dev_no_signature_grind ? NULL
|
||||
: extra_entropy);
|
||||
((u32 *)extra_entropy)[0]++;
|
||||
if (dev_no_signature_grind)
|
||||
break;
|
||||
} while (!sig_has_low_r(s));
|
||||
|
||||
ok = secp256k1_ecdsa_sign(secp256k1_ctx,
|
||||
s,
|
||||
h->sha.u.u8,
|
||||
privkey->secret.data, NULL, NULL);
|
||||
assert(ok);
|
||||
}
|
||||
|
||||
void bitcoin_tx_hash_for_sig(const struct bitcoin_tx *tx, unsigned int in,
|
||||
const u8 *script,
|
||||
enum sighash_type sighash_type,
|
||||
struct sha256_double *dest)
|
||||
static void sha256_tx_one_input(const struct bitcoin_tx *tx,
|
||||
size_t input_num,
|
||||
const u8 *script,
|
||||
const u8 *witness_script,
|
||||
enum sighash_type sighash_type,
|
||||
struct sha256_double *hash)
|
||||
{
|
||||
int ret;
|
||||
u8 value[9];
|
||||
u64 input_val_sats;
|
||||
struct amount_sat input_amt;
|
||||
int flags = WALLY_TX_FLAG_USE_WITNESS;
|
||||
assert(input_num < tal_count(tx->input));
|
||||
|
||||
input_amt = psbt_input_get_amount(tx->psbt, in);
|
||||
input_val_sats = input_amt.satoshis; /* Raw: type conversion */
|
||||
|
||||
/* Wally can allocate here, iff tx doesn't fit on stack */
|
||||
tal_wally_start();
|
||||
if (is_elements(chainparams)) {
|
||||
ret = wally_tx_confidential_value_from_satoshi(input_val_sats, value, sizeof(value));
|
||||
assert(ret == WALLY_OK);
|
||||
ret = wally_tx_get_elements_signature_hash(
|
||||
tx->wtx, in, script, tal_bytelen(script), value,
|
||||
sizeof(value), sighash_type, flags, dest->sha.u.u8,
|
||||
sizeof(*dest));
|
||||
assert(ret == WALLY_OK);
|
||||
} else {
|
||||
ret = wally_tx_get_btc_signature_hash(
|
||||
tx->wtx, in, script, tal_bytelen(script), input_val_sats,
|
||||
sighash_type, flags, dest->sha.u.u8, sizeof(*dest));
|
||||
assert(ret == WALLY_OK);
|
||||
}
|
||||
tal_wally_end(tx->wtx);
|
||||
sha256_tx_for_sig(hash, tx, input_num, script, witness_script,
|
||||
sighash_type);
|
||||
}
|
||||
|
||||
void sign_tx_input(const struct bitcoin_tx *tx,
|
||||
@ -161,14 +110,11 @@ void sign_tx_input(const struct bitcoin_tx *tx,
|
||||
struct bitcoin_signature *sig)
|
||||
{
|
||||
struct sha256_double hash;
|
||||
bool use_segwit = witness_script != NULL;
|
||||
const u8 *script = use_segwit ? witness_script : subscript;
|
||||
|
||||
assert(sighash_type_valid(sighash_type));
|
||||
|
||||
sig->sighash_type = sighash_type;
|
||||
bitcoin_tx_hash_for_sig(tx, in, script, sighash_type, &hash);
|
||||
|
||||
sha256_tx_one_input(tx, in, subscript, witness_script,
|
||||
sighash_type, &hash);
|
||||
dump_tx("Signing", tx, in, subscript, key, &hash);
|
||||
sign_hash(privkey, &hash, &sig->s);
|
||||
}
|
||||
@ -179,14 +125,6 @@ bool check_signed_hash(const struct sha256_double *hash,
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* - if `signature` is incorrect OR non-compliant with
|
||||
* LOW-S-standard rule
|
||||
*/
|
||||
/* From the secp256k1_ecdsa_verify documentation: "To avoid
|
||||
* accepting malleable signatures, only ECDSA signatures in
|
||||
* lower-S form are accepted." */
|
||||
ret = secp256k1_ecdsa_verify(secp256k1_ctx,
|
||||
signature,
|
||||
hash->sha.u.u8, &key->pubkey);
|
||||
@ -200,8 +138,6 @@ bool check_tx_sig(const struct bitcoin_tx *tx, size_t input_num,
|
||||
const struct bitcoin_signature *sig)
|
||||
{
|
||||
struct sha256_double hash;
|
||||
bool use_segwit = witness_script != NULL;
|
||||
const u8 *script = use_segwit ? witness_script : redeemscript;
|
||||
bool ret;
|
||||
|
||||
/* We only support a limited subset of sighash types. */
|
||||
@ -211,10 +147,10 @@ bool check_tx_sig(const struct bitcoin_tx *tx, size_t input_num,
|
||||
if (sig->sighash_type != (SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
|
||||
return false;
|
||||
}
|
||||
assert(input_num < tx->wtx->num_inputs);
|
||||
assert(input_num < tal_count(tx->input));
|
||||
|
||||
bitcoin_tx_hash_for_sig(tx, input_num, script, sig->sighash_type, &hash);
|
||||
dump_tx("check_tx_sig", tx, input_num, script, key, &hash);
|
||||
sha256_tx_one_input(tx, input_num, redeemscript, witness_script,
|
||||
sig->sighash_type, &hash);
|
||||
|
||||
ret = check_signed_hash(&hash, &sig->s, key);
|
||||
if (!ret)
|
||||
@ -324,7 +260,8 @@ bool signature_from_der(const u8 *der, size_t len, struct bitcoin_signature *sig
|
||||
return true;
|
||||
}
|
||||
|
||||
char *fmt_secp256k1_ecdsa_signature(const tal_t *ctx, const secp256k1_ecdsa_signature *sig)
|
||||
static char *signature_to_hexstr(const tal_t *ctx,
|
||||
const secp256k1_ecdsa_signature *sig)
|
||||
{
|
||||
u8 der[72];
|
||||
size_t len = 72;
|
||||
@ -334,99 +271,14 @@ char *fmt_secp256k1_ecdsa_signature(const tal_t *ctx, const secp256k1_ecdsa_sign
|
||||
|
||||
return tal_hexstr(ctx, der, len);
|
||||
}
|
||||
REGISTER_TYPE_TO_STRING(secp256k1_ecdsa_signature, signature_to_hexstr);
|
||||
|
||||
char *fmt_bitcoin_signature(const tal_t *ctx,
|
||||
const struct bitcoin_signature *sig)
|
||||
static char *bitcoin_signature_to_hexstr(const tal_t *ctx,
|
||||
const struct bitcoin_signature *sig)
|
||||
{
|
||||
u8 der[73];
|
||||
size_t len = signature_to_der(der, sig);
|
||||
|
||||
return tal_hexstr(ctx, der, len);
|
||||
}
|
||||
|
||||
void fromwire_bitcoin_signature(const u8 **cursor, size_t *max,
|
||||
struct bitcoin_signature *sig)
|
||||
{
|
||||
fromwire_secp256k1_ecdsa_signature(cursor, max, &sig->s);
|
||||
sig->sighash_type = fromwire_u8(cursor, max);
|
||||
if (!sighash_type_valid(sig->sighash_type))
|
||||
fromwire_fail(cursor, max);
|
||||
}
|
||||
|
||||
void towire_bitcoin_signature(u8 **pptr, const struct bitcoin_signature *sig)
|
||||
{
|
||||
assert(sighash_type_valid(sig->sighash_type));
|
||||
towire_secp256k1_ecdsa_signature(pptr, &sig->s);
|
||||
towire_u8(pptr, sig->sighash_type);
|
||||
}
|
||||
|
||||
void towire_bip340sig(u8 **pptr, const struct bip340sig *bip340sig)
|
||||
{
|
||||
towire_u8_array(pptr, bip340sig->u8, sizeof(bip340sig->u8));
|
||||
}
|
||||
|
||||
void fromwire_bip340sig(const u8 **cursor, size_t *max,
|
||||
struct bip340sig *bip340sig)
|
||||
{
|
||||
fromwire_u8_array(cursor, max, bip340sig->u8, sizeof(bip340sig->u8));
|
||||
}
|
||||
|
||||
char *fmt_bip340sig(const tal_t *ctx, const struct bip340sig *bip340sig)
|
||||
{
|
||||
return tal_hexstr(ctx, bip340sig->u8, sizeof(bip340sig->u8));
|
||||
}
|
||||
|
||||
/* BIP-340:
|
||||
*
|
||||
* This proposal suggests to include the tag by prefixing the hashed
|
||||
* data with ''SHA256(tag) || SHA256(tag)''. Because this is a 64-byte
|
||||
* long context-specific constant and the ''SHA256'' block size is
|
||||
* also 64 bytes, optimized implementations are possible (identical to
|
||||
* SHA256 itself, but with a modified initial state). Using SHA256 of
|
||||
* the tag name itself is reasonably simple and efficient for
|
||||
* implementations that don't choose to use the optimization.
|
||||
*/
|
||||
|
||||
/* For caller convenience, we hand in tag in parts (any can be "") */
|
||||
void bip340_sighash_init(struct sha256_ctx *sctx,
|
||||
const char *tag1,
|
||||
const char *tag2,
|
||||
const char *tag3)
|
||||
{
|
||||
struct sha256 taghash;
|
||||
|
||||
sha256_init(sctx);
|
||||
sha256_update(sctx, memcheck(tag1, strlen(tag1)), strlen(tag1));
|
||||
sha256_update(sctx, memcheck(tag2, strlen(tag2)), strlen(tag2));
|
||||
sha256_update(sctx, memcheck(tag3, strlen(tag3)), strlen(tag3));
|
||||
sha256_done(sctx, &taghash);
|
||||
|
||||
sha256_init(sctx);
|
||||
sha256_update(sctx, &taghash, sizeof(taghash));
|
||||
sha256_update(sctx, &taghash, sizeof(taghash));
|
||||
}
|
||||
|
||||
|
||||
bool check_schnorr_sig(const struct sha256 *hash,
|
||||
const secp256k1_pubkey *pubkey,
|
||||
const struct bip340sig *sig)
|
||||
{
|
||||
/* FIXME: uuuugly! There's no non-xonly verify function. */
|
||||
u8 raw[PUBKEY_CMPR_LEN];
|
||||
size_t outlen = sizeof(raw);
|
||||
secp256k1_xonly_pubkey xonly_pubkey;
|
||||
|
||||
if (!secp256k1_ec_pubkey_serialize(secp256k1_ctx, raw, &outlen,
|
||||
pubkey,
|
||||
SECP256K1_EC_COMPRESSED))
|
||||
abort();
|
||||
assert(outlen == PUBKEY_CMPR_LEN);
|
||||
if (!secp256k1_xonly_pubkey_parse(secp256k1_ctx, &xonly_pubkey, raw+1))
|
||||
abort();
|
||||
|
||||
return secp256k1_schnorrsig_verify(secp256k1_ctx,
|
||||
sig->u8,
|
||||
hash->u.u8,
|
||||
sizeof(hash->u.u8),
|
||||
&xonly_pubkey) == 1;
|
||||
}
|
||||
REGISTER_TYPE_TO_STRING(bitcoin_signature, bitcoin_signature_to_hexstr);
|
||||
|
||||
@ -2,17 +2,14 @@
|
||||
#define LIGHTNING_BITCOIN_SIGNATURE_H
|
||||
#include "config.h"
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <secp256k1.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct sha256;
|
||||
struct sha256_double;
|
||||
struct sha256_ctx;
|
||||
struct bitcoin_tx;
|
||||
struct pubkey;
|
||||
struct privkey;
|
||||
struct bitcoin_tx_output;
|
||||
struct bip340sig;
|
||||
|
||||
enum sighash_type {
|
||||
SIGHASH_ALL = 1,
|
||||
@ -50,21 +47,7 @@ struct bitcoin_signature {
|
||||
};
|
||||
|
||||
/**
|
||||
* bitcoin_tx_hash_for_sig - produce hash for a transaction
|
||||
*
|
||||
* @tx - tx to hash
|
||||
* @in - index that this 'hash' is for
|
||||
* @script - script for the index that's being 'hashed for'
|
||||
* @sighash_type - sighash_type to hash for
|
||||
* @dest - hash result
|
||||
*/
|
||||
void bitcoin_tx_hash_for_sig(const struct bitcoin_tx *tx, unsigned int in,
|
||||
const u8 *script,
|
||||
enum sighash_type sighash_type,
|
||||
struct sha256_double *dest);
|
||||
|
||||
/**
|
||||
* sign_hash - produce a raw secp256k1 signature (with low R value).
|
||||
* sign_hash - produce a raw secp256k1 signature.
|
||||
* @p: secret key
|
||||
* @h: hash to sign.
|
||||
* @sig: signature to fill in and return.
|
||||
@ -123,46 +106,10 @@ bool check_tx_sig(const struct bitcoin_tx *tx, size_t input_num,
|
||||
const struct pubkey *key,
|
||||
const struct bitcoin_signature *sig);
|
||||
|
||||
/**
|
||||
* check a Schnorr signature
|
||||
*/
|
||||
bool check_schnorr_sig(const struct sha256 *hash,
|
||||
const secp256k1_pubkey *pubkey,
|
||||
const struct bip340sig *sig);
|
||||
|
||||
/* Give DER encoding of signature: returns length used (<= 73). */
|
||||
size_t signature_to_der(u8 der[73], const struct bitcoin_signature *sig);
|
||||
|
||||
/* Parse DER encoding into signature sig */
|
||||
bool signature_from_der(const u8 *der, size_t len, struct bitcoin_signature *sig);
|
||||
|
||||
/* Wire marshalling and unmarshalling */
|
||||
void towire_bitcoin_signature(u8 **pptr, const struct bitcoin_signature *sig);
|
||||
void fromwire_bitcoin_signature(const u8 **cursor, size_t *max,
|
||||
struct bitcoin_signature *sig);
|
||||
|
||||
/* Schnorr */
|
||||
struct bip340sig {
|
||||
u8 u8[64];
|
||||
};
|
||||
void towire_bip340sig(u8 **pptr, const struct bip340sig *bip340sig);
|
||||
void fromwire_bip340sig(const u8 **cursor, size_t *max,
|
||||
struct bip340sig *bip340sig);
|
||||
|
||||
/* Get a hex string sig */
|
||||
char *fmt_secp256k1_ecdsa_signature(const tal_t *ctx,
|
||||
const secp256k1_ecdsa_signature *sig);
|
||||
char *fmt_bip340sig(const tal_t *ctx, const struct bip340sig *bip340sig);
|
||||
char *fmt_bitcoin_signature(const tal_t *ctx,
|
||||
const struct bitcoin_signature *sig);
|
||||
|
||||
/* For caller convenience, we hand in tag in parts (any can be "") */
|
||||
void bip340_sighash_init(struct sha256_ctx *sctx,
|
||||
const char *tag1,
|
||||
const char *tag2,
|
||||
const char *tag3);
|
||||
|
||||
/* Some of the spec test vectors assume no sig grinding. */
|
||||
extern bool dev_no_signature_grind;
|
||||
|
||||
#endif /* LIGHTNING_BITCOIN_SIGNATURE_H */
|
||||
|
||||
@ -2,15 +2,14 @@ BITCOIN_TEST_SRC := $(wildcard bitcoin/test/run-*.c)
|
||||
BITCOIN_TEST_OBJS := $(BITCOIN_TEST_SRC:.c=.o)
|
||||
BITCOIN_TEST_PROGRAMS := $(BITCOIN_TEST_OBJS:.o=)
|
||||
|
||||
BITCOIN_TEST_COMMON_OBJS := common/utils.o common/setup.o common/autodata.o
|
||||
BITCOIN_TEST_COMMON_OBJS := common/utils.o
|
||||
|
||||
$(BITCOIN_TEST_PROGRAMS): $(BITCOIN_TEST_COMMON_OBJS) bitcoin/chainparams.o
|
||||
$(BITCOIN_TEST_PROGRAMS): $(CCAN_OBJS) $(BITCOIN_TEST_COMMON_OBJS)
|
||||
$(BITCOIN_TEST_OBJS): $(CCAN_HEADERS) $(BITCOIN_HEADERS) $(BITCOIN_SRC)
|
||||
|
||||
ALL_TEST_PROGRAMS += $(BITCOIN_TEST_PROGRAMS)
|
||||
ALL_C_SOURCES += $(BITCOIN_TEST_PROGRAMS:=.c)
|
||||
ALL_OBJS += $(BITCOIN_TEST_PROGRAMS:=.o)
|
||||
|
||||
# This needs to know what level of optimization we're using.
|
||||
bitcoin/test/run-secret_eq_consttime.o: CFLAGS += -DCOPTFLAGS="\"${COPTFLAGS}\""
|
||||
update-mocks: $(BITCOIN_TEST_SRC:%=update-mocks/%)
|
||||
|
||||
check-units: $(BITCOIN_TEST_PROGRAMS:%=unittest/%)
|
||||
check: $(BITCOIN_TEST_PROGRAMS:%=unittest/%)
|
||||
|
||||
@ -1,204 +0,0 @@
|
||||
#include "config.h"
|
||||
#include "../block.c"
|
||||
#include "../psbt.c"
|
||||
#include "../shadouble.c"
|
||||
#include "../signature.c"
|
||||
#include "../tx.c"
|
||||
#include "../varint.c"
|
||||
#include <assert.h>
|
||||
#include <common/setup.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* 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_feerate */
|
||||
bool amount_feerate(u32 *feerate UNNEEDED, struct amount_sat fee UNNEEDED, size_t weight UNNEEDED)
|
||||
{ fprintf(stderr, "amount_feerate 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_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_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_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_u32 */
|
||||
u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_u32 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 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 scriptpubkey_p2wsh */
|
||||
u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED)
|
||||
{ fprintf(stderr, "scriptpubkey_p2wsh 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_u32 */
|
||||
void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u32 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 const char block[] =
|
||||
"00a09265c15bea24321eecadb27ddf660035ac1f2b450ec03b973e17310f000"
|
||||
"0000000008a0ee58ded5de949325ebc99583e3ca84f96a6597465c611685413"
|
||||
"f50f0ead7eafdc6a5c00013f1a3580194903010000000001010000000000000"
|
||||
"000000000000000000000000000000000000000000000000000ffffffff2703"
|
||||
"9985161a4d696e656420627920416e74506f6f6c2094000103208efc8ad9030"
|
||||
"00000101f0100ffffffff02d2545402000000001976a9144afc312d452c9c49"
|
||||
"9fb8662728b19ac0cd3ea68888ac0000000000000000266a24aa21a9ed08b1d"
|
||||
"c37da139ccd00803738db33e05331819736b3336352dc6e2fa74f1fd67b0120"
|
||||
"000000000000000000000000000000000000000000000000000000000000000"
|
||||
"00000000001000000019b1a8eaec64d596296c3abe9af09cce1dc09996a9ad0"
|
||||
"84aaef0e4f79eb13f1e400000000fd5e0100483045022100b16d81821baf80d"
|
||||
"6af47afea73cbd3f013bf4905c87ba896ed6e545dd00edd3a0220043262bf51"
|
||||
"fe21b22b74a3ed148396077da75969e76b5fd647cda138f323634d014830450"
|
||||
"22100a2b86c9e21b5b8ff0b185e42274bfe1ef6c8d4ec6e43c174bfdac360b6"
|
||||
"8ac2b80220440a60482cfccd5c384c7d62e16e03a86295224b3ef82fb6f7d29"
|
||||
"42657a4b330014cc95241048aa0d470b7a9328889c84ef0291ed30346986e22"
|
||||
"558e80c3ae06199391eae21308a00cdcfb34febc0ea9c80dfd16b01f26c7ec6"
|
||||
"7593cb8ab474aca8fa1d7029d4104cf54956634c4d0bdaf00e6b1871c089b7a"
|
||||
"892d0fecc077f03b91e8d4d146861b0a4fdd237891a9819c878984d4b123f6f"
|
||||
"e92d9bbc05873a1bb4fe510145bf369410471843c33b2971e4944c73d4500ab"
|
||||
"d6f61f7edf9ec919c408cbe12a6c9132d2cb8ebed8253322760d5ec6081165e"
|
||||
"0ab68900683de503f1544f03816d47fec699a53aeffffffff02707712000000"
|
||||
"00001976a9147e1d98594b7b8417ed905904bad4d0de0217ee0288acc9a20a0"
|
||||
"20000000017a9145629021f7668d4ec310ac5e99701a6d6cf95eb8f87000000"
|
||||
"0003000000046113feede7973b484e4b8605d4f8cf2d498c98cef1a30898eb2"
|
||||
"5e0958805031c000000006a47304402207afc3e15fc3c3657981cd4e0cf8afc"
|
||||
"2c62bf37efa7f92eef669d1b4ec0701c93022057bbcb4bb3b5b7b7341d708e8"
|
||||
"bf62975013f658c29fcd22482307b4ee8e223b3012103585914f7d7e37df12b"
|
||||
"df0171503922c86ea2c9f09d4f20c40660a74c883687adffffffff6d2663970"
|
||||
"ee08fbbf1dd9a30ba71ef1bc196cba2b9f6a19db1af4c7995003e8500000000"
|
||||
"6b483045022100906fd4411926dca316ba7127e7072bd0691481883811856ff"
|
||||
"81e4f9c526ec08e022005afc833c37cec7b87c58a8eec66704a0ed277f8e497"
|
||||
"f7512b9cefae3d50d3db012103585914f7d7e37df12bdf0171503922c86ea2c"
|
||||
"9f09d4f20c40660a74c883687adffffffff8356393fa3711040b67f221f1246"
|
||||
"4ea09a770381130b4070bf8514307decba18010000006a47304402200657e98"
|
||||
"4c480a37e2d73534d8314e2a73d315cb2934ad47a84d1ca9f5304332702206b"
|
||||
"212bb3ec549c39dca2f5e7ba5f8ba6020f5d4a975433a2334ceb8ff2f040590"
|
||||
"12103585914f7d7e37df12bdf0171503922c86ea2c9f09d4f20c40660a74c88"
|
||||
"3687adffffffffca9dd5661fc8caf4e5e75aa218c29a004a1d18a6461c493ef"
|
||||
"7c29e9cb77b54c9010000006b483045022100da7635fdaa91d5c293915802b4"
|
||||
"d02a044cd64548b8c23bfaaeec47d25d6039df022053927423c4d29c9a30458"
|
||||
"a837b6715ff50a3a2f5e97268cf606d9a52a30fa486012103585914f7d7e37d"
|
||||
"f12bdf0171503922c86ea2c9f09d4f20c40660a74c883687adffffffff02404"
|
||||
"20f00000000001976a914a2fdc4acc57254d6922607cd02b4826bb458528288"
|
||||
"ac0eb82500000000001976a914e05655a7d90b01ba874d81beff57ee09610ca"
|
||||
"3ce88ac00000000";
|
||||
|
||||
STRUCTEQ_DEF(sha256_double, 0, sha);
|
||||
|
||||
static bool bitcoin_blkid_from_hex(const char *hexstr, size_t hexstr_len,
|
||||
struct bitcoin_blkid *blockid)
|
||||
{
|
||||
struct bitcoin_txid fake_txid;
|
||||
if (!bitcoin_txid_from_hex(hexstr, hexstr_len, &fake_txid))
|
||||
return false;
|
||||
blockid->shad = fake_txid.shad;
|
||||
return true;
|
||||
}
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
struct bitcoin_blkid prev;
|
||||
struct sha256_double merkle;
|
||||
struct bitcoin_txid txid, expected_txid;
|
||||
struct bitcoin_block *b;
|
||||
|
||||
common_setup(argv[0]);
|
||||
chainparams = chainparams_for_network("bitcoin");
|
||||
b = bitcoin_block_from_hex(NULL, chainparams,
|
||||
block, strlen(block));
|
||||
|
||||
assert(b);
|
||||
assert(b->hdr.version == 0x6592a000);
|
||||
bitcoin_blkid_from_hex("0000000000000f31173e973bc00e452b1fac350066df7db2adec1e3224ea5bc1", strlen("0000000000000f31173e973bc00e452b1fac350066df7db2adec1e3224ea5bc1"), &prev);
|
||||
assert(bitcoin_blkid_eq(&prev, &b->hdr.prev_hash));
|
||||
hex_decode("8a0ee58ded5de949325ebc99583e3ca84f96a6597465c611685413f50f0ead7e", strlen("8a0ee58ded5de949325ebc99583e3ca84f96a6597465c611685413f50f0ead7e"), &merkle, sizeof(merkle));
|
||||
assert(sha256_double_eq(&merkle, &b->hdr.merkle_hash));
|
||||
assert(b->hdr.timestamp == 1550507183);
|
||||
assert(b->hdr.nonce == 1226407989);
|
||||
|
||||
assert(tal_count(b->tx) == 3);
|
||||
bitcoin_txid(b->tx[0], &txid);
|
||||
bitcoin_txid_from_hex("14d86acd2158acd1f59ab77ab251e3f5073db905a7b2aed25d3ba7780c3d790c",
|
||||
strlen("14d86acd2158acd1f59ab77ab251e3f5073db905a7b2aed25d3ba7780c3d790c"),
|
||||
&expected_txid);
|
||||
assert(bitcoin_txid_eq(&txid, &expected_txid));
|
||||
|
||||
bitcoin_txid(b->tx[1], &txid);
|
||||
bitcoin_txid_from_hex("c261a53121cc9841f843e2e6e0cff337e4f3c5eee788c982a0bffe771ce69919",
|
||||
strlen("c261a53121cc9841f843e2e6e0cff337e4f3c5eee788c982a0bffe771ce69919"),
|
||||
&expected_txid);
|
||||
assert(bitcoin_txid_eq(&txid, &expected_txid));
|
||||
|
||||
bitcoin_txid(b->tx[2], &txid);
|
||||
bitcoin_txid_from_hex("80cea306607b708a03a1854520729da884e4317b7b51f3d4a622f88176f5e034",
|
||||
strlen("80cea306607b708a03a1854520729da884e4317b7b51f3d4a622f88176f5e034"),
|
||||
&expected_txid);
|
||||
assert(bitcoin_txid_eq(&txid, &expected_txid));
|
||||
|
||||
tal_free(b);
|
||||
common_shutdown();
|
||||
return 0;
|
||||
}
|
||||
@ -1,121 +0,0 @@
|
||||
#include "config.h"
|
||||
#include "../psbt.c"
|
||||
#include "../tx.c"
|
||||
#include "../../wire/towire.c"
|
||||
#include "../../wire/fromwire.c"
|
||||
#include <assert.h>
|
||||
#include <ccan/cast/cast.h>
|
||||
#include <common/setup.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* 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_feerate */
|
||||
bool amount_feerate(u32 *feerate UNNEEDED, struct amount_sat fee UNNEEDED, size_t weight UNNEEDED)
|
||||
{ fprintf(stderr, "amount_feerate 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_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_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_sha256_double */
|
||||
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 scriptpubkey_p2wsh */
|
||||
u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED)
|
||||
{ fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); }
|
||||
/* Generated stub for sha256_double */
|
||||
void sha256_double(struct sha256_double *shadouble UNNEEDED, const void *p UNNEEDED, size_t len UNNEEDED)
|
||||
{ fprintf(stderr, "sha256_double called!\n"); abort(); }
|
||||
/* Generated stub for signature_from_der */
|
||||
bool signature_from_der(const u8 *der UNNEEDED, size_t len UNNEEDED, struct bitcoin_signature *sig UNNEEDED)
|
||||
{ fprintf(stderr, "signature_from_der called!\n"); abort(); }
|
||||
/* Generated stub for signature_to_der */
|
||||
size_t signature_to_der(u8 der[73] UNNEEDED, const struct bitcoin_signature *sig UNNEEDED)
|
||||
{ fprintf(stderr, "signature_to_der called!\n"); abort(); }
|
||||
/* Generated stub for towire_sha256_double */
|
||||
void towire_sha256_double(u8 **pptr UNNEEDED, const struct sha256_double *sha256d UNNEEDED)
|
||||
{ fprintf(stderr, "towire_sha256_double called!\n"); abort(); }
|
||||
/* Generated stub for varint_put */
|
||||
size_t varint_put(u8 buf[VARINT_MAX_LEN] UNNEEDED, varint_t v UNNEEDED)
|
||||
{ fprintf(stderr, "varint_put called!\n"); abort(); }
|
||||
/* Generated stub for varint_size */
|
||||
size_t varint_size(varint_t v UNNEEDED)
|
||||
{ fprintf(stderr, "varint_size called!\n"); abort(); }
|
||||
/* AUTOGENERATED MOCKS END */
|
||||
|
||||
/* This transaction has scriptSig data in it.
|
||||
* We expect that creating a new psbt from it will correctly
|
||||
* populate the PSBT object */
|
||||
static const char *raw_tx = "0200000000010151d12aa54cc6e59a6a92325a8315e93361d9805115a13aa5ba8dbcf30ffd858c000000001716001401fad90abcd66697e2592164722de4a95ebee165fdffffff02603c250200000000160014c2ccab171c2a5be9dab52ec41b825863024c546600093d00000000002200205b8cd3b914cf67cdd8fa6273c930353dd36476734fbd962102c2df53b90880cd02473044022001e73b1745d775521c758e70549ad79b1d076efc34303f416e66ff630f6088e402207b0aa44b35329ae4733463bc9f6ca433c5595f00a902a21c941945a24f8aa577012103d745445c9362665f22e0d96e9e766f273f3260dea39c8a76bfa05dd2684ddccf66000000";
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct bitcoin_tx *tx, *tx2;
|
||||
u8 *msg;
|
||||
size_t len;
|
||||
|
||||
common_setup(argv[0]);
|
||||
chainparams = chainparams_for_network("bitcoin");
|
||||
|
||||
msg = tal_arr(tmpctx, u8, 0);
|
||||
tx = bitcoin_tx_from_hex(tmpctx, raw_tx, strlen(raw_tx));
|
||||
|
||||
/* convert to wire format */
|
||||
towire_bitcoin_tx(&msg, tx);
|
||||
|
||||
len = tal_bytelen(msg);
|
||||
assert(len > 0);
|
||||
|
||||
tx2 = fromwire_bitcoin_tx(tmpctx,
|
||||
cast_const2(const u8 **, &msg), &len);
|
||||
assert(tx2 != NULL);
|
||||
|
||||
/* Witness/scriptsig data is saved down into psbt */
|
||||
assert(tx2->psbt->num_inputs == 1);
|
||||
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);
|
||||
audit_psbt(tx2->psbt, tx2->psbt);
|
||||
|
||||
common_shutdown();
|
||||
return 0;
|
||||
}
|
||||
@ -1,23 +1,13 @@
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <bitcoin/privkey.c>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/time/time.h>
|
||||
#include <common/setup.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* AUTOGENERATED MOCKS START */
|
||||
/* 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 towire */
|
||||
void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED)
|
||||
{ fprintf(stderr, "towire called!\n"); abort(); }
|
||||
/* AUTOGENERATED MOCKS END */
|
||||
static bool verbose = false;
|
||||
|
||||
#define RUNS (16 * 10000)
|
||||
#define RUNS (256 * 10000)
|
||||
static struct timerel const_time_test(struct secret *s1,
|
||||
struct secret *s2,
|
||||
size_t off)
|
||||
@ -74,23 +64,27 @@ static struct timerel nonconst_time_test(struct secret *s1,
|
||||
return time_between(end, start);
|
||||
}
|
||||
|
||||
static struct secret *s1, *s2;
|
||||
|
||||
/* Returns true if test result is expected: we consider 5% "same". */
|
||||
static bool secret_time_test(struct timerel (*test)(struct secret *s1,
|
||||
struct secret *s2,
|
||||
size_t off),
|
||||
bool should_be_const)
|
||||
{
|
||||
struct secret *s1, *s2;
|
||||
struct timerel firstbyte_time, lastbyte_time, diff;
|
||||
|
||||
s1 = calloc(RUNS, sizeof(*s1));
|
||||
s2 = calloc(RUNS, sizeof(*s2));
|
||||
|
||||
firstbyte_time = test(s1, s2, 0);
|
||||
lastbyte_time = test(s1, s2, sizeof(s1->data)-1);
|
||||
|
||||
if (verbose)
|
||||
printf("First byte %u psec vs last byte %u psec\n",
|
||||
(int)time_to_nsec(time_divide(firstbyte_time, RUNS/1000)),
|
||||
(int)time_to_nsec(time_divide(lastbyte_time, RUNS/1000)));
|
||||
free(s1);
|
||||
free(s2);
|
||||
|
||||
printf("First byte %u psec vs last byte %u psec\n",
|
||||
(int)time_to_nsec(time_divide(firstbyte_time, RUNS / 1000)),
|
||||
(int)time_to_nsec(time_divide(lastbyte_time, RUNS / 1000)));
|
||||
|
||||
/* If they differ by more than 5%, get upset. */
|
||||
if (time_less(firstbyte_time, lastbyte_time))
|
||||
@ -106,58 +100,37 @@ static bool secret_time_test(struct timerel (*test)(struct secret *s1,
|
||||
return time_less(time_multiply(diff, 20), firstbyte_time) == should_be_const;
|
||||
}
|
||||
|
||||
#define ITERATIONS 1000
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main(void)
|
||||
{
|
||||
const char *v;
|
||||
int const_success, nonconst_success = ITERATIONS, i;
|
||||
|
||||
common_setup(argv[0]);
|
||||
int success, i;
|
||||
setup_locale();
|
||||
|
||||
/* no point running this under valgrind. */
|
||||
v = getenv("VALGRIND");
|
||||
if (v && atoi(v) == 1)
|
||||
goto exit;
|
||||
exit(0);
|
||||
|
||||
/* this sometimes trips under CI */
|
||||
v = getenv("SLOW_MACHINE");
|
||||
if (v && atoi(v) == 1)
|
||||
goto exit;
|
||||
/* I've never seen this fail more than 5 times */
|
||||
success = 0;
|
||||
for (i = 0; i < 10; i++)
|
||||
success += secret_time_test(const_time_test, true);
|
||||
|
||||
s1 = calloc(RUNS, sizeof(*s1));
|
||||
s2 = calloc(RUNS, sizeof(*s2));
|
||||
printf("=> Within 5%% %u/%u times\n", success, i);
|
||||
if (success < i/2)
|
||||
errx(1, "Only const time %u/%u?", success, i);
|
||||
|
||||
/* When not loaded, this should pass over 50% of the time. */
|
||||
const_success = 0;
|
||||
for (i = 0; i < ITERATIONS; i++)
|
||||
const_success += secret_time_test(const_time_test, true);
|
||||
|
||||
printf("=> Within 5%% %u/%u times\n", const_success, i);
|
||||
/* This, should show measurable differences at least 1/2 the time. */
|
||||
success = 0;
|
||||
for (i = 0; i < 10; i++)
|
||||
success += secret_time_test(nonconst_time_test, false);
|
||||
|
||||
printf("=> More than 5%% slower %u/%u times\n", success, i);
|
||||
/* This fails without -O2 or above, at least here (x86 Ubuntu gcc 7.3) */
|
||||
if (strstr(COPTFLAGS, "-O2") || strstr(COPTFLAGS, "-O3")) {
|
||||
/* Should show measurable differences at least 1/2 the time. */
|
||||
nonconst_success = 0;
|
||||
for (i = 0; i < 1000; i++)
|
||||
nonconst_success
|
||||
+= secret_time_test(nonconst_time_test, false);
|
||||
#ifdef __OPTIMIZE__
|
||||
if (success < i/2)
|
||||
errx(1, "memcmp seemed const time %u/%u?", success, i);
|
||||
#endif
|
||||
|
||||
printf("=> More than 5%% slower %u/%u times\n",
|
||||
nonconst_success, i);
|
||||
}
|
||||
|
||||
/* Now, check loadavg: if we weren't alone, that could explain results */
|
||||
if (const_success < ITERATIONS / 2)
|
||||
errx(1, "Only const time %u/%u?", const_success, i);
|
||||
|
||||
if (nonconst_success < ITERATIONS / 2)
|
||||
errx(1, "memcmp seemed const time %u/%u?",
|
||||
nonconst_success, i);
|
||||
free(s1);
|
||||
free(s2);
|
||||
|
||||
exit:
|
||||
common_shutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1,164 +0,0 @@
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <bitcoin/privkey.c>
|
||||
#include <bitcoin/pubkey.c>
|
||||
#include <bitcoin/script.c>
|
||||
#include <bitcoin/shadouble.c>
|
||||
#include <bitcoin/signature.c>
|
||||
#include <bitcoin/tx.c>
|
||||
#include <bitcoin/varint.c>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <common/setup.h>
|
||||
#include <common/utils.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* 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_feerate */
|
||||
bool amount_feerate(u32 *feerate UNNEEDED, struct amount_sat fee UNNEEDED, size_t weight UNNEEDED)
|
||||
{ fprintf(stderr, "amount_feerate 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_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_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 clone_psbt */
|
||||
struct wally_psbt *clone_psbt(const tal_t *ctx UNNEEDED, const 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(); }
|
||||
/* 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_u32 */
|
||||
u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_u32 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 fromwire_wally_psbt */
|
||||
struct wally_psbt *fromwire_wally_psbt(const tal_t *ctx UNNEEDED,
|
||||
const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_wally_psbt called!\n"); abort(); }
|
||||
/* Generated stub for new_psbt */
|
||||
struct wally_psbt *new_psbt(const tal_t *ctx UNNEEDED,
|
||||
const struct wally_tx *wtx UNNEEDED)
|
||||
{ fprintf(stderr, "new_psbt called!\n"); abort(); }
|
||||
/* Generated stub for psbt_add_output */
|
||||
struct wally_psbt_output *psbt_add_output(struct wally_psbt *psbt UNNEEDED,
|
||||
struct wally_tx_output *output UNNEEDED,
|
||||
size_t insert_at UNNEEDED)
|
||||
{ fprintf(stderr, "psbt_add_output called!\n"); abort(); }
|
||||
/* Generated stub for psbt_append_input */
|
||||
struct wally_psbt_input *psbt_append_input(struct wally_psbt *psbt UNNEEDED,
|
||||
const struct bitcoin_outpoint *outpoint UNNEEDED,
|
||||
u32 sequence UNNEEDED,
|
||||
const u8 *scriptSig UNNEEDED,
|
||||
const u8 *input_wscript UNNEEDED,
|
||||
const u8 *redeemscript UNNEEDED)
|
||||
{ fprintf(stderr, "psbt_append_input 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(); }
|
||||
/* Generated stub for psbt_finalize */
|
||||
bool psbt_finalize(struct wally_psbt *psbt UNNEEDED)
|
||||
{ fprintf(stderr, "psbt_finalize called!\n"); abort(); }
|
||||
/* Generated stub for psbt_input_get_amount */
|
||||
struct amount_sat psbt_input_get_amount(const struct wally_psbt *psbt UNNEEDED,
|
||||
size_t in UNNEEDED)
|
||||
{ fprintf(stderr, "psbt_input_get_amount called!\n"); abort(); }
|
||||
/* Generated stub for psbt_input_set_wit_utxo */
|
||||
void psbt_input_set_wit_utxo(struct wally_psbt *psbt UNNEEDED, size_t in UNNEEDED,
|
||||
const u8 *scriptPubkey UNNEEDED, struct amount_sat amt UNNEEDED)
|
||||
{ fprintf(stderr, "psbt_input_set_wit_utxo 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_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_u32 */
|
||||
void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u32 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(); }
|
||||
/* Generated stub for towire_wally_psbt */
|
||||
void towire_wally_psbt(u8 **pptr UNNEEDED, const struct wally_psbt *psbt UNNEEDED)
|
||||
{ fprintf(stderr, "towire_wally_psbt called!\n"); abort(); }
|
||||
/* AUTOGENERATED MOCKS END */
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
struct privkey p;
|
||||
struct pubkey pub;
|
||||
struct bitcoin_signature sig;
|
||||
struct sha256_double h;
|
||||
u8 **wit;
|
||||
size_t weight;
|
||||
|
||||
common_setup(argv[0]);
|
||||
chainparams = chainparams_for_network("bitcoin");
|
||||
|
||||
memset(&h, 0, sizeof(h));
|
||||
memset(&p, 1, sizeof(p));
|
||||
sign_hash(&p, &h, &sig.s);
|
||||
sig.sighash_type = SIGHASH_ALL;
|
||||
pubkey_from_privkey(&p, &pub);
|
||||
|
||||
wit = bitcoin_witness_2of2(tmpctx, &sig, &sig, &pub, &pub);
|
||||
|
||||
/* 1 byte for num witnesses, one per witness element */
|
||||
weight = 1;
|
||||
|
||||
/* Two signatures, slightly overestimated to be 73 bytes each,
|
||||
* while the actual witness will often be smaller.*/
|
||||
/* BOLT #03:
|
||||
* Signatures are 73 bytes long (the maximum length).
|
||||
*/
|
||||
weight += 2 + 2;
|
||||
|
||||
for (size_t i = 0; i < tal_count(wit); i++)
|
||||
weight += 1 + tal_bytelen(wit[i]);
|
||||
assert(bitcoin_tx_2of2_input_witness_weight() == weight);
|
||||
|
||||
common_shutdown();
|
||||
return 0;
|
||||
}
|
||||
@ -1,112 +1,12 @@
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <bitcoin/psbt.c>
|
||||
#include <bitcoin/pullpush.c>
|
||||
#include <bitcoin/shadouble.c>
|
||||
#include <bitcoin/signature.c>
|
||||
#include <bitcoin/tx.c>
|
||||
#include <bitcoin/varint.c>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <common/setup.h>
|
||||
#include <common/utils.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* 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_feerate */
|
||||
bool amount_feerate(u32 *feerate UNNEEDED, struct amount_sat fee UNNEEDED, size_t weight UNNEEDED)
|
||||
{ fprintf(stderr, "amount_feerate 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_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_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_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_u32 */
|
||||
u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_u32 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 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 scriptpubkey_p2wsh */
|
||||
u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED)
|
||||
{ fprintf(stderr, "scriptpubkey_p2wsh 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_u32 */
|
||||
void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u32 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 */
|
||||
|
||||
const char extended_tx[] =
|
||||
"02000000000101b5bef485c41d0d1f58d1e8a561924ece5c476d86cff063ea10c8df06136e"
|
||||
"b31d00000000171600144aa38e396e1394fb45cbf83f48d1464fbc9f498fffffffff014033"
|
||||
"0f000000000017a9140580ba016669d3efaf09a0b2ec3954469ea2bf038702483045022100"
|
||||
"f2abf9e9cf238c66533af93f23937eae8ac01fb6f105a00ab71dbefb9637dc9502205c1ac7"
|
||||
"45829b3f6889607961f5d817dfa0c8f52bdda12e837c4f7b162f6db8a701210204096eb817"
|
||||
"f7efb414ef4d3d8be39dd04374256d3b054a322d4a6ee22736d03b00000000";
|
||||
const char extended_tx[] = "02000000000101b5bef485c41d0d1f58d1e8a561924ece5c476d86cff063ea10c8df06136eb31d00000000171600144aa38e396e1394fb45cbf83f48d1464fbc9f498fffffffff0140330f000000000017a9140580ba016669d3efaf09a0b2ec3954469ea2bf038702483045022100f2abf9e9cf238c66533af93f23937eae8ac01fb6f105a00ab71dbefb9637dc9502205c1ac745829b3f6889607961f5d817dfa0c8f52bdda12e837c4f7b162f6db8a701210204096eb817f7efb414ef4d3d8be39dd04374256d3b054a322d4a6ee22736d03b00000000";
|
||||
|
||||
static void hexeq(const void *p, size_t len, const char *hex)
|
||||
{
|
||||
@ -119,10 +19,14 @@ static void hexeq(const void *p, size_t len, const char *hex)
|
||||
tal_free(tmphex);
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
static void tal_hexeq(const u8 *p, const char *hex)
|
||||
{
|
||||
common_setup(argv[0]);
|
||||
chainparams = chainparams_for_network("bitcoin");
|
||||
hexeq(p, tal_count(p),hex);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
setup_locale();
|
||||
|
||||
struct bitcoin_tx *tx;
|
||||
|
||||
@ -133,35 +37,29 @@ int main(int argc, const char *argv[])
|
||||
* http://n.bitcoin.ninja/checktx
|
||||
* With much thanks!
|
||||
*/
|
||||
assert(tx->wtx->num_inputs == 1);
|
||||
assert(tx->wtx->num_outputs == 1);
|
||||
assert(tal_count(tx->input) == 1);
|
||||
assert(tal_count(tx->output) == 1);
|
||||
|
||||
reverse_bytes(tx->wtx->inputs[0].txhash,
|
||||
sizeof(tx->wtx->inputs[0].txhash));
|
||||
hexeq(tx->wtx->inputs[0].txhash, sizeof(tx->wtx->inputs[0].txhash),
|
||||
reverse_bytes(tx->input[0].txid.shad.sha.u.u8,
|
||||
sizeof(tx->input[0].txid));
|
||||
hexeq(&tx->input[0].txid, sizeof(tx->input[0].txid),
|
||||
"1db36e1306dfc810ea63f0cf866d475cce4e9261a5e8d1581f0d1dc485f4beb5");
|
||||
assert(tx->wtx->inputs[0].index == 0);
|
||||
assert(tx->input[0].index == 0);
|
||||
|
||||
/* This is a p2sh-p2wpkh: */
|
||||
/* ScriptSig is push of "version 0 + hash of pubkey" */
|
||||
hexeq(tx->wtx->inputs[0].script, tx->wtx->inputs[0].script_len,
|
||||
hexeq(tx->input[0].script, tal_count(tx->input[0].script),
|
||||
"16" "00" "144aa38e396e1394fb45cbf83f48d1464fbc9f498f");
|
||||
|
||||
/* Witness with 2 items */
|
||||
assert(tx->wtx->inputs[0].witness);
|
||||
assert(tx->wtx->inputs[0].witness->num_items == 2);
|
||||
assert(tx->input[0].witness);
|
||||
assert(tal_count(tx->input[0].witness) == 2);
|
||||
|
||||
hexeq(tx->wtx->inputs[0].witness->items[0].witness,
|
||||
tx->wtx->inputs[0].witness->items[0].witness_len,
|
||||
"3045022100f2abf9e9cf238c66533af93f23937eae8ac01fb6f105a00ab71dbe"
|
||||
"fb9637dc9502205c1ac745829b3f6889607961f5d817dfa0c8f52bdda12e837c"
|
||||
"4f7b162f6db8a701");
|
||||
hexeq(tx->wtx->inputs[0].witness->items[1].witness,
|
||||
tx->wtx->inputs[0].witness->items[1].witness_len,
|
||||
"0204096eb817f7efb414ef4d3d8be39dd04374256d3b054a322d4a6ee22736d0"
|
||||
"3b");
|
||||
tal_hexeq(tx->input[0].witness[0],
|
||||
"3045022100f2abf9e9cf238c66533af93f23937eae8ac01fb6f105a00ab71dbefb9637dc9502205c1ac745829b3f6889607961f5d817dfa0c8f52bdda12e837c4f7b162f6db8a701");
|
||||
tal_hexeq(tx->input[0].witness[1],
|
||||
"0204096eb817f7efb414ef4d3d8be39dd04374256d3b054a322d4a6ee22736d03b");
|
||||
|
||||
tal_free(tx);
|
||||
common_shutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
1298
bitcoin/tx.c
1298
bitcoin/tx.c
File diff suppressed because it is too large
Load Diff
355
bitcoin/tx.h
355
bitcoin/tx.h
@ -1,46 +1,25 @@
|
||||
#ifndef LIGHTNING_BITCOIN_TX_H
|
||||
#define LIGHTNING_BITCOIN_TX_H
|
||||
#include "config.h"
|
||||
#include <bitcoin/chainparams.h>
|
||||
#include <bitcoin/shadouble.h>
|
||||
#include <bitcoin/signature.h>
|
||||
#include <bitcoin/varint.h>
|
||||
#include "shadouble.h"
|
||||
#include "signature.h"
|
||||
#include "varint.h"
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <common/amount.h>
|
||||
#include <wally_transaction.h>
|
||||
|
||||
#define BITCOIN_TX_DEFAULT_SEQUENCE 0xFFFFFFFF
|
||||
|
||||
/* BIP 125: Any nsequence < 0xFFFFFFFE is replacable.
|
||||
* And bitcoind uses this value. */
|
||||
#define BITCOIN_TX_RBF_SEQUENCE 0xFFFFFFFD
|
||||
|
||||
struct wally_psbt;
|
||||
struct ripemd160;
|
||||
|
||||
struct bitcoin_txid {
|
||||
struct sha256_double shad;
|
||||
};
|
||||
|
||||
struct bitcoin_outpoint {
|
||||
struct bitcoin_txid txid;
|
||||
u32 n;
|
||||
};
|
||||
|
||||
/* Define bitcoin_txid_eq */
|
||||
STRUCTEQ_DEF(bitcoin_txid, 0, shad.sha.u);
|
||||
|
||||
/* Define bitcoin_outpoint_eq */
|
||||
STRUCTEQ_DEF(bitcoin_outpoint, 0, txid.shad.sha.u, n);
|
||||
|
||||
struct bitcoin_tx {
|
||||
struct wally_tx *wtx;
|
||||
|
||||
/* Keep a reference to the ruleset we have to abide by */
|
||||
const struct chainparams *chainparams;
|
||||
|
||||
/* psbt struct */
|
||||
struct wally_psbt *psbt;
|
||||
u32 version;
|
||||
struct bitcoin_tx_input *input;
|
||||
struct bitcoin_tx_output *output;
|
||||
u32 lock_time;
|
||||
};
|
||||
|
||||
struct bitcoin_tx_output {
|
||||
@ -48,60 +27,46 @@ struct bitcoin_tx_output {
|
||||
u8 *script;
|
||||
};
|
||||
|
||||
enum utxotype {
|
||||
/* Obsolete: we used to have P2SH-wrapped outputs (removed in 24.02, though can still have old UTXOs) */
|
||||
UTXO_P2SH_P2WPKH = 1,
|
||||
/* "bech32" addresses */
|
||||
UTXO_P2WPKH = 2,
|
||||
/* Used for closing addresses: implies ->close_info is non-NULL */
|
||||
UTXO_P2WSH_FROM_CLOSE = 3,
|
||||
/* "p2tr" addresses. */
|
||||
UTXO_P2TR = 4,
|
||||
struct bitcoin_tx_input {
|
||||
struct bitcoin_txid txid;
|
||||
u32 index; /* output number referred to by above */
|
||||
u8 *script;
|
||||
u32 sequence_number;
|
||||
|
||||
/* Value of the output we're spending (NULL if unknown). */
|
||||
struct amount_sat *amount;
|
||||
|
||||
/* Only if BIP141 used. */
|
||||
u8 **witness;
|
||||
};
|
||||
|
||||
struct bitcoin_tx_output *new_tx_output(const tal_t *ctx,
|
||||
struct amount_sat amount,
|
||||
const u8 *script);
|
||||
|
||||
/* SHA256^2 the tx in legacy format. */
|
||||
/* SHA256^2 the tx: simpler than sha256_tx */
|
||||
void bitcoin_txid(const struct bitcoin_tx *tx, struct bitcoin_txid *txid);
|
||||
void wally_txid(const struct wally_tx *wtx, struct bitcoin_txid *txid);
|
||||
|
||||
/* Useful for signature code. Only supports SIGHASH_ALL and
|
||||
* (for segwit) SIGHASH_SINGLE|SIGHASH_ANYONECANPAY. */
|
||||
void sha256_tx_for_sig(struct sha256_double *h, const struct bitcoin_tx *tx,
|
||||
unsigned int input_num,
|
||||
const u8 *script,
|
||||
const u8 *witness_script,
|
||||
enum sighash_type sighash_type);
|
||||
|
||||
/* Linear bytes of tx. */
|
||||
u8 *linearize_tx(const tal_t *ctx, const struct bitcoin_tx *tx);
|
||||
u8 *linearize_wtx(const tal_t *ctx, const struct wally_tx *wtx);
|
||||
|
||||
/* Get weight of tx in Sipa; assumes it will have witnesses! */
|
||||
size_t bitcoin_tx_weight(const struct bitcoin_tx *tx);
|
||||
size_t wally_tx_weight(const struct wally_tx *wtx);
|
||||
/* Get weight of tx in Sipa. */
|
||||
size_t measure_tx_weight(const struct bitcoin_tx *tx);
|
||||
|
||||
/* Allocate a tx: you just need to fill in inputs and outputs (they're
|
||||
* zeroed with inputs' sequence_number set to FFFFFFFF) */
|
||||
struct bitcoin_tx *bitcoin_tx(const tal_t *ctx,
|
||||
const struct chainparams *chainparams,
|
||||
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);
|
||||
struct bitcoin_tx *bitcoin_tx(const tal_t *ctx, varint_t input_count,
|
||||
varint_t output_count);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* <sigh>. Bitcoind represents hashes as little-endian for RPC. */
|
||||
static inline void reverse_bytes(u8 *arr, size_t len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len / 2; i++) {
|
||||
unsigned char tmp = arr[i];
|
||||
arr[i] = arr[len - 1 - i];
|
||||
arr[len - 1 - i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse hex string to get txid (reversed, a-la bitcoind). */
|
||||
bool bitcoin_txid_from_hex(const char *hexstr, size_t hexstr_len,
|
||||
struct bitcoin_txid *txid);
|
||||
@ -110,262 +75,8 @@ bool bitcoin_txid_from_hex(const char *hexstr, size_t hexstr_len,
|
||||
bool bitcoin_txid_to_hex(const struct bitcoin_txid *txid,
|
||||
char *hexstr, size_t hexstr_len);
|
||||
|
||||
/* Create a bitcoin_tx from a psbt */
|
||||
struct bitcoin_tx *bitcoin_tx_with_psbt(const tal_t *ctx,
|
||||
struct wally_psbt *psbt TAKES);
|
||||
|
||||
/* Internal de-linearization functions. */
|
||||
/* Pull a bitcoin tx, and create a PSBT wrapper for it */
|
||||
struct bitcoin_tx *pull_bitcoin_tx(const tal_t *ctx,
|
||||
const u8 **cursor, size_t *max);
|
||||
|
||||
/* Pull a bitcoin tx without creating a PSBT wrapper for it */
|
||||
struct bitcoin_tx *pull_bitcoin_tx_only(const tal_t *ctx,
|
||||
const u8 **cursor, size_t *max);
|
||||
|
||||
/* Helper to create a wally_tx_output: make sure to wally_tx_output_free!
|
||||
* Returns NULL if amount is extreme (wally doesn't like).
|
||||
*/
|
||||
struct wally_tx_output *wally_tx_output(const tal_t *ctx,
|
||||
const u8 *script,
|
||||
struct amount_sat amount);
|
||||
|
||||
/* Add one output to tx. */
|
||||
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);
|
||||
|
||||
/* Add a new input to a bitcoin tx.
|
||||
*
|
||||
* For P2WSH inputs, we'll also store the wscript and/or scriptPubkey
|
||||
* Passing in just the {input_wscript}, we'll generate the scriptPubkey for you.
|
||||
* In some cases we may not have the wscript, in which case the scriptPubkey
|
||||
* should be provided. We'll check that it's P2WSH before saving it */
|
||||
int bitcoin_tx_add_input(struct bitcoin_tx *tx,
|
||||
const struct bitcoin_outpoint *outpoint,
|
||||
u32 sequence, const u8 *scriptSig,
|
||||
struct amount_sat amount, const u8 *scriptPubkey,
|
||||
const u8 *input_wscript);
|
||||
|
||||
/* This is useful because wally uses a raw byte array for txids */
|
||||
bool wally_tx_input_spends(const struct wally_tx_input *input,
|
||||
const struct bitcoin_outpoint *outpoint);
|
||||
|
||||
struct amount_asset
|
||||
wally_tx_output_get_amount(const struct wally_tx_output *output);
|
||||
|
||||
/**
|
||||
* Set the output amount on the transaction.
|
||||
*
|
||||
* Allows changing the amount on the transaction output after it was set on
|
||||
* creation. This is useful to grind a feerate or subtract the fee from an
|
||||
* existing output.
|
||||
*/
|
||||
void bitcoin_tx_output_set_amount(struct bitcoin_tx *tx, int outnum,
|
||||
struct amount_sat amount);
|
||||
|
||||
/**
|
||||
* Helper to get a witness script for an output.
|
||||
*/
|
||||
u8 *bitcoin_tx_output_get_witscript(const tal_t *ctx, const struct bitcoin_tx *tx, int outnum);
|
||||
|
||||
/** bitcoin_tx_output_get_amount_sat - Helper to get transaction output's amount
|
||||
*
|
||||
* Internally we use a `wally_tx` to represent the transaction. The
|
||||
* satoshi amount isn't a struct amount_sat, so we need a conversion
|
||||
*/
|
||||
void bitcoin_tx_output_get_amount_sat(const struct bitcoin_tx *tx, int outnum,
|
||||
struct amount_sat *amount);
|
||||
/**
|
||||
* Helper to just get an amount_sat for the output amount.
|
||||
*/
|
||||
struct amount_asset bitcoin_tx_output_get_amount(const struct bitcoin_tx *tx,
|
||||
int outnum);
|
||||
|
||||
/**
|
||||
* Set the input witness.
|
||||
*
|
||||
* Given that we generate the witness after constructing the transaction
|
||||
* itself, we need a way to attach a witness to an existing input.
|
||||
*/
|
||||
void bitcoin_tx_input_set_witness(struct bitcoin_tx *tx, int innum,
|
||||
u8 **witness TAKES);
|
||||
|
||||
/**
|
||||
* Set the input script on the given input.
|
||||
*/
|
||||
void bitcoin_tx_input_set_script(struct bitcoin_tx *tx, int innum, u8 *script);
|
||||
|
||||
/**
|
||||
* Wrap the raw txhash in the wally_tx_input into a bitcoin_txid
|
||||
*/
|
||||
void bitcoin_tx_input_get_outpoint(const struct bitcoin_tx *tx,
|
||||
int innum,
|
||||
struct bitcoin_outpoint *outpoint);
|
||||
|
||||
void bitcoin_tx_input_get_txid(const struct bitcoin_tx *tx, int innum,
|
||||
struct bitcoin_txid *out);
|
||||
void wally_tx_input_get_txid(const struct wally_tx_input *in,
|
||||
struct bitcoin_txid *txid);
|
||||
|
||||
void wally_tx_input_get_outpoint(const struct wally_tx_input *in,
|
||||
struct bitcoin_outpoint *outpoint);
|
||||
|
||||
/**
|
||||
* Overwrite the txhash and index in the wally_tx_input
|
||||
*/
|
||||
void bitcoin_tx_input_set_outpoint(struct bitcoin_tx *tx, int innum,
|
||||
const struct bitcoin_outpoint *outpoint);
|
||||
|
||||
/**
|
||||
* Check a transaction for consistency.
|
||||
*
|
||||
* Mainly for the transition from `bitcoin_tx` to the `wally_tx`. Checks that
|
||||
* both transactions serialize to two identical representations.
|
||||
*/
|
||||
bool bitcoin_tx_check(const struct bitcoin_tx *tx);
|
||||
|
||||
|
||||
/**
|
||||
* Finalize a transaction by truncating overallocated and temporary
|
||||
* fields. This includes adding a fee output for elements transactions or
|
||||
* adjusting an existing fee output, and resizing metadata arrays for inputs
|
||||
* and outputs.
|
||||
*/
|
||||
void bitcoin_tx_finalize(struct bitcoin_tx *tx);
|
||||
|
||||
/**
|
||||
* Returns true if the given outnum is a fee output
|
||||
*/
|
||||
bool elements_wtx_output_is_fee(const struct wally_tx *tx, int outnum);
|
||||
|
||||
/**
|
||||
* Returns true if the given outnum is a fee output
|
||||
*/
|
||||
bool elements_tx_output_is_fee(const struct bitcoin_tx *tx, int outnum);
|
||||
|
||||
/** Attempt to compute the elements overhead given a base bitcoin size.
|
||||
*
|
||||
* The overhead consists of 2 empty proofs for the transaction, 6 bytes of
|
||||
* proofs per input and 35 bytes per output. In addition the explicit fee
|
||||
* output will add 9 bytes and the per output overhead as well.
|
||||
*/
|
||||
static inline size_t elements_tx_overhead(const struct chainparams *chainparams,
|
||||
size_t incount, size_t outcount)
|
||||
{
|
||||
size_t overhead;
|
||||
|
||||
if (!chainparams->is_elements)
|
||||
return 0;
|
||||
|
||||
/* Each transaction has surjection and rangeproof (both empty
|
||||
* for us as long as we use unblinded L-BTC transactions). */
|
||||
overhead = 2 * 4;
|
||||
/* For elements we also need to add the fee output and the
|
||||
* overhead for rangeproofs into the mix. */
|
||||
overhead += (8 + 1) * 4; /* Bitcoin style output */
|
||||
|
||||
/* All outputs have a bit of elements overhead (incl fee) */
|
||||
overhead += (32 + 1 + 1 + 1) * 4 * (outcount + 1); /* Elements added fields */
|
||||
|
||||
/* Inputs have 6 bytes of blank proofs attached. */
|
||||
overhead += 6 * incount;
|
||||
|
||||
return overhead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the fees for this transaction
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* This is needed for cases where the transaction's psbt metadata isn't properly filled
|
||||
* in typically due to being instantiated from a tx hex (i.e. from a block scan)
|
||||
*/
|
||||
struct amount_sat bitcoin_tx_compute_fee_w_inputs(const struct bitcoin_tx *tx,
|
||||
struct amount_sat input_val);
|
||||
|
||||
/* Wire marshalling and unmarshalling */
|
||||
void fromwire_bitcoin_txid(const u8 **cursor, size_t *max,
|
||||
struct bitcoin_txid *txid);
|
||||
struct bitcoin_tx *fromwire_bitcoin_tx(const tal_t *ctx,
|
||||
const u8 **cursor, size_t *max);
|
||||
void towire_bitcoin_txid(u8 **pptr, const struct bitcoin_txid *txid);
|
||||
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);
|
||||
char *fmt_bitcoin_txid(const tal_t *ctx, const struct bitcoin_txid *txid);
|
||||
char *fmt_bitcoin_outpoint(const tal_t *ctx,
|
||||
const struct bitcoin_outpoint *outpoint);
|
||||
char *fmt_wally_tx(const tal_t *ctx, const struct wally_tx *tx);
|
||||
|
||||
/* For want of somewhere better to define them! */
|
||||
char *fmt_sha256(const tal_t *ctx, const struct sha256 *sha256);
|
||||
char *fmt_ripemd160(const tal_t *ctx, const struct ripemd160 *ripemd160);
|
||||
|
||||
/* Various weights of transaction parts. */
|
||||
size_t bitcoin_tx_core_weight(size_t num_inputs, size_t num_outputs);
|
||||
size_t bitcoin_tx_output_weight(size_t outscript_len);
|
||||
|
||||
/* Weight to push sig on stack. */
|
||||
size_t bitcoin_tx_input_sig_weight(void);
|
||||
|
||||
/* Segwit input, but with parameter for witness weight (size).
|
||||
* witness_weight must include the varint_size() for each witness element,
|
||||
* but not the varint_size() for the number of elements. */
|
||||
size_t bitcoin_tx_input_weight(bool p2sh, size_t witness_weight);
|
||||
|
||||
/* The witness weight */
|
||||
size_t bitcoin_tx_input_witness_weight(enum utxotype utxotype);
|
||||
|
||||
/* The witness for our 2of2 input (closing or commitment tx). */
|
||||
size_t bitcoin_tx_2of2_input_witness_weight(void);
|
||||
|
||||
/**
|
||||
* change_weight - what's the weight of a change output?
|
||||
*/
|
||||
size_t change_weight(void);
|
||||
|
||||
/**
|
||||
* change_fee - what's the cost to add a change output to this tx?
|
||||
* @feerate_perkw: feerate.
|
||||
* @total_weight: current weight of tx.
|
||||
*
|
||||
* We pass in the total_weight of the tx (up until this point) so as
|
||||
* to avoid any off-by-one errors with rounding the change fee (down)
|
||||
*/
|
||||
struct amount_sat change_fee(u32 feerate_perkw, size_t total_weight);
|
||||
|
||||
/**
|
||||
* change_amount - Is it worth making a change output at this feerate?
|
||||
* @excess: input amount we have above the tx fee and other outputs.
|
||||
* @feerate_perkw: feerate.
|
||||
* @total_weight: current weight of tx.
|
||||
*
|
||||
* Change script is P2TR for Bitcoin, P2WPKH for Elements
|
||||
*
|
||||
* If it's not worth (or possible) to make change, returns AMOUNT_SAT(0).
|
||||
* Otherwise returns the amount of the change output to add (@excess minus
|
||||
* the change_fee()).
|
||||
*/
|
||||
struct amount_sat change_amount(struct amount_sat excess, u32 feerate_perkw,
|
||||
size_t total_weight);
|
||||
|
||||
#endif /* LIGHTNING_BITCOIN_TX_H */
|
||||
|
||||
@ -1,381 +0,0 @@
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <bitcoin/tx_parts.h>
|
||||
#include <common/utils.h>
|
||||
#include <wire/wire.h>
|
||||
|
||||
/* This destructor makes it behave like a native tal tree (a little!) */
|
||||
static void destroy_wally_tx_input(struct wally_tx_input *in)
|
||||
{
|
||||
wally_tx_input_free(in);
|
||||
}
|
||||
|
||||
static void destroy_wally_tx_output(struct wally_tx_output *out)
|
||||
{
|
||||
wally_tx_output_free(out);
|
||||
}
|
||||
|
||||
struct tx_parts *tx_parts_from_wally_tx(const tal_t *ctx,
|
||||
const struct wally_tx *wtx,
|
||||
int input, int output)
|
||||
{
|
||||
struct tx_parts *txp = tal(ctx, struct tx_parts);
|
||||
|
||||
wally_txid(wtx, &txp->txid);
|
||||
txp->inputs = tal_arrz(txp, struct wally_tx_input *, wtx->num_inputs);
|
||||
txp->outputs = tal_arrz(txp, struct wally_tx_output *, wtx->num_outputs);
|
||||
|
||||
tal_wally_start();
|
||||
for (size_t i = 0; i < wtx->num_inputs; i++) {
|
||||
if (input != -1 && input != i)
|
||||
continue;
|
||||
if (wally_tx_input_clone_alloc(&wtx->inputs[i],
|
||||
&txp->inputs[i]) != WALLY_OK)
|
||||
abort();
|
||||
tal_add_destructor(txp->inputs[i], destroy_wally_tx_input);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < wtx->num_outputs; i++) {
|
||||
if (output != -1 && output != i)
|
||||
continue;
|
||||
if (wally_tx_output_clone_alloc(&wtx->outputs[i],
|
||||
&txp->outputs[i]) != WALLY_OK)
|
||||
abort();
|
||||
tal_add_destructor(txp->outputs[i], destroy_wally_tx_output);
|
||||
|
||||
/* Cheat a bit by also setting the numeric satoshi
|
||||
* value, otherwise we end up converting a
|
||||
* number of times */
|
||||
if (chainparams->is_elements) {
|
||||
struct amount_asset asset;
|
||||
struct amount_sat sats;
|
||||
asset = wally_tx_output_get_amount(txp->outputs[i]);
|
||||
/* FIXME: non l-btc assets */
|
||||
assert(amount_asset_is_main(&asset));
|
||||
sats = amount_asset_to_sat(&asset);
|
||||
txp->outputs[i]->satoshi = sats.satoshis; /* Raw: wally conversion */
|
||||
}
|
||||
}
|
||||
tal_wally_end(txp);
|
||||
|
||||
return txp;
|
||||
}
|
||||
|
||||
static void destroy_wally_tx_witness_stack(struct wally_tx_witness_stack *ws)
|
||||
{
|
||||
wally_tx_witness_stack_free(ws);
|
||||
}
|
||||
|
||||
/* FIXME: If libwally exposed their linearization code, we could use it */
|
||||
static struct wally_tx_witness_stack *
|
||||
fromwire_wally_tx_witness_stack(const tal_t *ctx,
|
||||
const u8 **cursor,
|
||||
size_t *max)
|
||||
{
|
||||
struct wally_tx_witness_stack *ws;
|
||||
size_t num;
|
||||
int ret;
|
||||
|
||||
num = fromwire_u32(cursor, max);
|
||||
if (num == 0)
|
||||
return NULL;
|
||||
|
||||
tal_wally_start();
|
||||
ret = wally_tx_witness_stack_init_alloc(num, &ws);
|
||||
if (ret != WALLY_OK) {
|
||||
fromwire_fail(cursor, max);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
u8 *w = fromwire_tal_arrn(tmpctx,
|
||||
cursor, max,
|
||||
fromwire_u32(cursor, max));
|
||||
ret = wally_tx_witness_stack_add(ws, w, tal_bytelen(w));
|
||||
if (ret != WALLY_OK) {
|
||||
wally_tx_witness_stack_free(ws);
|
||||
fromwire_fail(cursor, max);
|
||||
ws = NULL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
tal_add_destructor(ws, destroy_wally_tx_witness_stack);
|
||||
out:
|
||||
tal_wally_end_onto(ctx, ws, struct wally_tx_witness_stack);
|
||||
return ws;
|
||||
}
|
||||
|
||||
static void towire_wally_tx_witness_stack(u8 **pptr,
|
||||
const struct wally_tx_witness_stack *ws)
|
||||
{
|
||||
if (!ws) {
|
||||
towire_u32(pptr, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
towire_u32(pptr, ws->num_items);
|
||||
for (size_t i = 0; i < ws->num_items; i++) {
|
||||
towire_u32(pptr, ws->items[i].witness_len);
|
||||
towire_u8_array(pptr,
|
||||
ws->items[i].witness,
|
||||
ws->items[i].witness_len);
|
||||
}
|
||||
}
|
||||
|
||||
static struct wally_tx_input *fromwire_wally_tx_input(const tal_t *ctx,
|
||||
const u8 **cursor,
|
||||
size_t *max)
|
||||
{
|
||||
struct wally_tx_input *in;
|
||||
struct bitcoin_txid txid;
|
||||
u32 index, sequence;
|
||||
u8 *script;
|
||||
struct wally_tx_witness_stack *ws;
|
||||
int ret;
|
||||
|
||||
fromwire_bitcoin_txid(cursor, max, &txid);
|
||||
index = fromwire_u32(cursor, max);
|
||||
sequence = fromwire_u32(cursor, max);
|
||||
script = fromwire_tal_arrn(tmpctx,
|
||||
cursor, max, fromwire_u32(cursor, max));
|
||||
/* libwally doesn't like non-NULL ptrs with zero lengths. */
|
||||
if (tal_bytelen(script) == 0)
|
||||
script = tal_free(script);
|
||||
ws = fromwire_wally_tx_witness_stack(tmpctx, cursor, max);
|
||||
|
||||
tal_wally_start();
|
||||
if (is_elements(chainparams)) {
|
||||
u8 *blinding_nonce, *entropy, *issuance_amount,
|
||||
*inflation_keys, *issuance_amount_rangeproof,
|
||||
*inflation_keys_rangeproof;
|
||||
struct wally_tx_witness_stack *pegin_witness;
|
||||
|
||||
blinding_nonce = fromwire_tal_arrn(tmpctx,
|
||||
cursor, max,
|
||||
fromwire_u32(cursor, max));
|
||||
entropy = fromwire_tal_arrn(tmpctx,
|
||||
cursor, max,
|
||||
fromwire_u32(cursor, max));
|
||||
issuance_amount = fromwire_tal_arrn(tmpctx,
|
||||
cursor, max,
|
||||
fromwire_u32(cursor, max));
|
||||
inflation_keys = fromwire_tal_arrn(tmpctx,
|
||||
cursor, max,
|
||||
fromwire_u32(cursor, max));
|
||||
issuance_amount_rangeproof = fromwire_tal_arrn(tmpctx,
|
||||
cursor, max,
|
||||
fromwire_u32(cursor, max));
|
||||
inflation_keys_rangeproof = fromwire_tal_arrn(tmpctx,
|
||||
cursor, max,
|
||||
fromwire_u32(cursor, max));
|
||||
pegin_witness = fromwire_wally_tx_witness_stack(tmpctx,
|
||||
cursor, max);
|
||||
ret = wally_tx_elements_input_init_alloc
|
||||
(txid.shad.sha.u.u8, sizeof(txid.shad.sha.u.u8),
|
||||
index, sequence,
|
||||
script, tal_bytelen(script),
|
||||
ws,
|
||||
blinding_nonce, tal_bytelen(blinding_nonce),
|
||||
entropy, tal_bytelen(entropy),
|
||||
issuance_amount, tal_bytelen(issuance_amount),
|
||||
inflation_keys, tal_bytelen(inflation_keys),
|
||||
issuance_amount_rangeproof,
|
||||
tal_bytelen(issuance_amount_rangeproof),
|
||||
inflation_keys_rangeproof,
|
||||
tal_bytelen(inflation_keys_rangeproof),
|
||||
pegin_witness,
|
||||
&in);
|
||||
} else {
|
||||
ret = wally_tx_input_init_alloc(txid.shad.sha.u.u8,
|
||||
sizeof(txid.shad.sha.u.u8),
|
||||
index, sequence,
|
||||
script, tal_bytelen(script),
|
||||
ws, &in);
|
||||
}
|
||||
if (ret != WALLY_OK) {
|
||||
fromwire_fail(cursor, max);
|
||||
in = NULL;
|
||||
} else {
|
||||
tal_add_destructor(in, destroy_wally_tx_input);
|
||||
}
|
||||
|
||||
tal_wally_end_onto(ctx, in, struct wally_tx_input);
|
||||
return in;
|
||||
}
|
||||
|
||||
static struct wally_tx_output *fromwire_wally_tx_output(const tal_t *ctx,
|
||||
const u8 **cursor,
|
||||
size_t *max)
|
||||
{
|
||||
struct wally_tx_output *out;
|
||||
unsigned char *script;
|
||||
int ret;
|
||||
|
||||
script = fromwire_tal_arrn(tmpctx,
|
||||
cursor, max, fromwire_u32(cursor, max));
|
||||
|
||||
tal_wally_start();
|
||||
if (is_elements(chainparams)) {
|
||||
u8 *asset, *value, *nonce, *surjectionproof, *rangeproof;
|
||||
|
||||
asset = fromwire_tal_arrn(tmpctx,
|
||||
cursor, max,
|
||||
fromwire_u32(cursor, max));
|
||||
value = fromwire_tal_arrn(tmpctx,
|
||||
cursor, max,
|
||||
fromwire_u32(cursor, max));
|
||||
nonce = fromwire_tal_arrn(tmpctx,
|
||||
cursor, max,
|
||||
fromwire_u32(cursor, max));
|
||||
surjectionproof = fromwire_tal_arrn(tmpctx,
|
||||
cursor, max,
|
||||
fromwire_u32(cursor, max));
|
||||
rangeproof = fromwire_tal_arrn(tmpctx,
|
||||
cursor, max,
|
||||
fromwire_u32(cursor, max));
|
||||
ret = wally_tx_elements_output_init_alloc
|
||||
(script, tal_bytelen(script),
|
||||
asset, tal_bytelen(asset),
|
||||
value, tal_bytelen(value),
|
||||
nonce, tal_bytelen(nonce),
|
||||
surjectionproof, tal_bytelen(surjectionproof),
|
||||
rangeproof, tal_bytelen(rangeproof),
|
||||
&out);
|
||||
|
||||
/* As a convenience, we sent the value over as satoshis */
|
||||
out->satoshi = fromwire_u64(cursor, max);
|
||||
} else {
|
||||
u64 satoshi;
|
||||
satoshi = fromwire_u64(cursor, max);
|
||||
ret = wally_tx_output_init_alloc(satoshi,
|
||||
script, tal_bytelen(script),
|
||||
&out);
|
||||
}
|
||||
if (ret != WALLY_OK) {
|
||||
fromwire_fail(cursor, max);
|
||||
out = NULL;
|
||||
} else {
|
||||
tal_add_destructor(out, destroy_wally_tx_output);
|
||||
}
|
||||
tal_wally_end_onto(ctx, out, struct wally_tx_output);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static void towire_wally_tx_input(u8 **pptr, const struct wally_tx_input *in)
|
||||
{
|
||||
/* Just like a bitcoin_txid */
|
||||
towire_u8_array(pptr, in->txhash, sizeof(in->txhash));
|
||||
towire_u32(pptr, in->index);
|
||||
towire_u32(pptr, in->sequence);
|
||||
towire_u32(pptr, in->script_len);
|
||||
towire_u8_array(pptr, in->script, in->script_len);
|
||||
towire_wally_tx_witness_stack(pptr, in->witness);
|
||||
|
||||
if (is_elements(chainparams)) {
|
||||
towire_u32(pptr, sizeof(in->blinding_nonce));
|
||||
towire_u8_array(pptr, in->blinding_nonce,
|
||||
sizeof(in->blinding_nonce));
|
||||
towire_u32(pptr, sizeof(in->entropy));
|
||||
towire_u8_array(pptr, in->entropy, sizeof(in->entropy));
|
||||
towire_u32(pptr, in->issuance_amount_len);
|
||||
towire_u8_array(pptr, in->issuance_amount,
|
||||
in->issuance_amount_len);
|
||||
towire_u32(pptr, in->inflation_keys_len);
|
||||
towire_u8_array(pptr, in->inflation_keys,
|
||||
in->inflation_keys_len);
|
||||
towire_u32(pptr, in->issuance_amount_rangeproof_len);
|
||||
towire_u8_array(pptr, in->issuance_amount_rangeproof,
|
||||
in->issuance_amount_rangeproof_len);
|
||||
towire_u32(pptr, in->inflation_keys_rangeproof_len);
|
||||
towire_u8_array(pptr, in->inflation_keys_rangeproof,
|
||||
in->inflation_keys_rangeproof_len);
|
||||
towire_wally_tx_witness_stack(pptr, in->pegin_witness);
|
||||
}
|
||||
}
|
||||
|
||||
static void towire_wally_tx_output(u8 **pptr, const struct wally_tx_output *out)
|
||||
{
|
||||
towire_u32(pptr, out->script_len);
|
||||
towire_u8_array(pptr, out->script, out->script_len);
|
||||
|
||||
if (is_elements(chainparams)) {
|
||||
towire_u32(pptr, out->asset_len);
|
||||
towire_u8_array(pptr, out->asset, out->asset_len);
|
||||
towire_u32(pptr, out->value_len);
|
||||
towire_u8_array(pptr, out->value, out->value_len);
|
||||
towire_u32(pptr, out->nonce_len);
|
||||
towire_u8_array(pptr, out->nonce, out->nonce_len);
|
||||
towire_u32(pptr, out->surjectionproof_len);
|
||||
towire_u8_array(pptr, out->surjectionproof,
|
||||
out->surjectionproof_len);
|
||||
towire_u32(pptr, out->rangeproof_len);
|
||||
towire_u8_array(pptr, out->rangeproof, out->rangeproof_len);
|
||||
/* Copy the value over, as a convenience */
|
||||
towire_u64(pptr, out->satoshi);
|
||||
} else {
|
||||
towire_u64(pptr, out->satoshi);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wire marshalling and unmarshalling */
|
||||
struct tx_parts *fromwire_tx_parts(const tal_t *ctx,
|
||||
const u8 **cursor, size_t *max)
|
||||
{
|
||||
struct tx_parts *txp = tal(ctx, struct tx_parts);
|
||||
u32 num_inputs, num_outputs;
|
||||
|
||||
fromwire_bitcoin_txid(cursor, max, &txp->txid);
|
||||
num_inputs = fromwire_u32(cursor, max);
|
||||
txp->inputs = tal_arr(txp, struct wally_tx_input *, num_inputs);
|
||||
for (size_t i = 0; i < num_inputs; i++) {
|
||||
if (fromwire_bool(cursor, max)) {
|
||||
txp->inputs[i] = fromwire_wally_tx_input(txp->inputs,
|
||||
cursor, max);
|
||||
} else {
|
||||
txp->inputs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
num_outputs = fromwire_u32(cursor, max);
|
||||
txp->outputs = tal_arr(txp, struct wally_tx_output *, num_outputs);
|
||||
for (size_t i = 0; i < num_outputs; i++) {
|
||||
if (fromwire_bool(cursor, max)) {
|
||||
txp->outputs[i] = fromwire_wally_tx_output(txp->outputs,
|
||||
cursor, max);
|
||||
} else {
|
||||
txp->outputs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (*cursor == NULL)
|
||||
return tal_free(txp);
|
||||
|
||||
return txp;
|
||||
}
|
||||
|
||||
void towire_tx_parts(u8 **pptr, const struct tx_parts *txp)
|
||||
{
|
||||
towire_bitcoin_txid(pptr, &txp->txid);
|
||||
|
||||
towire_u32(pptr, tal_count(txp->inputs));
|
||||
for (size_t i = 0; i < tal_count(txp->inputs); i++) {
|
||||
if (txp->inputs[i]) {
|
||||
towire_bool(pptr, true);
|
||||
towire_wally_tx_input(pptr, txp->inputs[i]);
|
||||
} else {
|
||||
towire_bool(pptr, false);
|
||||
}
|
||||
}
|
||||
|
||||
towire_u32(pptr, tal_count(txp->outputs));
|
||||
for (size_t i = 0; i < tal_count(txp->outputs); i++) {
|
||||
if (txp->outputs[i]) {
|
||||
towire_bool(pptr, true);
|
||||
towire_wally_tx_output(pptr, txp->outputs[i]);
|
||||
} else {
|
||||
towire_bool(pptr, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
/* This represents a specific part of a transaction, without including
|
||||
* all the metadata (which we might not know, if we didn't make the
|
||||
* transction ourselves). */
|
||||
#ifndef LIGHTNING_BITCOIN_TX_PARTS_H
|
||||
#define LIGHTNING_BITCOIN_TX_PARTS_H
|
||||
#include "config.h"
|
||||
#include <bitcoin/tx.h>
|
||||
|
||||
struct tx_parts {
|
||||
/* The txid of this transacation */
|
||||
struct bitcoin_txid txid;
|
||||
/* A subset of inputs: NULL means it's not included. */
|
||||
struct wally_tx_input **inputs;
|
||||
/* A subset of outputs: NULL means it's not included. */
|
||||
struct wally_tx_output **outputs;
|
||||
};
|
||||
|
||||
/* Initialize this from a wally_tx: input/output == -1 for all,
|
||||
* otherwise the input/output number to include. */
|
||||
struct tx_parts *tx_parts_from_wally_tx(const tal_t *ctx,
|
||||
const struct wally_tx *wtx,
|
||||
int input, int output);
|
||||
|
||||
/* Wire marshalling and unmarshalling */
|
||||
struct tx_parts *fromwire_tx_parts(const tal_t *ctx,
|
||||
const u8 **cursor, size_t *max);
|
||||
void towire_tx_parts(u8 **pptr, const struct tx_parts *tx_parts);
|
||||
#endif /* LIGHTNING_BITCOIN_TX_PARTS_H */
|
||||
@ -1,16 +1,4 @@
|
||||
#include "config.h"
|
||||
#include <bitcoin/varint.h>
|
||||
|
||||
size_t varint_size(varint_t v)
|
||||
{
|
||||
if (v < 0xfd)
|
||||
return 1;
|
||||
if (v <= 0xffff)
|
||||
return 3;
|
||||
if (v <= 0xffffffff)
|
||||
return 5;
|
||||
return 9;
|
||||
}
|
||||
#include "varint.h"
|
||||
|
||||
size_t varint_put(u8 buf[VARINT_MAX_LEN], varint_t v)
|
||||
{
|
||||
|
||||
@ -9,13 +9,9 @@
|
||||
|
||||
#define VARINT_MAX_LEN 9
|
||||
|
||||
/* Calculate bytes used (up to 9) */
|
||||
size_t varint_size(varint_t v);
|
||||
|
||||
/* Returns bytes used (up to 9) */
|
||||
size_t varint_put(u8 buf[VARINT_MAX_LEN], varint_t v);
|
||||
|
||||
/* Returns bytes used: 0 if max_len too small. */
|
||||
size_t varint_get(const u8 *p, size_t max_len, varint_t *val);
|
||||
|
||||
#endif /* LIGHTNING_BITCOIN_VARINT_H */
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
CCAN imported from http://ccodearchive.net.
|
||||
|
||||
CCAN version: init-2593-gca094039
|
||||
CCAN version: init-2458-g8cc0749a
|
||||
|
||||
111
ccan/ccan/autodata/_info
Normal file
111
ccan/ccan/autodata/_info
Normal file
@ -0,0 +1,111 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* autodata - stash pointers in your binary for automatic registration
|
||||
*
|
||||
* This code allows declarations in your source which you can gather
|
||||
* together at runtime to form tables. This is often used in place of
|
||||
* having a central registration function or table.
|
||||
*
|
||||
* Note that this technique does not work in general for shared libaries,
|
||||
* only for code compiled into a binary.
|
||||
*
|
||||
* License: BSD-MIT
|
||||
*
|
||||
* Example:
|
||||
* // Distributed commandline option registration (note: ccan/opt is better!)
|
||||
* #include <ccan/autodata/autodata.h>
|
||||
* #include <stdio.h>
|
||||
* #include <unistd.h>
|
||||
* #include <stdbool.h>
|
||||
* #include <err.h>
|
||||
*
|
||||
* static bool verbose = false;
|
||||
*
|
||||
* // This would normally be in a header, so any C file can use it.
|
||||
* struct option {
|
||||
* char c;
|
||||
* bool takes_arg;
|
||||
* bool (*cb)(char *optarg);
|
||||
* };
|
||||
* AUTODATA_TYPE(options, struct option);
|
||||
* #define REGISTER_OPTION(optstruct) \
|
||||
* AUTODATA(options, (optstruct))
|
||||
*
|
||||
* // Now a few examples (could be anywhere in source)
|
||||
* static bool verbose_cb(char *unused)
|
||||
* {
|
||||
* verbose = true;
|
||||
* return true;
|
||||
* }
|
||||
* static struct option dash_v = { 'v', false, verbose_cb };
|
||||
* REGISTER_OPTION(&dash_v);
|
||||
*
|
||||
* static bool chdir_cb(char *dir)
|
||||
* {
|
||||
* if (verbose)
|
||||
* printf("chdir to %s. ", dir);
|
||||
* if (chdir(dir) != 0)
|
||||
* return false;
|
||||
* return true;
|
||||
* }
|
||||
* static struct option dash_C = { 'C', true, chdir_cb };
|
||||
* REGISTER_OPTION(&dash_C);
|
||||
*
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* struct option **opts;
|
||||
* size_t i, num;
|
||||
* int o;
|
||||
* char *optstring, *p;
|
||||
*
|
||||
* // Gather together all the registered options.
|
||||
* opts = autodata_get(options, &num);
|
||||
*
|
||||
* // Make pretty string for getopt().
|
||||
* p = optstring = malloc(num * 2 + 1);
|
||||
* for (i = 0; i < num; i++) {
|
||||
* *(p++) = opts[i]->c;
|
||||
* if (opts[i]->takes_arg)
|
||||
* *(p++) = ':';
|
||||
* }
|
||||
* *p = '\0';
|
||||
*
|
||||
* while ((o = getopt(argc, argv, optstring)) != -1) {
|
||||
* if (o == '?')
|
||||
* exit(1);
|
||||
* // Call callback in matching option.
|
||||
* for (i = 0; i < num; i++) {
|
||||
* if (opts[i]->c == o) {
|
||||
* if (!opts[i]->cb(optarg))
|
||||
* err(1, "parsing -%c", o);
|
||||
* break;
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* // free up gathered option table.
|
||||
* autodata_free(opts);
|
||||
*
|
||||
* if (verbose)
|
||||
* printf("verbose mode on\n");
|
||||
* return 0;
|
||||
* }
|
||||
* // Given "-v" outputs "verbose mode on\n"
|
||||
* // Given "-v -C /" outputs "chdir to /. verbose mode on\n"
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* Expect exactly one argument */
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
printf("ccan/compiler\n");
|
||||
printf("ccan/ptr_valid\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
80
ccan/ccan/autodata/autodata.c
Normal file
80
ccan/ccan/autodata/autodata.c
Normal file
@ -0,0 +1,80 @@
|
||||
// Licensed under BSD-MIT: See LICENSE.
|
||||
#include "autodata.h"
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#if HAVE_SECTION_START_STOP
|
||||
void *autodata_get_section(void *start, void *stop, size_t *nump)
|
||||
{
|
||||
*nump = (void **)(stop) - (void **)(start);
|
||||
return start;
|
||||
}
|
||||
|
||||
void autodata_free(void *table UNNEEDED)
|
||||
{
|
||||
}
|
||||
#else
|
||||
#include <ccan/ptr_valid/ptr_valid.h>
|
||||
|
||||
void *autodata_make_table(const void *example, const char *name, size_t *nump)
|
||||
{
|
||||
const char *start, *end, *tag;
|
||||
struct ptr_valid_batch batch;
|
||||
const void *const magic = (void *)AUTODATA_MAGIC;
|
||||
void **table = NULL;
|
||||
char first_magic;
|
||||
|
||||
if (!ptr_valid_batch_start(&batch))
|
||||
return NULL;
|
||||
|
||||
/* Get range to search. */
|
||||
for (start = (char *)((intptr_t)example & ~(getpagesize() - 1));
|
||||
ptr_valid_batch(&batch, start-getpagesize(), 1, sizeof(void *),
|
||||
false);
|
||||
start -= getpagesize());
|
||||
|
||||
for (end = (char *)((intptr_t)example & ~(getpagesize() - 1));
|
||||
ptr_valid_batch(&batch, end, 1, sizeof(void *), false);
|
||||
end += getpagesize());
|
||||
|
||||
*nump = 0;
|
||||
first_magic = *(char *)&magic;
|
||||
for (tag = memchr(start, first_magic, end - start);
|
||||
tag;
|
||||
tag = memchr(tag+1, first_magic, end - (tag + 1))) {
|
||||
void *adata[4];
|
||||
|
||||
/* We can read 4 void *'s here? */
|
||||
if (tag + sizeof(adata) > end)
|
||||
continue;
|
||||
|
||||
memcpy(adata, tag, sizeof(adata));
|
||||
|
||||
/* False match? */
|
||||
if (adata[0] != (void *)AUTODATA_MAGIC || adata[1] != tag)
|
||||
continue;
|
||||
|
||||
/* OK, check name. */
|
||||
if (!ptr_valid_batch_string(&batch, adata[3])
|
||||
|| strcmp(name, adata[3]) != 0)
|
||||
continue;
|
||||
|
||||
if (!ptr_valid_batch_read(&batch, (char *)adata[2]))
|
||||
continue;
|
||||
|
||||
table = realloc(table, sizeof(void *) * (*nump + 1));
|
||||
if (!table)
|
||||
break;
|
||||
table[*nump] = adata[2];
|
||||
(*nump)++;
|
||||
}
|
||||
ptr_valid_batch_end(&batch);
|
||||
return table;
|
||||
}
|
||||
|
||||
void autodata_free(void *table)
|
||||
{
|
||||
free(table);
|
||||
}
|
||||
#endif
|
||||
109
ccan/ccan/autodata/autodata.h
Normal file
109
ccan/ccan/autodata/autodata.h
Normal file
@ -0,0 +1,109 @@
|
||||
// Licensed under BSD-MIT: See LICENSE.
|
||||
#ifndef CCAN_AUTODATA_H
|
||||
#define CCAN_AUTODATA_H
|
||||
#include "config.h"
|
||||
#include <ccan/compiler/compiler.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if HAVE_SECTION_START_STOP
|
||||
|
||||
/**
|
||||
* AUTODATA_TYPE - declare the type for a given autodata name.
|
||||
* @name: the name for this set of autodata
|
||||
* @type: the type this autodata points to
|
||||
*
|
||||
* This macro is usually placed in a header: it must precede any
|
||||
* autodata functions in the file.
|
||||
*
|
||||
* Example:
|
||||
* #include <ccan/autodata/autodata.h>
|
||||
*
|
||||
* // My set of char pointers.
|
||||
* AUTODATA_TYPE(names, char);
|
||||
*/
|
||||
#define AUTODATA_TYPE(name, type) \
|
||||
typedef type autodata_##name##_; \
|
||||
extern type *__start_xautodata_##name[], *__stop_xautodata_##name[]
|
||||
|
||||
/**
|
||||
* AUTODATA - add a pointer to this autodata set
|
||||
* @name: the name of the set of autodata
|
||||
* @ptr: the compile-time-known pointer
|
||||
*
|
||||
* This embeds @ptr into the binary, with the tag corresponding to
|
||||
* @name (which must look like a valid identifier, no punctuation!).
|
||||
* The type of @ptr must match that given by AUTODATA_TYPE. It is
|
||||
* usually a file-level declaration.
|
||||
*
|
||||
* Example:
|
||||
* // Put two char pointers into the names AUTODATA set.
|
||||
* AUTODATA(names, "Arabella");
|
||||
* AUTODATA(names, "Alex");
|
||||
*/
|
||||
#define AUTODATA(name, ptr) \
|
||||
static const autodata_##name##_ *NEEDED \
|
||||
__attribute__((section("xautodata_" #name))) \
|
||||
AUTODATA_VAR_(name, __LINE__) = (ptr);
|
||||
|
||||
/**
|
||||
* autodata_get - get an autodata set
|
||||
* @name: the name of the set of autodata
|
||||
* @nump: the number of items in the set.
|
||||
*
|
||||
* This extract the embedded pointers matching @name. It may fail
|
||||
* if malloc() fails, or if there is no AUTODATA at all.
|
||||
*
|
||||
* The return will be a pointer to an array of @type pointers (from
|
||||
* AUTODATA_TYPE).
|
||||
*
|
||||
* Example:
|
||||
* static void print_embedded_names(void)
|
||||
* {
|
||||
* unsigned int i;
|
||||
* size_t num;
|
||||
* char **n = autodata_get(names, &num);
|
||||
*
|
||||
* for (i = 0; i < num; i++)
|
||||
* printf("%s\n", n[i]);
|
||||
* }
|
||||
*/
|
||||
#define autodata_get(name, nump) \
|
||||
((autodata_##name##_ **) \
|
||||
autodata_get_section(__start_xautodata_##name, \
|
||||
__stop_xautodata_##name, (nump)))
|
||||
#endif /* HAVE_SECTION_START_STOP */
|
||||
|
||||
/**
|
||||
* autodata_free - free the table returned by autodata_get()
|
||||
* @p: the table.
|
||||
*/
|
||||
void autodata_free(void *p);
|
||||
|
||||
/* Internal functions. */
|
||||
#define AUTODATA_VAR__(name, line) autodata_##name##_##line
|
||||
#define AUTODATA_VAR_(name, line) AUTODATA_VAR__(name, line)
|
||||
|
||||
#if HAVE_SECTION_START_STOP
|
||||
void *autodata_get_section(void *start, void *stop, size_t *nump);
|
||||
#else
|
||||
#define AUTODATA_TYPE(name, type) \
|
||||
typedef type autodata_##name##_; \
|
||||
static const void *autodata_##name##_ex = &autodata_##name##_ex
|
||||
|
||||
#define AUTODATA_MAGIC ((long)0xFEEDA10DA7AF00D5ULL)
|
||||
#define AUTODATA(name, ptr) \
|
||||
static const autodata_##name##_ *NEEDED \
|
||||
AUTODATA_VAR_(name, __LINE__)[4] = \
|
||||
{ (void *)AUTODATA_MAGIC, \
|
||||
(void *)&AUTODATA_VAR_(name, __LINE__), \
|
||||
(ptr), \
|
||||
(void *)#name }
|
||||
|
||||
#define autodata_get(name, nump) \
|
||||
((autodata_##name##_ **) \
|
||||
autodata_make_table(&autodata_##name##_ex, #name, (nump)))
|
||||
|
||||
void *autodata_make_table(const void *example, const char *name, size_t *nump);
|
||||
#endif
|
||||
|
||||
#endif /* CCAN_AUTODATA_H */
|
||||
6
ccan/ccan/autodata/test/helper.c
Normal file
6
ccan/ccan/autodata/test/helper.c
Normal file
@ -0,0 +1,6 @@
|
||||
/* Check that linking together works. */
|
||||
#include <ccan/autodata/autodata.h>
|
||||
|
||||
AUTODATA_TYPE(autostrings, char);
|
||||
|
||||
AUTODATA(autostrings, "helper");
|
||||
71
ccan/ccan/autodata/test/run-fools.c
Normal file
71
ccan/ccan/autodata/test/run-fools.c
Normal file
@ -0,0 +1,71 @@
|
||||
#include <ccan/autodata/autodata.h>
|
||||
/* Include the C files directly. */
|
||||
#include <ccan/autodata/autodata.c>
|
||||
#include <ccan/tap/tap.h>
|
||||
|
||||
AUTODATA_TYPE(autostrings, char);
|
||||
|
||||
AUTODATA(autostrings, "genuine");
|
||||
|
||||
#if !HAVE_SECTION_START_STOP
|
||||
/* These are all fake, to test the various failure paths. */
|
||||
/* Hopefully fake_alpha or fake_omega will test run-past-end. */
|
||||
static const void *NEEDED fake_alpha[] = { (void *)AUTODATA_MAGIC };
|
||||
|
||||
/* Wrong magic in the middle. */
|
||||
static const void *NEEDED fake1[] = { (void *)(AUTODATA_MAGIC ^ 0x10000),
|
||||
(void *)&fake1,
|
||||
"fake1",
|
||||
(void *)"autostrings" };
|
||||
|
||||
/* Wrong self pointer. */
|
||||
static const void *NEEDED fake2[] = { (void *)AUTODATA_MAGIC,
|
||||
(void *)&fake1,
|
||||
"fake2",
|
||||
(void *)"autostrings" };
|
||||
|
||||
/* Wrong name. */
|
||||
static const void *NEEDED fake3[] = { (void *)AUTODATA_MAGIC,
|
||||
(void *)&fake3,
|
||||
"fake3",
|
||||
(void *)"autostrings2" };
|
||||
|
||||
/* Invalid self-pointer. */
|
||||
static const void *NEEDED fake4[] = { (void *)AUTODATA_MAGIC,
|
||||
(void *)1UL,
|
||||
"fake4",
|
||||
(void *)"autostrings" };
|
||||
|
||||
/* Invalid name pointer */
|
||||
static const void *NEEDED fake5[] = { (void *)AUTODATA_MAGIC,
|
||||
(void *)&fake5,
|
||||
"fake5",
|
||||
(void *)1UL };
|
||||
|
||||
/* Invalid contents pointer */
|
||||
static const void *NEEDED fake6[] = { (void *)AUTODATA_MAGIC,
|
||||
(void *)&fake6,
|
||||
(char *)1UL,
|
||||
(void *)"autostrings" };
|
||||
|
||||
static const void *NEEDED fake_omega[] = { (void *)AUTODATA_MAGIC };
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char **table;
|
||||
size_t num;
|
||||
|
||||
/* This is how many tests you plan to run */
|
||||
plan_tests(2);
|
||||
|
||||
table = autodata_get(autostrings, &num);
|
||||
ok1(num == 2);
|
||||
ok1((!strcmp(table[0], "genuine") && !strcmp(table[1], "helper"))
|
||||
|| (!strcmp(table[1], "genuine") && !strcmp(table[0], "helper")));
|
||||
|
||||
autodata_free(table);
|
||||
|
||||
/* This exits depending on whether all tests passed */
|
||||
return exit_status();
|
||||
}
|
||||
41
ccan/ccan/autodata/test/run.c
Normal file
41
ccan/ccan/autodata/test/run.c
Normal file
@ -0,0 +1,41 @@
|
||||
#include <ccan/autodata/autodata.h>
|
||||
/* Include the C files directly. */
|
||||
#include <ccan/autodata/autodata.c>
|
||||
#include <ccan/tap/tap.h>
|
||||
|
||||
AUTODATA_TYPE(autostrings, char);
|
||||
|
||||
AUTODATA(autostrings, "hello");
|
||||
AUTODATA(autostrings, "world");
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char **table;
|
||||
size_t num;
|
||||
int i, hello = -1, world = -1, helper = -1;
|
||||
|
||||
/* This is how many tests you plan to run */
|
||||
plan_tests(4);
|
||||
|
||||
table = autodata_get(autostrings, &num);
|
||||
ok1(num == 3);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (strcmp(table[i], "hello") == 0)
|
||||
hello = i;
|
||||
else if (strcmp(table[i], "world") == 0)
|
||||
world = i;
|
||||
else if (strcmp(table[i], "helper") == 0)
|
||||
helper = i;
|
||||
else
|
||||
fail("Unknown entry %s", table[i]);
|
||||
}
|
||||
ok1(hello != -1);
|
||||
ok1(world != -1);
|
||||
ok1(helper != -1);
|
||||
|
||||
autodata_free(table);
|
||||
|
||||
/* This exits depending on whether all tests passed */
|
||||
return exit_status();
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* base64 - base64 encoding and decoding (rfc4648).
|
||||
*
|
||||
* base64 encoding is used to encode data in a 7-bit clean manner.
|
||||
* Commonly used for escaping data before encapsulation or transfer
|
||||
*
|
||||
* Example:
|
||||
* #include <stdio.h>
|
||||
* #include <string.h>
|
||||
* #include <ccan/base64/base64.h>
|
||||
*
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* char *base64_encoded_string;
|
||||
* int i;
|
||||
*
|
||||
* // print the base64-encoded form of the program arguments
|
||||
* for(i=1;i<argc;i++) {
|
||||
* size_t unencoded_length = strlen(argv[i]);
|
||||
* size_t encoded_length = base64_encoded_length(unencoded_length);
|
||||
* base64_encoded_string = malloc(encoded_length);
|
||||
* base64_encode(base64_encoded_string, encoded_length,
|
||||
* argv[i], unencoded_length);
|
||||
* printf("%s\n", base64_encoded_string);
|
||||
* free(base64_encoded_string);
|
||||
* }
|
||||
*
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* License: BSD-MIT
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -1,253 +0,0 @@
|
||||
/* Licensed under BSD-MIT - see LICENSE file for details */
|
||||
#include "base64.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* sixbit_to_b64 - maps a 6-bit value to the base64 alphabet
|
||||
* @param map A base 64 map (see base64_init_map)
|
||||
* @param sixbit Six-bit value to map
|
||||
* @return a base 64 character
|
||||
*/
|
||||
static char sixbit_to_b64(const base64_maps_t *maps, const uint8_t sixbit)
|
||||
{
|
||||
assert(sixbit <= 63);
|
||||
|
||||
return maps->encode_map[(unsigned char)sixbit];
|
||||
}
|
||||
|
||||
/**
|
||||
* sixbit_from_b64 - maps a base64-alphabet character to its 6-bit value
|
||||
* @param maps A base 64 maps structure (see base64_init_maps)
|
||||
* @param sixbit Six-bit value to map
|
||||
* @return a six-bit value
|
||||
*/
|
||||
static int8_t sixbit_from_b64(const base64_maps_t *maps,
|
||||
const unsigned char b64letter)
|
||||
{
|
||||
int8_t ret;
|
||||
|
||||
ret = maps->decode_map[(unsigned char)b64letter];
|
||||
if (ret == (int8_t)'\xff') {
|
||||
errno = EDOM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool base64_char_in_alphabet(const base64_maps_t *maps, const char b64char)
|
||||
{
|
||||
return (maps->decode_map[(const unsigned char)b64char] != (signed char)'\xff');
|
||||
}
|
||||
|
||||
void base64_init_maps(base64_maps_t *dest, const char src[64])
|
||||
{
|
||||
unsigned char i;
|
||||
|
||||
memcpy(dest->encode_map,src,64);
|
||||
memset(dest->decode_map,0xff,256);
|
||||
for (i=0; i<64; i++) {
|
||||
dest->decode_map[(unsigned char)src[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
size_t base64_encoded_length(size_t srclen)
|
||||
{
|
||||
return ((srclen + 2) / 3) * 4;
|
||||
}
|
||||
|
||||
void base64_encode_triplet_using_maps(const base64_maps_t *maps,
|
||||
char dest[4], const char src[3])
|
||||
{
|
||||
char a = src[0];
|
||||
char b = src[1];
|
||||
char c = src[2];
|
||||
|
||||
dest[0] = sixbit_to_b64(maps, (a & 0xfc) >> 2);
|
||||
dest[1] = sixbit_to_b64(maps, ((a & 0x3) << 4) | ((b & 0xf0) >> 4));
|
||||
dest[2] = sixbit_to_b64(maps, ((c & 0xc0) >> 6) | ((b & 0xf) << 2));
|
||||
dest[3] = sixbit_to_b64(maps, c & 0x3f);
|
||||
}
|
||||
|
||||
void base64_encode_tail_using_maps(const base64_maps_t *maps, char dest[4],
|
||||
const char *src, const size_t srclen)
|
||||
{
|
||||
char longsrc[3] = { 0 };
|
||||
|
||||
assert(srclen <= 3);
|
||||
|
||||
memcpy(longsrc, src, srclen);
|
||||
base64_encode_triplet_using_maps(maps, dest, longsrc);
|
||||
memset(dest+1+srclen, '=', 3-srclen);
|
||||
}
|
||||
|
||||
ssize_t base64_encode_using_maps(const base64_maps_t *maps,
|
||||
char *dest, const size_t destlen,
|
||||
const char *src, const size_t srclen)
|
||||
{
|
||||
size_t src_offset = 0;
|
||||
size_t dest_offset = 0;
|
||||
|
||||
if (destlen < base64_encoded_length(srclen)) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (srclen - src_offset >= 3) {
|
||||
base64_encode_triplet_using_maps(maps, &dest[dest_offset], &src[src_offset]);
|
||||
src_offset += 3;
|
||||
dest_offset += 4;
|
||||
}
|
||||
|
||||
if (src_offset < srclen) {
|
||||
base64_encode_tail_using_maps(maps, &dest[dest_offset], &src[src_offset], srclen-src_offset);
|
||||
dest_offset += 4;
|
||||
}
|
||||
|
||||
memset(&dest[dest_offset], '\0', destlen-dest_offset);
|
||||
|
||||
return dest_offset;
|
||||
}
|
||||
|
||||
size_t base64_decoded_length(size_t srclen)
|
||||
{
|
||||
return ((srclen+3)/4*3);
|
||||
}
|
||||
|
||||
ssize_t base64_decode_quartet_using_maps(const base64_maps_t *maps, char dest[3],
|
||||
const char src[4])
|
||||
{
|
||||
signed char a;
|
||||
signed char b;
|
||||
signed char c;
|
||||
signed char d;
|
||||
|
||||
a = sixbit_from_b64(maps, src[0]);
|
||||
b = sixbit_from_b64(maps, src[1]);
|
||||
c = sixbit_from_b64(maps, src[2]);
|
||||
d = sixbit_from_b64(maps, src[3]);
|
||||
|
||||
if ((a == -1) || (b == -1) || (c == -1) || (d == -1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dest[0] = (a << 2) | (b >> 4);
|
||||
dest[1] = ((b & 0xf) << 4) | (c >> 2);
|
||||
dest[2] = ((c & 0x3) << 6) | d;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ssize_t base64_decode_tail_using_maps(const base64_maps_t *maps, char dest[3],
|
||||
const char * src, const size_t srclen)
|
||||
{
|
||||
char longsrc[4];
|
||||
int quartet_result;
|
||||
size_t insize = srclen;
|
||||
|
||||
while (insize != 0 &&
|
||||
src[insize-1] == '=') { /* throw away padding symbols */
|
||||
insize--;
|
||||
}
|
||||
if (insize == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (insize == 1) {
|
||||
/* the input is malformed.... */
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
memcpy(longsrc, src, insize);
|
||||
memset(longsrc+insize, 'A', 4-insize);
|
||||
quartet_result = base64_decode_quartet_using_maps(maps, dest, longsrc);
|
||||
if (quartet_result == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return insize - 1;
|
||||
}
|
||||
|
||||
ssize_t base64_decode_using_maps(const base64_maps_t *maps,
|
||||
char *dest, const size_t destlen,
|
||||
const char *src, const size_t srclen)
|
||||
{
|
||||
ssize_t dest_offset = 0;
|
||||
ssize_t i;
|
||||
ssize_t more;
|
||||
|
||||
if (destlen < base64_decoded_length(srclen)) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(i=0; srclen - i > 4; i+=4) {
|
||||
if (base64_decode_quartet_using_maps(maps, &dest[dest_offset], &src[i]) == -1) {
|
||||
return -1;
|
||||
}
|
||||
dest_offset += 3;
|
||||
}
|
||||
|
||||
more = base64_decode_tail_using_maps(maps, &dest[dest_offset], &src[i], srclen - i);
|
||||
if (more == -1) {
|
||||
return -1;
|
||||
}
|
||||
dest_offset += more;
|
||||
|
||||
memset(&dest[dest_offset], '\0', destlen-dest_offset);
|
||||
|
||||
return dest_offset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* base64_maps_rfc4648 - pregenerated maps struct for rfc4648
|
||||
*/
|
||||
const base64_maps_t base64_maps_rfc4648 = {
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
|
||||
|
||||
"\xff\xff\xff\xff\xff" /* 0 */ \
|
||||
"\xff\xff\xff\xff\xff" /* 5 */ \
|
||||
"\xff\xff\xff\xff\xff" /* 10 */ \
|
||||
"\xff\xff\xff\xff\xff" /* 15 */ \
|
||||
"\xff\xff\xff\xff\xff" /* 20 */ \
|
||||
"\xff\xff\xff\xff\xff" /* 25 */ \
|
||||
"\xff\xff\xff\xff\xff" /* 30 */ \
|
||||
"\xff\xff\xff\xff\xff" /* 35 */ \
|
||||
"\xff\xff\xff\x3e\xff" /* 40 */ \
|
||||
"\xff\xff\x3f\x34\x35" /* 45 */ \
|
||||
"\x36\x37\x38\x39\x3a" /* 50 */ \
|
||||
"\x3b\x3c\x3d\xff\xff" /* 55 */ \
|
||||
"\xff\xff\xff\xff\xff" /* 60 */ \
|
||||
"\x00\x01\x02\x03\x04" /* 65 A */ \
|
||||
"\x05\x06\x07\x08\x09" /* 70 */ \
|
||||
"\x0a\x0b\x0c\x0d\x0e" /* 75 */ \
|
||||
"\x0f\x10\x11\x12\x13" /* 80 */ \
|
||||
"\x14\x15\x16\x17\x18" /* 85 */ \
|
||||
"\x19\xff\xff\xff\xff" /* 90 */ \
|
||||
"\xff\xff\x1a\x1b\x1c" /* 95 */ \
|
||||
"\x1d\x1e\x1f\x20\x21" /* 100 */ \
|
||||
"\x22\x23\x24\x25\x26" /* 105 */ \
|
||||
"\x27\x28\x29\x2a\x2b" /* 110 */ \
|
||||
"\x2c\x2d\x2e\x2f\x30" /* 115 */ \
|
||||
"\x31\x32\x33\xff\xff" /* 120 */ \
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 125 */ \
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 155 */ \
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 185 */ \
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 215 */ \
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 245 */
|
||||
};
|
||||
@ -1,241 +0,0 @@
|
||||
/* Licensed under BSD-MIT - see LICENSE file for details */
|
||||
#ifndef CCAN_BASE64_H
|
||||
#define CCAN_BASE64_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/**
|
||||
* base64_maps_t - structure to hold maps for encode/decode
|
||||
*/
|
||||
typedef struct {
|
||||
char encode_map[64];
|
||||
signed char decode_map[256];
|
||||
} base64_maps_t;
|
||||
|
||||
/**
|
||||
* base64_encoded_length - Calculate encode buffer length
|
||||
* @param srclen the size of the data to be encoded
|
||||
* @note add 1 to this to get null-termination
|
||||
* @return Buffer length required for encode
|
||||
*/
|
||||
size_t base64_encoded_length(size_t srclen);
|
||||
|
||||
/**
|
||||
* base64_decoded_length - Calculate decode buffer length
|
||||
* @param srclen Length of the data to be decoded
|
||||
* @note This does not return the size of the decoded data! see base64_decode
|
||||
* @return Minimum buffer length for safe decode
|
||||
*/
|
||||
size_t base64_decoded_length(size_t srclen);
|
||||
|
||||
/**
|
||||
* base64_init_maps - populate a base64_maps_t based on a supplied alphabet
|
||||
* @param dest A base64 maps object
|
||||
* @param src Alphabet to populate the maps from (e.g. base64_alphabet_rfc4648)
|
||||
*/
|
||||
void base64_init_maps(base64_maps_t *dest, const char src[64]);
|
||||
|
||||
|
||||
/**
|
||||
* base64_encode_triplet_using_maps - encode 3 bytes into base64 using a specific alphabet
|
||||
* @param maps Maps to use for encoding (see base64_init_maps)
|
||||
* @param dest Buffer containing 3 bytes
|
||||
* @param src Buffer containing 4 characters
|
||||
*/
|
||||
void base64_encode_triplet_using_maps(const base64_maps_t *maps,
|
||||
char dest[4], const char src[3]);
|
||||
|
||||
/**
|
||||
* base64_encode_tail_using_maps - encode the final bytes of a source using a specific alphabet
|
||||
* @param maps Maps to use for encoding (see base64_init_maps)
|
||||
* @param dest Buffer containing 4 bytes
|
||||
* @param src Buffer containing srclen bytes
|
||||
* @param srclen Number of bytes (<= 3) to encode in src
|
||||
*/
|
||||
void base64_encode_tail_using_maps(const base64_maps_t *maps, char dest[4],
|
||||
const char *src, size_t srclen);
|
||||
|
||||
/**
|
||||
* base64_encode_using_maps - encode a buffer into base64 using a specific alphabet
|
||||
* @param maps Maps to use for encoding (see base64_init_maps)
|
||||
* @param dest Buffer to encode into
|
||||
* @param destlen Length of dest
|
||||
* @param src Buffer to encode
|
||||
* @param srclen Length of the data to encode
|
||||
* @return Number of encoded bytes set in dest. -1 on error (and errno set)
|
||||
* @note dest will be nul-padded to destlen (past any required padding)
|
||||
* @note sets errno = EOVERFLOW if destlen is too small
|
||||
*/
|
||||
ssize_t base64_encode_using_maps(const base64_maps_t *maps,
|
||||
char *dest, size_t destlen,
|
||||
const char *src, size_t srclen);
|
||||
|
||||
/*
|
||||
* base64_char_in_alphabet - returns true if character can be part of an encoded string
|
||||
* @param maps A base64 maps object (see base64_init_maps)
|
||||
* @param b64char Character to check
|
||||
*/
|
||||
bool base64_char_in_alphabet(const base64_maps_t *maps, char b64char);
|
||||
|
||||
/**
|
||||
* base64_decode_using_maps - decode a base64-encoded string using a specific alphabet
|
||||
* @param maps A base64 maps object (see base64_init_maps)
|
||||
* @param dest Buffer to decode into
|
||||
* @param destlen length of dest
|
||||
* @param src the buffer to decode
|
||||
* @param srclen the length of the data to decode
|
||||
* @return Number of decoded bytes set in dest. -1 on error (and errno set)
|
||||
* @note dest will be nul-padded to destlen
|
||||
* @note sets errno = EOVERFLOW if destlen is too small
|
||||
* @note sets errno = EDOM if src contains invalid characters
|
||||
*/
|
||||
ssize_t base64_decode_using_maps(const base64_maps_t *maps,
|
||||
char *dest, size_t destlen,
|
||||
const char *src, size_t srclen);
|
||||
|
||||
/**
|
||||
* base64_decode_quartet_using_maps - decode 4 bytes from base64 using a specific alphabet
|
||||
* @param maps A base64 maps object (see base64_init_maps)
|
||||
* @param dest Buffer containing 3 bytes
|
||||
* @param src Buffer containing 4 bytes
|
||||
* @return Number of decoded bytes set in dest. -1 on error (and errno set)
|
||||
* @note sets errno = EDOM if src contains invalid characters
|
||||
*/
|
||||
ssize_t base64_decode_quartet_using_maps(const base64_maps_t *maps,
|
||||
char dest[3], const char src[4]);
|
||||
|
||||
/**
|
||||
* base64_decode_tail_using_maps - decode the final bytes of a base64 string using a specific alphabet
|
||||
* @param maps A base64 maps object (see base64_init_maps)
|
||||
* @param dest Buffer containing 3 bytes
|
||||
* @param src Buffer containing 4 bytes - padded with '=' as required
|
||||
* @param srclen Number of bytes to decode in src
|
||||
* @return Number of decoded bytes set in dest. -1 on error (and errno set)
|
||||
* @note sets errno = EDOM if src contains invalid characters
|
||||
* @note sets errno = EINVAL if src is an invalid base64 tail
|
||||
*/
|
||||
ssize_t base64_decode_tail_using_maps(const base64_maps_t *maps, char dest[3],
|
||||
const char *src, size_t srclen);
|
||||
|
||||
|
||||
/* the rfc4648 functions: */
|
||||
|
||||
extern const base64_maps_t base64_maps_rfc4648;
|
||||
|
||||
/**
|
||||
* base64_encode - Encode a buffer into base64 according to rfc4648
|
||||
* @param dest Buffer to encode into
|
||||
* @param destlen Length of the destination buffer
|
||||
* @param src Buffer to encode
|
||||
* @param srclen Length of the data to encode
|
||||
* @return Number of encoded bytes set in dest. -1 on error (and errno set)
|
||||
* @note dest will be nul-padded to destlen (past any required padding)
|
||||
* @note sets errno = EOVERFLOW if destlen is too small
|
||||
*
|
||||
* This function encodes src according to http://tools.ietf.org/html/rfc4648
|
||||
*
|
||||
* Example:
|
||||
* size_t encoded_length;
|
||||
* char dest[100];
|
||||
* const char *src = "This string gets encoded";
|
||||
* encoded_length = base64_encode(dest, sizeof(dest), src, strlen(src));
|
||||
* printf("Returned data of length %zd @%p\n", encoded_length, &dest);
|
||||
*/
|
||||
static inline
|
||||
ssize_t base64_encode(char *dest, size_t destlen,
|
||||
const char *src, size_t srclen)
|
||||
{
|
||||
return base64_encode_using_maps(&base64_maps_rfc4648,
|
||||
dest, destlen, src, srclen);
|
||||
}
|
||||
|
||||
/**
|
||||
* base64_encode_triplet - encode 3 bytes into base64 according to rfc4648
|
||||
* @param dest Buffer containing 4 bytes
|
||||
* @param src Buffer containing 3 bytes
|
||||
*/
|
||||
static inline
|
||||
void base64_encode_triplet(char dest[4], const char src[3])
|
||||
{
|
||||
base64_encode_triplet_using_maps(&base64_maps_rfc4648, dest, src);
|
||||
}
|
||||
|
||||
/**
|
||||
* base64_encode_tail - encode the final bytes of a source according to rfc4648
|
||||
* @param dest Buffer containing 4 bytes
|
||||
* @param src Buffer containing srclen bytes
|
||||
* @param srclen Number of bytes (<= 3) to encode in src
|
||||
*/
|
||||
static inline
|
||||
void base64_encode_tail(char dest[4], const char *src, size_t srclen)
|
||||
{
|
||||
base64_encode_tail_using_maps(&base64_maps_rfc4648, dest, src, srclen);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* base64_decode - decode An rfc4648 base64-encoded string
|
||||
* @param dest Buffer to decode into
|
||||
* @param destlen Length of the destination buffer
|
||||
* @param src Buffer to decode
|
||||
* @param srclen Length of the data to decode
|
||||
* @return Number of decoded bytes set in dest. -1 on error (and errno set)
|
||||
* @note dest will be nul-padded to destlen
|
||||
* @note sets errno = EOVERFLOW if destlen is too small
|
||||
* @note sets errno = EDOM if src contains invalid characters
|
||||
*
|
||||
* This function decodes the buffer according to
|
||||
* http://tools.ietf.org/html/rfc4648
|
||||
*
|
||||
* Example:
|
||||
* size_t decoded_length;
|
||||
* char ret[100];
|
||||
* const char *src = "Zm9vYmFyYmF6";
|
||||
* decoded_length = base64_decode(ret, sizeof(ret), src, strlen(src));
|
||||
* printf("Returned data of length %zd @%p\n", decoded_length, &ret);
|
||||
*/
|
||||
static inline
|
||||
ssize_t base64_decode(char *dest, size_t destlen,
|
||||
const char *src, size_t srclen)
|
||||
{
|
||||
return base64_decode_using_maps(&base64_maps_rfc4648,
|
||||
dest, destlen, src, srclen);
|
||||
}
|
||||
|
||||
/**
|
||||
* base64_decode_quartet - decode the first 4 characters in src into dest
|
||||
* @param dest Buffer containing 3 bytes
|
||||
* @param src Buffer containing 4 characters
|
||||
* @return Number of decoded bytes set in dest. -1 on error (and errno set)
|
||||
* @note sets errno = EDOM if src contains invalid characters
|
||||
*/
|
||||
static inline
|
||||
ssize_t base64_decode_quartet(char dest[3], const char src[4])
|
||||
{
|
||||
return base64_decode_quartet_using_maps(&base64_maps_rfc4648,
|
||||
dest, src);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief decode the final bytes of a base64 string from src into dest
|
||||
* @param dest Buffer containing 3 bytes
|
||||
* @param src Buffer containing 4 bytes - padded with '=' as required
|
||||
* @param srclen Number of bytes to decode in src
|
||||
* @return Number of decoded bytes set in dest. -1 on error (and errno set)
|
||||
* @note sets errno = EDOM if src contains invalid characters
|
||||
* @note sets errno = EINVAL if src is an invalid base64 tail
|
||||
*/
|
||||
static inline
|
||||
ssize_t base64_decode_tail(char dest[3], const char *src, size_t srclen)
|
||||
{
|
||||
return base64_decode_tail_using_maps(&base64_maps_rfc4648,
|
||||
dest, src, srclen);
|
||||
}
|
||||
|
||||
/* end rfc4648 functions */
|
||||
|
||||
|
||||
|
||||
#endif /* CCAN_BASE64_H */
|
||||
@ -1,96 +0,0 @@
|
||||
#ifndef _BASE64_MORETAP_H
|
||||
#define _BASE64_MORETAP_H
|
||||
|
||||
#include <ccan/str/str.h>
|
||||
|
||||
/**
|
||||
* is_str - OK if strings are equal
|
||||
* @e1: expression for the variable string
|
||||
* @e2: expression for the expected string
|
||||
*
|
||||
* If the strings are equal, the test passes.
|
||||
*
|
||||
* Example:
|
||||
* is_str(give_me_a_fred(),"fred");
|
||||
*/
|
||||
static void _is_str(char *got,const char *expected, const char *got_string, const char *expected_string, const char *func, const char *file, int line) {
|
||||
if (streq(expected,got)) {
|
||||
_gen_result(1, func, file, line,"%s eq %s",
|
||||
got_string,expected_string);
|
||||
} else {
|
||||
_gen_result(0, func, file, line,"%s eq %s",
|
||||
got_string,expected_string);
|
||||
diag("Expected: %s",expected);
|
||||
diag(" Got: %s",got);
|
||||
}
|
||||
}
|
||||
# define is_str(got,expected) _is_str(got,expected,#got,#expected,__func__, __FILE__, __LINE__)
|
||||
|
||||
|
||||
/**
|
||||
* is_int - OK if arguments are equal when cast to integers
|
||||
* @e1: expression for the number
|
||||
* @e2: expression for the expected number
|
||||
*
|
||||
* If the numbers are equal, the test passes.
|
||||
*
|
||||
* Example:
|
||||
* is_int(give_me_17(),17);
|
||||
*/
|
||||
# define is_int(e1,e2 ...) \
|
||||
(((int)e1)==((int)e2) ? \
|
||||
_gen_result(1, __func__, __FILE__, __LINE__,"%s == %s",#e1,#e2) : \
|
||||
(_gen_result(0, __func__, __FILE__, __LINE__,"%s == %s",#e1,#e2)) || (diag("Expected: %d",e2),diag(" Got: %d",e1),0)) /* diag is void; note commas. */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* is_mem - OK if arguments are identical up to length @e3
|
||||
* @e1: expression for the buffer
|
||||
* @e2: expression for the expected buffer
|
||||
* @e2: length to compare in buffers
|
||||
*
|
||||
* If the buffers are equal up to @e2, the test passes.
|
||||
*
|
||||
* Example:
|
||||
* is_mem(give_me_foo(),"foo",3);
|
||||
*/
|
||||
static void _is_mem(const char *got, const char *expected, const size_t len,
|
||||
const char *got_string, const char *expected_string, const char *len_string,
|
||||
const char *func, const char *file, int line) {
|
||||
size_t offset = 0;
|
||||
|
||||
for (offset=0; offset<len; offset++) {
|
||||
if (got[offset] != expected[offset]) {
|
||||
_gen_result(0, func, file, line,"%s eq %s",got_string,expected_string);
|
||||
/* diag("Expected: %s",e2); */
|
||||
/* diag(" Got: %s",e1); */
|
||||
diag("Buffers differ at offset %zd (got=0x%02x expected=0x%02x)",
|
||||
offset,got[offset],expected[offset]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_gen_result(1, __func__, __FILE__, __LINE__,"%s eq %s",
|
||||
expected_string,got_string);
|
||||
}
|
||||
# define is_mem(got,expected,len) \
|
||||
_is_mem(got,expected,len,#got,#expected,#len,__func__, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* is_size_t - OK if arguments are equal when cast to size_t
|
||||
* @e1: expression for the number
|
||||
* @e2: expression for the expected number
|
||||
*
|
||||
* If the numbers are equal, the test passes.
|
||||
*
|
||||
* Example:
|
||||
* is_size_t(give_me_17(),17);
|
||||
*/
|
||||
# define is_size_t(e1,e2 ...) \
|
||||
((size_t)(e1)==((size_t)e2) ? \
|
||||
_gen_result(1, __func__, __FILE__, __LINE__,"%s == %s",#e1,#e2) : \
|
||||
(_gen_result(0, __func__, __FILE__, __LINE__, \
|
||||
"%s == %s",#e1,#e2)) || (diag("Expected: %zd",(size_t)e2),diag(" Got: %zd",(size_t)e1),0)) /* diag is void; note commas. */
|
||||
|
||||
#endif
|
||||
@ -1,359 +0,0 @@
|
||||
/* Start of run.c test */
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ccan/base64/base64.h>
|
||||
#include <ccan/tap/tap.h>
|
||||
|
||||
#include <ccan/base64/base64.c>
|
||||
#include "moretap.h"
|
||||
|
||||
static void * xmalloc(size_t size);
|
||||
|
||||
/* not defined in terms of test_encode_using_maps so we cross
|
||||
appropriate paths in library */
|
||||
#define test_encode(src,srclen,expected) \
|
||||
do { \
|
||||
size_t destlen; \
|
||||
char * dest; \
|
||||
destlen = base64_encoded_length(srclen); \
|
||||
destlen++; /* null termination */ \
|
||||
dest = xmalloc(destlen); \
|
||||
ok1(base64_encode(dest,destlen,src,srclen) != -1); \
|
||||
is_str(dest,expected); \
|
||||
free(dest); \
|
||||
} while (0)
|
||||
|
||||
#define test_encode_using_alphabet(alphastring,src,srclen,expected) \
|
||||
do { \
|
||||
size_t destlen; \
|
||||
char * dest; \
|
||||
base64_maps_t maps; \
|
||||
base64_init_maps(&maps,alphastring); \
|
||||
destlen = base64_encoded_length(srclen); \
|
||||
destlen++; /* null termination */ \
|
||||
dest = xmalloc(destlen); \
|
||||
ok1(base64_encode_using_maps(&maps,dest,destlen,src,srclen) != -1); \
|
||||
is_str(dest,expected); \
|
||||
free(dest); \
|
||||
} while (0)
|
||||
|
||||
/* not defined in terms of test_decode_using_alphabet so we cross
|
||||
appropriate paths in library */
|
||||
#define test_decode(src,srclen,expected,expectedlen) \
|
||||
do { \
|
||||
size_t destlen; \
|
||||
size_t bytes_used; \
|
||||
char * dest; \
|
||||
destlen = base64_decoded_length(srclen); \
|
||||
dest = xmalloc(destlen); \
|
||||
ok1((bytes_used = base64_decode(dest,destlen,src,srclen)) != -1); \
|
||||
is_size_t(bytes_used,expectedlen); \
|
||||
is_mem(dest,expected,bytes_used); \
|
||||
free(dest); \
|
||||
} while (0)
|
||||
|
||||
#define test_decode_using_alphabet(alphastring,src,srclen,expected,expectedlen) \
|
||||
do { \
|
||||
size_t destlen; \
|
||||
size_t bytes_used; \
|
||||
char * dest; \
|
||||
base64_maps_t maps; \
|
||||
\
|
||||
base64_init_maps(&maps,alphastring); \
|
||||
destlen = base64_decoded_length(srclen); \
|
||||
dest = xmalloc(destlen); \
|
||||
ok1((bytes_used = base64_decode_using_maps(&maps,dest,destlen,src,srclen)) != -1); \
|
||||
is_size_t(bytes_used,expectedlen); \
|
||||
is_mem(dest,expected,bytes_used); \
|
||||
free(dest); \
|
||||
} while (0)
|
||||
|
||||
#define check_bad_range_decode(stuff_to_test,stufflen) \
|
||||
do { \
|
||||
char dest[10]; \
|
||||
errno = 0; \
|
||||
is_size_t(base64_decode(dest,sizeof(dest),stuff_to_test,(size_t)stufflen), \
|
||||
(size_t)-1); \
|
||||
is_int(errno,EDOM); \
|
||||
} while (0)
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
plan_tests(131);
|
||||
|
||||
is_size_t(base64_encoded_length(0),(size_t)0);
|
||||
is_size_t(base64_encoded_length(1),(size_t)4);
|
||||
is_size_t(base64_encoded_length(2),(size_t)4);
|
||||
is_size_t(base64_encoded_length(3),(size_t)4);
|
||||
is_size_t(base64_encoded_length(512),(size_t)684);
|
||||
|
||||
/* straight from page 11 of http://tools.ietf.org/html/rfc4648 */
|
||||
test_encode("",0,"");
|
||||
test_encode("f",1,"Zg==");
|
||||
test_encode("fo",2,"Zm8=");
|
||||
|
||||
test_encode("foo",3,"Zm9v");
|
||||
test_encode("foob",4,"Zm9vYg==");
|
||||
test_encode("fooba",5,"Zm9vYmE=");
|
||||
test_encode("foobar",6,"Zm9vYmFy");
|
||||
|
||||
/* a few more */
|
||||
test_encode("foobarb",7,"Zm9vYmFyYg==");
|
||||
test_encode("foobarba",8,"Zm9vYmFyYmE=");
|
||||
test_encode("foobarbaz",9,"Zm9vYmFyYmF6");
|
||||
|
||||
test_encode("foobart",7,"Zm9vYmFydA==");
|
||||
|
||||
test_encode("abcdefghijklmnopqrstuvwxyz",26,"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=");
|
||||
test_encode("\x05\x05\x01\x00\x07",5,"BQUBAAc=");
|
||||
|
||||
test_encode("FOO",3,"Rk9P");
|
||||
test_encode("Z",1,"Wg==");
|
||||
|
||||
/* decode testing */
|
||||
|
||||
test_decode("",0,"",0);
|
||||
test_decode("Zg==",4,"f",1);
|
||||
test_decode("Zm8=",4,"fo",2);
|
||||
test_decode("Zm9v",4,"foo",3);
|
||||
test_decode("Zm9vYg==",8,"foob",4);
|
||||
test_decode("Zm9vYmE=",8,"fooba",5);
|
||||
test_decode("Zm9vYmFy",8,"foobar",6);
|
||||
test_decode("Zm9vYmFyYg==",12,"foobarb",7);
|
||||
test_decode("Zm9vYmFyYmE=",12,"foobarba",8);
|
||||
test_decode("Zm9vYmFyYmF6",12,"foobarbaz",9);
|
||||
|
||||
test_decode("Rk9P",4,"FOO",3);
|
||||
|
||||
test_decode("Wg==",4,"Z",1);
|
||||
test_decode("AA==",4,"\0",1);
|
||||
test_decode("AAA=",4,"\0\0",2);
|
||||
|
||||
{
|
||||
const char *binary = "\x01\x00\x03";
|
||||
const size_t binarylen = 3;
|
||||
|
||||
char * decoded;
|
||||
char * encoded;
|
||||
size_t encoded_len;
|
||||
size_t decoded_len;
|
||||
size_t decoded_space_required;
|
||||
|
||||
size_t encoded_space_required = base64_encoded_length(binarylen);
|
||||
encoded_space_required++; /* null termination */
|
||||
encoded = xmalloc(encoded_space_required);
|
||||
encoded_len = base64_encode(encoded,encoded_space_required,binary,binarylen);
|
||||
is_mem(encoded,"AQAD",encoded_len);
|
||||
|
||||
decoded_space_required = base64_decoded_length(encoded_len);
|
||||
decoded = xmalloc(decoded_space_required);
|
||||
decoded_len = base64_decode(decoded,decoded_space_required,encoded,encoded_len);
|
||||
is_size_t(decoded_len,binarylen);
|
||||
is_mem(binary,decoded,decoded_len);
|
||||
}
|
||||
|
||||
/* some expected encode failures: */
|
||||
{
|
||||
size_t destlen = 1;
|
||||
char dest[destlen];
|
||||
errno = 0;
|
||||
is_size_t(base64_encode(dest,destlen,"A",1),(size_t)-1);
|
||||
is_int(errno,EOVERFLOW);
|
||||
}
|
||||
|
||||
/* some expected decode failures: */
|
||||
{
|
||||
base64_maps_t maps;
|
||||
const char * src = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
base64_init_maps(&maps,src);
|
||||
|
||||
is_int(sixbit_from_b64(&maps,'\xfe'),(signed char)-1);
|
||||
is_int(errno,EDOM);
|
||||
}
|
||||
{
|
||||
size_t destlen = 10;
|
||||
char dest[destlen];
|
||||
errno = 0;
|
||||
is_size_t(base64_decode(dest,destlen,"A",1),(size_t)-1);
|
||||
is_int(errno,EINVAL);
|
||||
}
|
||||
{
|
||||
size_t destlen = 1;
|
||||
char dest[destlen];
|
||||
errno = 0;
|
||||
is_size_t(base64_decode(dest,destlen,"A",1),(size_t)-1);
|
||||
is_int(errno,EOVERFLOW);
|
||||
}
|
||||
{
|
||||
/* (char)1 is not a valid base64 character: */
|
||||
check_bad_range_decode("A\x01",2);
|
||||
/* (char)255 is not a valid base64 character: (char is signed on most platforms, so this is actually < 0 */
|
||||
check_bad_range_decode("\xff""A",2);
|
||||
check_bad_range_decode("A\xff",2);
|
||||
check_bad_range_decode("AA\xff",3);
|
||||
check_bad_range_decode("A\xff""A",3);
|
||||
check_bad_range_decode("\xff""AA",3);
|
||||
check_bad_range_decode("AAA\xff",4);
|
||||
check_bad_range_decode("\xff\x41\x41\x41\x41",5);
|
||||
check_bad_range_decode("A\xff\x41\x41\x41\x41",6);
|
||||
check_bad_range_decode("AA\xff\x41\x41\x41\x41",7);
|
||||
check_bad_range_decode("AAA\xff\x41\x41\x41\x41",8);
|
||||
}
|
||||
/* trigger some failures in the sixbit-to-b64 encoder: */
|
||||
/* this function now aborts rather than returning -1/setting errno */
|
||||
/* { */
|
||||
/* is_int(sixbit_to_b64(base64_maps_rfc4648,'\x70'),(char)-1); */
|
||||
/* is_int(sixbit_to_b64(base64_maps_rfc4648,'\xff'),(char)-1); */
|
||||
/* } */
|
||||
/* following tests all of the mapping from b64 chars to 6-bit values: */
|
||||
test_decode("//+FwHRSRIsFU2IhAEGD+AMPhOA=",28,"\xff\xff\x85\xc0\x74\x52\x44\x8b\x05\x53\x62\x21\x00\x41\x83\xf8\x03\x0f\x84\xe0",20);
|
||||
test_encode("\xff\xff\x85\xc0\x74\x52\x44\x8b\x05\x53\x62\x21\x00\x41\x83\xf8\x03\x0f\x84\xe0",20,"//+FwHRSRIsFU2IhAEGD+AMPhOA=");
|
||||
|
||||
|
||||
/* check the null-padding stuff */
|
||||
{
|
||||
size_t destlen = 8;
|
||||
char dest[destlen];
|
||||
memset(dest,'\1',sizeof(dest));
|
||||
is_size_t(base64_encode(dest,destlen,"A",1),(size_t)4);
|
||||
is_mem(&dest[4],"\0\0\0\0",4);
|
||||
}
|
||||
{
|
||||
size_t destlen = 3;
|
||||
char dest[destlen];
|
||||
memset(dest,'\1',sizeof(dest));
|
||||
is_size_t(base64_decode(dest,destlen,"Wg==",4), 1);
|
||||
is_mem(&dest[1],"\0",2);
|
||||
}
|
||||
|
||||
/* test encoding using different alphabets */
|
||||
{
|
||||
char alphabet_fs_safe[64];
|
||||
memcpy(alphabet_fs_safe,base64_maps_rfc4648.encode_map,sizeof(alphabet_fs_safe));
|
||||
alphabet_fs_safe[62] = '-';
|
||||
alphabet_fs_safe[63] = '_';
|
||||
test_encode_using_alphabet(alphabet_fs_safe,"\xff\xff\x85\xc0\x74\x52\x44\x8b\x05\x53\x62\x21\x00\x41\x83\xf8\x03\x0f\x84\xe0",20,"__-FwHRSRIsFU2IhAEGD-AMPhOA=");
|
||||
}
|
||||
|
||||
/* test decoding using different alphabets */
|
||||
{
|
||||
char alphabet_fs_safe[64];
|
||||
#define src "__-FwHRSRIsFU2IhAEGD-AMPhOA="
|
||||
#define expected "\xff\xff\x85\xc0\x74\x52\x44\x8b\x05\x53\x62\x21\x00\x41\x83\xf8\x03\x0f\x84\xe0"
|
||||
|
||||
memcpy(alphabet_fs_safe,base64_maps_rfc4648.encode_map,sizeof(alphabet_fs_safe));
|
||||
alphabet_fs_safe[62] = '-';
|
||||
alphabet_fs_safe[63] = '_';
|
||||
|
||||
test_decode_using_alphabet(alphabet_fs_safe,src,strlen(src),expected,20);
|
||||
#undef src
|
||||
#undef expected
|
||||
}
|
||||
|
||||
/* explicitly test the non-maps encode_triplet and
|
||||
encode_tail functions */
|
||||
{
|
||||
size_t destlen = 4;
|
||||
char dest[destlen];
|
||||
const char *src = "AB\04";
|
||||
memset(dest,'\1',sizeof(dest));
|
||||
base64_encode_triplet(dest,src);
|
||||
is_mem(dest,"QUIE",sizeof(dest));
|
||||
}
|
||||
{
|
||||
size_t destlen = 4;
|
||||
char dest[destlen];
|
||||
const char *src = "A";
|
||||
memset(dest,'\1',sizeof(dest));
|
||||
base64_encode_tail(dest,src,strlen(src));
|
||||
is_mem(dest,"QQ==",sizeof(dest));
|
||||
}
|
||||
|
||||
/* test the alphabet inversion */
|
||||
{
|
||||
base64_maps_t dest;
|
||||
const char expected_inverse[] =
|
||||
"\xff\xff\xff\xff\xff" /* 0 */
|
||||
"\xff\xff\xff\xff\xff" /* 5 */
|
||||
"\xff\xff\xff\xff\xff" /* 10 */
|
||||
"\xff\xff\xff\xff\xff" /* 15 */
|
||||
"\xff\xff\xff\xff\xff" /* 20 */
|
||||
"\xff\xff\xff\xff\xff" /* 25 */
|
||||
"\xff\xff\xff\xff\xff" /* 30 */
|
||||
"\xff\xff\xff\xff\xff" /* 35 */
|
||||
"\xff\xff\xff\x3e\xff" /* 40 */
|
||||
"\xff\xff\x3f\x34\x35" /* 45 - */
|
||||
"\x36\x37\x38\x39\x3a" /* 50 */
|
||||
"\x3b\x3c\x3d\xff\xff" /* 55 */
|
||||
"\xff\xff\xff\xff\xff" /* 60 */
|
||||
"\x00\x01\x02\x03\x04" /* 65 A */
|
||||
"\x05\x06\x07\x08\x09" /* 70 */
|
||||
"\x0a\x0b\x0c\x0d\x0e" /* 75 */
|
||||
"\x0f\x10\x11\x12\x13" /* 80 */
|
||||
"\x14\x15\x16\x17\x18" /* 85 */
|
||||
"\x19\xff\xff\xff\xff" /* 90 */
|
||||
"\xff\xff\x1a\x1b\x1c" /* 95 _ */
|
||||
"\x1d\x1e\x1f\x20\x21" /* 100 */
|
||||
"\x22\x23\x24\x25\x26" /* 105 */
|
||||
"\x27\x28\x29\x2a\x2b" /* 110 */
|
||||
"\x2c\x2d\x2e\x2f\x30" /* 115 */
|
||||
"\x31\x32\x33\xff\xff" /* 120 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 125 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 155 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 185 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 215 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 245 */
|
||||
;
|
||||
const char * src = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
base64_init_maps(&dest, src);
|
||||
is_mem((const char *)dest.decode_map, expected_inverse, 256);
|
||||
ok1(base64_char_in_alphabet(&dest,'A'));
|
||||
ok1(!base64_char_in_alphabet(&dest,'\n'));
|
||||
}
|
||||
|
||||
/* explicitly test the non-alpha decode_tail and decode_quartet */
|
||||
{
|
||||
char dest[4];
|
||||
const char *src = "QQ==";
|
||||
const char * expected = "A";
|
||||
memset(dest, '%', sizeof(dest));
|
||||
base64_decode_tail(dest,src,4);
|
||||
is_mem(dest, expected, 1);
|
||||
}
|
||||
{
|
||||
char dest[4];
|
||||
const char *src = "Zm9v";
|
||||
const char * expected = "foo";
|
||||
memset(dest, '%', sizeof(dest));
|
||||
base64_decode_quartet(dest,src);
|
||||
is_mem(dest, expected, 1);
|
||||
}
|
||||
|
||||
exit(exit_status());
|
||||
}
|
||||
|
||||
static void * xmalloc(size_t size)
|
||||
{
|
||||
char * ret;
|
||||
ret = malloc(size);
|
||||
if (ret == NULL) {
|
||||
perror("malloc");
|
||||
abort();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* End of run.c test */
|
||||
@ -9,54 +9,54 @@
|
||||
#define BIT_ALIGN_DOWN(n) ((n) & ~(BITMAP_WORD_BITS - 1))
|
||||
#define BIT_ALIGN_UP(n) BIT_ALIGN_DOWN((n) + BITMAP_WORD_BITS - 1)
|
||||
|
||||
void bitmap_zero_range(bitmap *b, unsigned long n, unsigned long m)
|
||||
void bitmap_zero_range(bitmap *bitmap, unsigned long n, unsigned long m)
|
||||
{
|
||||
unsigned long an = BIT_ALIGN_UP(n);
|
||||
unsigned long am = BIT_ALIGN_DOWN(m);
|
||||
bitmap_word headmask = BITMAP_WORD_1 >> (n % BITMAP_WORD_BITS);
|
||||
bitmap_word tailmask = ~(BITMAP_WORD_1 >> (m % BITMAP_WORD_BITS));
|
||||
bitmap_word headmask = -1ULL >> (n % BITMAP_WORD_BITS);
|
||||
bitmap_word tailmask = ~(-1ULL >> (m % BITMAP_WORD_BITS));
|
||||
|
||||
assert(m >= n);
|
||||
|
||||
if (am < an) {
|
||||
BITMAP_WORD(b, n) &= ~bitmap_bswap(headmask & tailmask);
|
||||
BITMAP_WORD(bitmap, n) &= ~bitmap_bswap(headmask & tailmask);
|
||||
return;
|
||||
}
|
||||
|
||||
if (an > n)
|
||||
BITMAP_WORD(b, n) &= ~bitmap_bswap(headmask);
|
||||
BITMAP_WORD(bitmap, n) &= ~bitmap_bswap(headmask);
|
||||
|
||||
if (am > an)
|
||||
memset(&BITMAP_WORD(b, an), 0,
|
||||
memset(&BITMAP_WORD(bitmap, an), 0,
|
||||
(am - an) / BITMAP_WORD_BITS * sizeof(bitmap_word));
|
||||
|
||||
if (m > am)
|
||||
BITMAP_WORD(b, m) &= ~bitmap_bswap(tailmask);
|
||||
BITMAP_WORD(bitmap, m) &= ~bitmap_bswap(tailmask);
|
||||
}
|
||||
|
||||
void bitmap_fill_range(bitmap *b, unsigned long n, unsigned long m)
|
||||
void bitmap_fill_range(bitmap *bitmap, unsigned long n, unsigned long m)
|
||||
{
|
||||
unsigned long an = BIT_ALIGN_UP(n);
|
||||
unsigned long am = BIT_ALIGN_DOWN(m);
|
||||
bitmap_word headmask = BITMAP_WORD_1 >> (n % BITMAP_WORD_BITS);
|
||||
bitmap_word tailmask = ~(BITMAP_WORD_1 >> (m % BITMAP_WORD_BITS));
|
||||
bitmap_word headmask = -1ULL >> (n % BITMAP_WORD_BITS);
|
||||
bitmap_word tailmask = ~(-1ULL >> (m % BITMAP_WORD_BITS));
|
||||
|
||||
assert(m >= n);
|
||||
|
||||
if (am < an) {
|
||||
BITMAP_WORD(b, n) |= bitmap_bswap(headmask & tailmask);
|
||||
BITMAP_WORD(bitmap, n) |= bitmap_bswap(headmask & tailmask);
|
||||
return;
|
||||
}
|
||||
|
||||
if (an > n)
|
||||
BITMAP_WORD(b, n) |= bitmap_bswap(headmask);
|
||||
BITMAP_WORD(bitmap, n) |= bitmap_bswap(headmask);
|
||||
|
||||
if (am > an)
|
||||
memset(&BITMAP_WORD(b, an), 0xff,
|
||||
memset(&BITMAP_WORD(bitmap, an), 0xff,
|
||||
(am - an) / BITMAP_WORD_BITS * sizeof(bitmap_word));
|
||||
|
||||
if (m > am)
|
||||
BITMAP_WORD(b, m) |= bitmap_bswap(tailmask);
|
||||
BITMAP_WORD(bitmap, m) |= bitmap_bswap(tailmask);
|
||||
}
|
||||
|
||||
static int bitmap_clz(bitmap_word w)
|
||||
@ -65,7 +65,7 @@ static int bitmap_clz(bitmap_word w)
|
||||
return __builtin_clzl(w);
|
||||
#else
|
||||
int lz = 0;
|
||||
bitmap_word mask = (bitmap_word)1 << (BITMAP_WORD_BITS - 1);
|
||||
bitmap_word mask = 1UL << (BITMAP_WORD_BITS - 1);
|
||||
|
||||
while (!(w & mask)) {
|
||||
lz++;
|
||||
@ -76,18 +76,18 @@ static int bitmap_clz(bitmap_word w)
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long bitmap_ffs(const bitmap *b,
|
||||
unsigned long bitmap_ffs(const bitmap *bitmap,
|
||||
unsigned long n, unsigned long m)
|
||||
{
|
||||
unsigned long an = BIT_ALIGN_UP(n);
|
||||
unsigned long am = BIT_ALIGN_DOWN(m);
|
||||
bitmap_word headmask = BITMAP_WORD_1 >> (n % BITMAP_WORD_BITS);
|
||||
bitmap_word tailmask = ~(BITMAP_WORD_1 >> (m % BITMAP_WORD_BITS));
|
||||
bitmap_word headmask = -1ULL >> (n % BITMAP_WORD_BITS);
|
||||
bitmap_word tailmask = ~(-1ULL >> (m % BITMAP_WORD_BITS));
|
||||
|
||||
assert(m >= n);
|
||||
|
||||
if (am < an) {
|
||||
bitmap_word w = bitmap_bswap(BITMAP_WORD(b, n));
|
||||
bitmap_word w = bitmap_bswap(BITMAP_WORD(bitmap, n));
|
||||
|
||||
w &= (headmask & tailmask);
|
||||
|
||||
@ -95,7 +95,7 @@ unsigned long bitmap_ffs(const bitmap *b,
|
||||
}
|
||||
|
||||
if (an > n) {
|
||||
bitmap_word w = bitmap_bswap(BITMAP_WORD(b, n));
|
||||
bitmap_word w = bitmap_bswap(BITMAP_WORD(bitmap, n));
|
||||
|
||||
w &= headmask;
|
||||
|
||||
@ -104,7 +104,7 @@ unsigned long bitmap_ffs(const bitmap *b,
|
||||
}
|
||||
|
||||
while (an < am) {
|
||||
bitmap_word w = bitmap_bswap(BITMAP_WORD(b, an));
|
||||
bitmap_word w = bitmap_bswap(BITMAP_WORD(bitmap, an));
|
||||
|
||||
if (w)
|
||||
return an + bitmap_clz(w);
|
||||
@ -113,7 +113,7 @@ unsigned long bitmap_ffs(const bitmap *b,
|
||||
}
|
||||
|
||||
if (m > am) {
|
||||
bitmap_word w = bitmap_bswap(BITMAP_WORD(b, m));
|
||||
bitmap_word w = bitmap_bswap(BITMAP_WORD(bitmap, m));
|
||||
|
||||
w &= tailmask;
|
||||
|
||||
|
||||
@ -15,13 +15,10 @@ typedef unsigned long bitmap_word;
|
||||
#define BITMAP_NWORDS(_n) \
|
||||
(((_n) + BITMAP_WORD_BITS - 1) / BITMAP_WORD_BITS)
|
||||
|
||||
#define BITMAP_WORD_0 (0)
|
||||
#define BITMAP_WORD_1 ((bitmap_word)-1UL)
|
||||
|
||||
/*
|
||||
* We wrap each word in a structure for type checking.
|
||||
*/
|
||||
typedef struct bitmap {
|
||||
typedef struct {
|
||||
bitmap_word w;
|
||||
} bitmap;
|
||||
|
||||
@ -58,37 +55,37 @@ static inline bitmap_word bitmap_bswap(bitmap_word w)
|
||||
#define BITMAP_TAIL(_bm, _nbits) \
|
||||
(BITMAP_TAILWORD(_bm, _nbits) & BITMAP_TAILBITS(_nbits))
|
||||
|
||||
static inline void bitmap_set_bit(bitmap *b, unsigned long n)
|
||||
static inline void bitmap_set_bit(bitmap *bitmap, unsigned long n)
|
||||
{
|
||||
BITMAP_WORD(b, n) |= BITMAP_WORDBIT(n);
|
||||
BITMAP_WORD(bitmap, n) |= BITMAP_WORDBIT(n);
|
||||
}
|
||||
|
||||
static inline void bitmap_clear_bit(bitmap *b, unsigned long n)
|
||||
static inline void bitmap_clear_bit(bitmap *bitmap, unsigned long n)
|
||||
{
|
||||
BITMAP_WORD(b, n) &= ~BITMAP_WORDBIT(n);
|
||||
BITMAP_WORD(bitmap, n) &= ~BITMAP_WORDBIT(n);
|
||||
}
|
||||
|
||||
static inline void bitmap_change_bit(bitmap *b, unsigned long n)
|
||||
static inline void bitmap_change_bit(bitmap *bitmap, unsigned long n)
|
||||
{
|
||||
BITMAP_WORD(b, n) ^= BITMAP_WORDBIT(n);
|
||||
BITMAP_WORD(bitmap, n) ^= BITMAP_WORDBIT(n);
|
||||
}
|
||||
|
||||
static inline bool bitmap_test_bit(const bitmap *b, unsigned long n)
|
||||
static inline bool bitmap_test_bit(const bitmap *bitmap, unsigned long n)
|
||||
{
|
||||
return !!(BITMAP_WORD(b, n) & BITMAP_WORDBIT(n));
|
||||
return !!(BITMAP_WORD(bitmap, n) & BITMAP_WORDBIT(n));
|
||||
}
|
||||
|
||||
void bitmap_zero_range(bitmap *b, unsigned long n, unsigned long m);
|
||||
void bitmap_fill_range(bitmap *b, unsigned long n, unsigned long m);
|
||||
void bitmap_zero_range(bitmap *bitmap, unsigned long n, unsigned long m);
|
||||
void bitmap_fill_range(bitmap *bitmap, unsigned long n, unsigned long m);
|
||||
|
||||
static inline void bitmap_zero(bitmap *b, unsigned long nbits)
|
||||
static inline void bitmap_zero(bitmap *bitmap, unsigned long nbits)
|
||||
{
|
||||
memset(b, 0, bitmap_sizeof(nbits));
|
||||
memset(bitmap, 0, bitmap_sizeof(nbits));
|
||||
}
|
||||
|
||||
static inline void bitmap_fill(bitmap *b, unsigned long nbits)
|
||||
static inline void bitmap_fill(bitmap *bitmap, unsigned long nbits)
|
||||
{
|
||||
memset(b, 0xff, bitmap_sizeof(nbits));
|
||||
memset(bitmap, 0xff, bitmap_sizeof(nbits));
|
||||
}
|
||||
|
||||
static inline void bitmap_copy(bitmap *dst, const bitmap *src,
|
||||
@ -161,36 +158,37 @@ static inline bool bitmap_subset(const bitmap *src1, const bitmap *src2,
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool bitmap_full(const bitmap *b, unsigned long nbits)
|
||||
static inline bool bitmap_full(const bitmap *bitmap, unsigned long nbits)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < BITMAP_HEADWORDS(nbits); i++) {
|
||||
if (b[i].w != -1UL)
|
||||
if (bitmap[i].w != -1UL)
|
||||
return false;
|
||||
}
|
||||
if (BITMAP_HASTAIL(nbits) &&
|
||||
(BITMAP_TAIL(b, nbits) != BITMAP_TAILBITS(nbits)))
|
||||
(BITMAP_TAIL(bitmap, nbits) != BITMAP_TAILBITS(nbits)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool bitmap_empty(const bitmap *b, unsigned long nbits)
|
||||
static inline bool bitmap_empty(const bitmap *bitmap, unsigned long nbits)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < BITMAP_HEADWORDS(nbits); i++) {
|
||||
if (b[i].w != 0)
|
||||
if (bitmap[i].w != 0)
|
||||
return false;
|
||||
}
|
||||
if (BITMAP_HASTAIL(nbits) && (BITMAP_TAIL(b, nbits) != 0))
|
||||
if (BITMAP_HASTAIL(nbits) && (BITMAP_TAIL(bitmap, nbits) != 0))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long bitmap_ffs(const bitmap *b, unsigned long n, unsigned long m);
|
||||
unsigned long bitmap_ffs(const bitmap *bitmap,
|
||||
unsigned long n, unsigned long m);
|
||||
|
||||
/*
|
||||
* Allocation functions
|
||||
@ -220,26 +218,26 @@ static inline bitmap *bitmap_alloc1(unsigned long nbits)
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
static inline bitmap *bitmap_realloc0(bitmap *b,
|
||||
static inline bitmap *bitmap_realloc0(bitmap *bitmap,
|
||||
unsigned long obits, unsigned long nbits)
|
||||
{
|
||||
b = realloc(b, bitmap_sizeof(nbits));
|
||||
bitmap = realloc(bitmap, bitmap_sizeof(nbits));
|
||||
|
||||
if ((nbits > obits) && b)
|
||||
bitmap_zero_range(b, obits, nbits);
|
||||
if ((nbits > obits) && bitmap)
|
||||
bitmap_zero_range(bitmap, obits, nbits);
|
||||
|
||||
return b;
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
static inline bitmap *bitmap_realloc1(bitmap *b,
|
||||
static inline bitmap *bitmap_realloc1(bitmap *bitmap,
|
||||
unsigned long obits, unsigned long nbits)
|
||||
{
|
||||
b = realloc(b, bitmap_sizeof(nbits));
|
||||
bitmap = realloc(bitmap, bitmap_sizeof(nbits));
|
||||
|
||||
if ((nbits > obits) && b)
|
||||
bitmap_fill_range(b, obits, nbits);
|
||||
if ((nbits > obits) && bitmap)
|
||||
bitmap_fill_range(bitmap, obits, nbits);
|
||||
|
||||
return b;
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
#endif /* CCAN_BITMAP_H_ */
|
||||
|
||||
@ -10,7 +10,7 @@ int main(void)
|
||||
plan_tests(68 + 6 * (31 + 63));
|
||||
|
||||
for (i = 0; i < 32; i++)
|
||||
ok1(bitops_ffs32(1U << i) == i+1);
|
||||
ok1(bitops_ffs32(1 << 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(1U << i) == 31 - i);
|
||||
ok1(bitops_clz32(1 << 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((1U << i) + (1U << i)-1) == 31 - i);
|
||||
ok1(bitops_clz32((1 << i) + (1 << 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(1U << i) == i);
|
||||
ok1(bitops_ctz32(1 << i) == i);
|
||||
for (i = 0; i < 64; i++)
|
||||
ok1(bitops_ctz64((uint64_t)1 << i) == i);
|
||||
|
||||
|
||||
@ -1 +0,0 @@
|
||||
../../licenses/CC0
|
||||
@ -1,69 +0,0 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* closefrom - close all fds starting from specified fd.
|
||||
*
|
||||
* This code is an example of what to do in a child process to
|
||||
* ensure that none of the (possibly sensitive) file descriptors
|
||||
* in the parent remain in the child process.
|
||||
*
|
||||
* License: CC0 (Public domain)
|
||||
* Author: ZmnSCPxj jxPCSnmZ <ZmnSCPxj@protonmail.com>
|
||||
*
|
||||
* Example:
|
||||
* #include <ccan/closefrom/closefrom.h>
|
||||
* #include <ccan/err/err.h>
|
||||
* #include <stdio.h>
|
||||
* #include <sys/resource.h>
|
||||
* #include <sys/time.h>
|
||||
* #include <sys/types.h>
|
||||
* #include <sys/wait.h>
|
||||
* #include <unistd.h>
|
||||
*
|
||||
* int main(int argc, char **argv)
|
||||
* {
|
||||
* pid_t child;
|
||||
*
|
||||
* // If being emulated, then we might end up
|
||||
* // looping over a large _SC_OPEN_MAX
|
||||
* // (Some systems have it as INT_MAX!)
|
||||
* // If so, closefrom_limit will lower this limit
|
||||
* // to a value you specify, or if given 0 will
|
||||
* // limit to 4096.
|
||||
* // Call this as early as possible.
|
||||
* closefrom_limit(0);
|
||||
*
|
||||
* // If we limited, we can query this so we can
|
||||
* // print it in debug logs or something.
|
||||
* if (closefrom_may_be_slow())
|
||||
* printf("we limited ourselves to 4096 fds.\n");
|
||||
*
|
||||
* child = fork();
|
||||
* if (child < 0)
|
||||
* err(1, "Forking");
|
||||
* if (child == 0) {
|
||||
* closefrom(STDERR_FILENO + 1);
|
||||
* // Insert your *whatever* code here.
|
||||
* _exit(0);
|
||||
* }
|
||||
*
|
||||
* waitpid(child, NULL, 0);
|
||||
*
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* Expect exactly one argument */
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -1,225 +0,0 @@
|
||||
/* CC0 license (public domain) - see LICENSE file for details */
|
||||
#include <ccan/closefrom/closefrom.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* See also:
|
||||
* https://stackoverflow.com/a/918469
|
||||
*
|
||||
* The implementation below is not exhaustive of all the suggested above.
|
||||
*/
|
||||
|
||||
#if !HAVE_CLOSEFROM
|
||||
|
||||
/* IBM AIX.
|
||||
* https://www.ibm.com/docs/en/aix/7.2?topic=f-fcntl-dup-dup2-subroutine
|
||||
*/
|
||||
#if HAVE_F_CLOSEM
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
void closefrom(int fromfd)
|
||||
{
|
||||
(void) fcntl(fromfd, F_CLOSEM, 0);
|
||||
}
|
||||
|
||||
bool closefrom_may_be_slow(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#else /* !HAVE_F_CLOSEM */
|
||||
|
||||
#if HAVE_NR_CLOSE_RANGE
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#define PROC_PID_FD_LEN \
|
||||
( 6 /* /proc/ */ \
|
||||
+ 20 /* 64-bit $PID */ \
|
||||
+ 3 /* /fd */ \
|
||||
+ 1 /* NUL */ \
|
||||
)
|
||||
|
||||
static bool can_get_maxfd(void)
|
||||
{
|
||||
#if HAVE_F_MAXFD
|
||||
int res = fcntl(0, F_MAXFD);
|
||||
if (res < 0)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Linux >= 5.9 */
|
||||
static bool can_close_range(void)
|
||||
{
|
||||
#if HAVE_NR_CLOSE_RANGE
|
||||
int res = syscall(__NR_close_range, INT_MAX, INT_MAX, 0);
|
||||
if (res < 0)
|
||||
return false;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* On Linux, Solaris, AIX, Cygwin, and NetBSD. */
|
||||
static bool can_open_proc_pid_fd(void)
|
||||
{
|
||||
char dnam[PROC_PID_FD_LEN];
|
||||
DIR *dir;
|
||||
|
||||
sprintf(dnam, "/proc/%ld/fd", (long) getpid());
|
||||
dir = opendir(dnam);
|
||||
if (!dir)
|
||||
return false;
|
||||
closedir(dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* On FreeBSD and MacOS. */
|
||||
static bool can_open_dev_fd(void)
|
||||
{
|
||||
DIR *dir;
|
||||
dir = opendir("/dev/fd");
|
||||
if (!dir)
|
||||
return false;
|
||||
closedir(dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool closefrom_may_be_slow(void)
|
||||
{
|
||||
if (can_get_maxfd())
|
||||
return false;
|
||||
else if (can_close_range())
|
||||
return false;
|
||||
else if (can_open_proc_pid_fd())
|
||||
return false;
|
||||
else if (can_open_dev_fd())
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/* It is possible that we run out of available file descriptors.
|
||||
* However, if we are going to close anyway, we could just try
|
||||
* closing file descriptors until we reach maxfd.
|
||||
*/
|
||||
static
|
||||
DIR *try_opendir(const char *dnam, int *fromfd, int maxfd)
|
||||
{
|
||||
DIR *dir;
|
||||
|
||||
do {
|
||||
dir = opendir(dnam);
|
||||
if (!dir && (errno == ENFILE || errno == EMFILE)) {
|
||||
if (*fromfd < maxfd)
|
||||
close((*fromfd)++);
|
||||
else
|
||||
break;
|
||||
}
|
||||
} while (!dir && (errno == ENFILE || errno == EMFILE));
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
void closefrom(int fromfd)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
|
||||
int res;
|
||||
int maxfd;
|
||||
|
||||
char dnam[PROC_PID_FD_LEN];
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
(void) res;
|
||||
|
||||
if (fromfd < 0)
|
||||
goto quit;
|
||||
|
||||
#if HAVE_NR_CLOSE_RANGE
|
||||
res = syscall(__NR_close_range, fromfd, INT_MAX, 0);
|
||||
if (res == 0)
|
||||
goto quit;
|
||||
#endif
|
||||
|
||||
maxfd = sysconf(_SC_OPEN_MAX);
|
||||
|
||||
sprintf(dnam, "/proc/%ld/fd", (long) getpid());
|
||||
dir = try_opendir(dnam, &fromfd, maxfd);
|
||||
if (!dir)
|
||||
dir = try_opendir("/dev/fd", &fromfd, maxfd);
|
||||
|
||||
if (dir) {
|
||||
while ((entry = readdir(dir))) {
|
||||
long fd;
|
||||
char *endp;
|
||||
|
||||
fd = strtol(entry->d_name, &endp, 10);
|
||||
if (entry->d_name != endp && *endp == '\0' &&
|
||||
fd >= 0 && fd < INT_MAX && fd >= fromfd &&
|
||||
fd != dirfd(dir) )
|
||||
close(fd);
|
||||
}
|
||||
closedir(dir);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
#if HAVE_F_MAXFD
|
||||
res = fcntl(0, F_MAXFD);
|
||||
if (res >= 0)
|
||||
maxfd = res + 1;
|
||||
#endif
|
||||
|
||||
/* Fallback. */
|
||||
for (; fromfd < maxfd; ++fromfd)
|
||||
close(fromfd);
|
||||
|
||||
quit:
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
#endif /* !HAVE_F_CLOSEM */
|
||||
|
||||
void closefrom_limit(unsigned int arg_limit)
|
||||
{
|
||||
rlim_t limit = (rlim_t) arg_limit;
|
||||
|
||||
struct rlimit nofile;
|
||||
|
||||
if (!closefrom_may_be_slow())
|
||||
return;
|
||||
|
||||
if (limit == 0)
|
||||
limit = 4096;
|
||||
|
||||
getrlimit(RLIMIT_NOFILE, &nofile);
|
||||
|
||||
/* Respect the max limit.
|
||||
* If we are not running as root then we cannot raise
|
||||
* it, but we *can* lower the max limit.
|
||||
*/
|
||||
if (nofile.rlim_max != RLIM_INFINITY && limit > nofile.rlim_max)
|
||||
limit = nofile.rlim_max;
|
||||
|
||||
nofile.rlim_cur = limit;
|
||||
nofile.rlim_max = limit;
|
||||
|
||||
setrlimit(RLIMIT_NOFILE, &nofile);
|
||||
}
|
||||
|
||||
#endif /* !HAVE_CLOSEFROM */
|
||||
@ -1,81 +0,0 @@
|
||||
/* CC0 license (public domain) - see LICENSE file for details */
|
||||
#ifndef CCAN_CLOSEFROM_H
|
||||
#define CCAN_CLOSEFROM_H
|
||||
#include "config.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#if HAVE_CLOSEFROM
|
||||
/* BSD. */
|
||||
#include <unistd.h>
|
||||
/* Solaris. */
|
||||
#include <stdlib.h>
|
||||
|
||||
static inline
|
||||
bool closefrom_may_be_slow(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
void closefrom_limit(unsigned int limit)
|
||||
{
|
||||
}
|
||||
|
||||
#else /* !HAVE_CLOSEFROM */
|
||||
|
||||
/**
|
||||
* closefrom - Close all open file descriptors, starting
|
||||
* at fromfd onwards.
|
||||
* @fromfd: the first fd to close; it and all higher file descriptors
|
||||
* will be closed.
|
||||
*
|
||||
* This is not multithread-safe: other threads in the same process
|
||||
* may or may not open new file descriptors in parallel to this call.
|
||||
* However, the expected use-case is that this will be called in a
|
||||
* child process just after fork(), meaning the child process is still
|
||||
* single-threaded.
|
||||
*/
|
||||
void closefrom_(int fromfd);
|
||||
/* In case the standard library has it, but declared in some
|
||||
* *other* header we do not know of yet, we use closefrom_ in
|
||||
* the actual name the linker sees.
|
||||
*/
|
||||
#define closefrom closefrom_
|
||||
|
||||
/**
|
||||
* closefrom_may_be_slow - check if the closefrom() function could
|
||||
* potentially take a long time.
|
||||
*
|
||||
* The return value is true if closefrom() is emulated by
|
||||
* looping from fromfd to sysconf(_SC_OPEN_MAX), which can be
|
||||
* very large (possibly even INT_MAX on some systems).
|
||||
* If so, you might want to use setrlimit to limit _SC_OPEN_MAX.
|
||||
* If this returns false, then closefrom is efficient and you do not
|
||||
* need to limit the number of file descriptors.
|
||||
*
|
||||
* You can use closefrom_limit to perform the limiting based on
|
||||
* closefrom_may_be_slow.
|
||||
* This API is exposed in case you want to output to debug logs or
|
||||
* something similar.
|
||||
*/
|
||||
bool closefrom_may_be_slow(void);
|
||||
|
||||
/**
|
||||
* closefrom_limit - If closefrom_may_be_slow(), lower the limit on
|
||||
* the number of file descriptors we keep open, to prevent closefrom
|
||||
* from being *too* slow.
|
||||
* @limit: 0 to use a reasonable default of 4096, or non-zero for the
|
||||
* limit you prefer.
|
||||
*
|
||||
* This function does nothing if closefrom_may_be_slow() return false.
|
||||
*
|
||||
* This function only *lowers* the limit from the hard limit set by
|
||||
* root before running this program.
|
||||
* If the limit is higher than the hard limit, then the hard limit is
|
||||
* respected.
|
||||
*/
|
||||
void closefrom_limit(unsigned int limit);
|
||||
|
||||
#endif /* !HAVE_CLOSEFROM */
|
||||
|
||||
#endif /* CCAN_CLOSEFROM_H */
|
||||
@ -1,192 +0,0 @@
|
||||
#include <ccan/closefrom/closefrom.h>
|
||||
/* Include the C files directly. */
|
||||
#include <ccan/closefrom/closefrom.c>
|
||||
#include <ccan/tap/tap.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Open a pipe, do closefrom, check pipe no longer works. */
|
||||
static
|
||||
int pipe_close(void)
|
||||
{
|
||||
int fds[2];
|
||||
ssize_t wres;
|
||||
|
||||
char buf = '\0';
|
||||
|
||||
if (pipe(fds) < 0)
|
||||
return 0;
|
||||
|
||||
/* Writing to the write end should succeed, the
|
||||
* pipe is working. */
|
||||
do {
|
||||
wres = write(fds[1], &buf, 1);
|
||||
} while ((wres < 0) && (errno == EINTR));
|
||||
if (wres < 0)
|
||||
return 0;
|
||||
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
|
||||
/* Writing to the write end should fail because
|
||||
* everything should be closed. */
|
||||
do {
|
||||
wres = write(fds[1], &buf, 1);
|
||||
} while ((wres < 0) && (errno == EINTR));
|
||||
|
||||
return (wres < 0) && (errno == EBADF);
|
||||
}
|
||||
|
||||
/* Open a pipe, fork, do closefrom in child, read pipe from parent,
|
||||
* parent should see EOF.
|
||||
*/
|
||||
static
|
||||
int fork_close(void)
|
||||
{
|
||||
int fds[2];
|
||||
pid_t child;
|
||||
|
||||
char buf;
|
||||
ssize_t rres;
|
||||
|
||||
if (pipe(fds) < 0)
|
||||
return 0;
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return 0;
|
||||
|
||||
if (child == 0) {
|
||||
/* Child. */
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
_exit(0);
|
||||
} else {
|
||||
/* Parent. */
|
||||
|
||||
/* Close write end of pipe. */
|
||||
close(fds[1]);
|
||||
|
||||
do {
|
||||
rres = read(fds[0], &buf, 1);
|
||||
} while ((rres < 0) && (errno == EINTR));
|
||||
|
||||
/* Should have seen EOF. */
|
||||
if (rres != 0)
|
||||
return 0;
|
||||
|
||||
/* Clean up. */
|
||||
waitpid(child, NULL, 0);
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/* Open a pipe, fork, in child set the write end to fd #3,
|
||||
* in parent set the read end to fd #3, send a byte from
|
||||
* child to parent, check.
|
||||
*/
|
||||
static
|
||||
int fork_communicate(void)
|
||||
{
|
||||
int fds[2];
|
||||
pid_t child;
|
||||
|
||||
char wbuf = 42;
|
||||
char rbuf;
|
||||
ssize_t rres;
|
||||
ssize_t wres;
|
||||
|
||||
int status;
|
||||
|
||||
if (pipe(fds) < 0)
|
||||
return 0;
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return 0;
|
||||
|
||||
if (child == 0) {
|
||||
/* Child. */
|
||||
|
||||
/* Move write end to fd #3. */
|
||||
if (fds[1] != 3) {
|
||||
if (dup2(fds[1], 3) < 0)
|
||||
_exit(127);
|
||||
close(fds[1]);
|
||||
fds[1] = 3;
|
||||
}
|
||||
|
||||
closefrom(4);
|
||||
|
||||
do {
|
||||
wres = write(fds[1], &wbuf, 1);
|
||||
} while ((wres < 0) && (errno == EINTR));
|
||||
if (wres < 0)
|
||||
_exit(127);
|
||||
|
||||
_exit(0);
|
||||
} else {
|
||||
/* Parent. */
|
||||
|
||||
/* Move read end to fd #3. */
|
||||
if (fds[0] != 3) {
|
||||
if (dup2(fds[0], 3) < 0)
|
||||
return 0;
|
||||
close(fds[0]);
|
||||
fds[0] = 3;
|
||||
}
|
||||
|
||||
closefrom(4);
|
||||
|
||||
/* Wait for child to finish. */
|
||||
waitpid(child, &status, 0);
|
||||
if (!WIFEXITED(status))
|
||||
return 0;
|
||||
if (WEXITSTATUS(status) != 0)
|
||||
return 0;
|
||||
|
||||
/* Read 1 byte. */
|
||||
do {
|
||||
rres = read(fds[0], &rbuf, 1);
|
||||
} while ((rres < 0) && (errno == EINTR));
|
||||
if (rres < 0)
|
||||
return 0;
|
||||
if (rres != 1)
|
||||
return 0;
|
||||
/* Should get same byte as what was sent. */
|
||||
if (rbuf != wbuf)
|
||||
return 0;
|
||||
|
||||
/* Next attempt to read should EOF. */
|
||||
do {
|
||||
rres = read(fds[0], &rbuf, 1);
|
||||
} while ((rres < 0) && (errno == EINTR));
|
||||
if (rres < 0)
|
||||
return 0;
|
||||
/* Should EOF. */
|
||||
if (rres != 0)
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* Clean up. */
|
||||
close(fds[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Limit closefrom. */
|
||||
closefrom_limit(0);
|
||||
|
||||
/* This is how many tests you plan to run */
|
||||
plan_tests(3);
|
||||
|
||||
ok1(pipe_close());
|
||||
ok1(fork_close());
|
||||
ok1(fork_communicate());
|
||||
|
||||
/* This exits depending on whether all tests passed */
|
||||
return exit_status();
|
||||
}
|
||||
@ -263,27 +263,14 @@
|
||||
* The compiler will warn if any of the specified pointer args are NULL.
|
||||
*
|
||||
* Example:
|
||||
* char *my_copy2(char *buf, char *maybenull) NON_NULL_ARGS(1);
|
||||
* char *my_copy2(char *buf, char *maybenull) NON_NULL_ARGS(1, 2);
|
||||
*/
|
||||
#define NON_NULL_ARGS(...) __attribute__((__nonnull__(__VA_ARGS__)))
|
||||
#define NON_NULL_ARGS(index, ...) __attribute__((__nonnull__(index, __VA_ARGS__)))
|
||||
#else
|
||||
#define NO_NULL_ARGS
|
||||
#define NON_NULL_ARGS(...)
|
||||
#define NON_NULL_ARGS(index, ...)
|
||||
#endif
|
||||
|
||||
#if HAVE_ATTRIBUTE_RETURNS_NONNULL
|
||||
/**
|
||||
* RETURNS_NONNULL - specify that this function cannot return NULL.
|
||||
*
|
||||
* Mainly an optimization opportunity, but can also suppress warnings.
|
||||
*
|
||||
* Example:
|
||||
* RETURNS_NONNULL char *my_copy(char *buf);
|
||||
*/
|
||||
#define RETURNS_NONNULL __attribute__((__returns_nonnull__))
|
||||
#else
|
||||
#define RETURNS_NONNULL
|
||||
#endif
|
||||
|
||||
#if HAVE_ATTRIBUTE_SENTINEL
|
||||
/**
|
||||
@ -299,19 +286,4 @@
|
||||
#define LAST_ARG_NULL
|
||||
#endif
|
||||
|
||||
#if HAVE_BUILTIN_CPU_SUPPORTS
|
||||
/**
|
||||
* cpu_supports - test if current CPU supports the named feature.
|
||||
*
|
||||
* This takes a literal string, and currently only works on glibc platforms.
|
||||
*
|
||||
* Example:
|
||||
* if (cpu_supports("mmx"))
|
||||
* printf("MMX support engaged!\n");
|
||||
*/
|
||||
#define cpu_supports(x) __builtin_cpu_supports(x)
|
||||
#else
|
||||
#define cpu_supports(x) 0
|
||||
#endif /* HAVE_BUILTIN_CPU_SUPPORTS */
|
||||
|
||||
#endif /* CCAN_COMPILER_H */
|
||||
|
||||
1
ccan/ccan/crc/LICENSE
Symbolic link
1
ccan/ccan/crc/LICENSE
Symbolic link
@ -0,0 +1 @@
|
||||
../../licenses/GPL-2
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user