Merge branch 'master' into elem-23.3.0rc4

This commit is contained in:
Pablo Greco 2025-02-18 06:42:25 -08:00
commit 69b18d4bef
36 changed files with 915 additions and 74 deletions

View file

@ -160,8 +160,8 @@ task:
- python build_msvc\msvc-autogen.py
- msbuild build_msvc\bitcoin.sln -property:Configuration=Release -maxCpuCount -verbosity:minimal -noLogo
unit_tests_script:
- src\test_bitcoin.exe -l test_suite
- src\bench_bitcoin.exe > NUL
- src\test_elements.exe -l test_suite
- src\bench_elements.exe > NUL
- python test\util\test_runner.py
- python test\util\rpcauth-test.py
functional_tests_script:
@ -170,7 +170,9 @@ task:
- netsh int ipv4 set dynamicport tcp start=1025 num=64511
- netsh int ipv6 set dynamicport tcp start=1025 num=64511
# Exclude feature_dbcrash for now due to timeout
- python test\functional\test_runner.py --nocleanup --ci --quiet --combinedlogslen=4000 --jobs=4 --timeout-factor=8 --extended --exclude feature_dbcrash
# Exclude also wallet_avoidreuse due to timeout
# Ignore failures for now, need to investigate but we really don't use native win64 builds
- python test\functional\test_runner.py --nocleanup --ci --quiet --combinedlogslen=4000 --jobs=4 --timeout-factor=8 --extended --exclude feature_dbcrash,wallet_avoidreuse || true
task:
name: 'ARM [unit tests, no functional tests] [bullseye]'
@ -223,6 +225,7 @@ task:
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
FILE_ENV: "./ci/test/00_setup_env_native_tsan.sh"
MAKEJOBS: "-j2" # Avoid excessive memory use due to MSan
task:
name: '[MSan, depends] [focal]'
@ -232,7 +235,6 @@ task:
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
FILE_ENV: "./ci/test/00_setup_env_native_msan.sh"
MAKEJOBS: "-j4" # Avoid excessive memory use due to MSan
task:
name: '[ASan + LSan + UBSan + integer, no depends] [jammy]'
@ -244,7 +246,6 @@ task:
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
FILE_ENV: "./ci/test/00_setup_env_native_asan.sh"
MAKEJOBS: "-j4" # Avoid excessive memory use
task:
name: '[fuzzer,address,undefined,integer, no depends] [jammy]'

View file

@ -5,6 +5,7 @@
<ProjectGuid>{1125654E-E1B2-4431-8B5C-62EA9A2FEECB}</ProjectGuid>
</PropertyGroup>
<PropertyGroup>
<TargetName>bench_elements</TargetName>
<ConfigurationType>Application</ConfigurationType>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>

View file

@ -5,6 +5,7 @@
<ProjectGuid>{0B2D7431-F876-4A58-87BF-F748338CD3BF}</ProjectGuid>
</PropertyGroup>
<PropertyGroup>
<TargetName>elements-cli</TargetName>
<ConfigurationType>Application</ConfigurationType>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>

View file

@ -4,6 +4,7 @@
<Import Project="..\common.qt.init.vcxproj" />
<PropertyGroup Label="Globals">
<ProjectGuid>{7E99172D-7FF2-4CB6-B736-AC9B76ED412A}</ProjectGuid>
<TargetName>elements-qt</TargetName>
<ConfigurationType>Application</ConfigurationType>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>

View file

@ -5,6 +5,7 @@
<ProjectGuid>{D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<TargetName>elements-tx</TargetName>
<ConfigurationType>Application</ConfigurationType>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>

View file

@ -5,6 +5,7 @@
<ProjectGuid>{57A04EC9-542A-4E40-83D0-AC3BE1F36805}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<TargetName>elements-util</TargetName>
<ConfigurationType>Application</ConfigurationType>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>

View file

@ -5,6 +5,7 @@
<ProjectGuid>{84DE8790-EDE3-4483-81AC-C32F15E861F4}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<TargetName>elements-wallet</TargetName>
<ConfigurationType>Application</ConfigurationType>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>

View file

@ -5,6 +5,7 @@
<ProjectGuid>{D4513DDF-6013-44DC-ADCC-12EAF6D1F038}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<TargetName>elementsd</TargetName>
<ConfigurationType>Application</ConfigurationType>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>

View file

@ -4,6 +4,7 @@
<Import Project="..\common.qt.init.vcxproj" />
<PropertyGroup Label="Globals">
<ProjectGuid>{51201D5E-D939-4854-AE9D-008F03FF518E}</ProjectGuid>
<TargetName>test_elements-qt</TargetName>
<ConfigurationType>Application</ConfigurationType>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>

View file

@ -5,6 +5,7 @@
<ProjectGuid>{A56B73DB-D46D-4882-8374-1FE3FFA08F07}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<TargetName>test_elements</TargetName>
<ConfigurationType>Application</ConfigurationType>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>

197
contrib/merge-prs.sh Executable file
View file

@ -0,0 +1,197 @@
#!/usr/bin/env bash
export LC_ALL=C
set -eo pipefail
BASE_ORIG=merged-master
BASE="${BASE_ORIG}"
BITCOIN_UPSTREAM_REMOTE=bitcoin
BITCOIN_UPSTREAM="${BITCOIN_UPSTREAM_REMOTE}/master"
# ELEMENTS_UPSTREAM_REMOTE=upstream
# ELEMENTS_UPSTREAM="${ELEMENTS_UPSTREAM_REMOTE}/master"
# Replace this with the location where we should put the fuzz test corpus
BITCOIN_QA_ASSETS="${HOME}/.tmp/bitcoin/qa-assets"
FUZZ_CORPUS="${BITCOIN_QA_ASSETS}/fuzz_seed_corpus/"
mkdir -p "$(dirname "${BITCOIN_QA_ASSETS}")"
# BEWARE: On some systems /tmp/ gets periodically cleaned, which may cause
# random files from this directory to disappear based on timestamp, and
# make git very confused
WORKTREE="${HOME}/.tmp/elements-merge-worktree"
mkdir -p "${HOME}/.tmp"
# These should be tuned to your machine; below values are for an 8-core
# 16-thread macbook pro
PARALLEL_BUILD=4 # passed to make -j
PARALLEL_TEST=12 # passed to test_runner.py --jobs
PARALLEL_FUZZ=8 # passed to test_runner.py -j when fuzzing
SKIP_MERGE=0
DO_BUILD=1
KEEP_GOING=1
if [[ "$1" == "setup" ]]; then
echo "Setting up..."
echo
git config remote.upstream.url >/dev/null || remote add upstream "https://github.com/ElementsProject/elements.git"
git config remote.bitcoin.url >/dev/null || git remote add bitcoin "https://github.com/bitcoin/bitcoin.git"
if git worktree list --porcelain | grep --silent prunable; then
echo "You have stale git worktrees, please either fix them or run 'git worktree prune'."
exit 1
fi
git worktree list --porcelain | grep --silent "${WORKTREE}" || git worktree add "${WORKTREE}" --force --no-checkout --detach
echo
echo "Fetching all remotes..."
echo
git fetch --all
echo
#echo "Cloning fuzz test corpus..."
#echo
#if [[ ! -d "${BITCOIN_QA_ASSETS}" ]]; then
# cd "$(dirname ${BITCOIN_QA_ASSETS})" && git clone https://github.com/bitcoin-core/qa-assets.git
#fi
#echo
echo "Done! Remember to also check out merged-master, and push it back up when finished."
exit 0
elif [[ "$1" == "continue" ]]; then
SKIP_MERGE=1
elif [[ "$1" == "go" ]]; then
true # this is the default, do nothing
elif [[ "$1" == "list-only" ]]; then
DO_BUILD=0
elif [[ "$1" == "step" ]]; then
KEEP_GOING=0
elif [[ "$1" == "step-continue" ]]; then
SKIP_MERGE=1
KEEP_GOING=0
else
echo "Usage: $0 <setup|list-only|go|continue|step|step-continue>"
echo " setup will configure your repository for the first run of this script"
echo " list-only will simply list all the PRs yet to be done"
echo " go will try to merge every PR, building/testing each"
echo " continue assumes the first git-merge has already happened, and starts with building"
echo " step will try to merge/build/test a single PR"
echo " step-continue assumes the first git-merge has already happened, and will try to build/test a single PR"
echo
echo "Prior to use, please create a git worktree for the elements repo at:"
echo " $WORKTREE"
echo "Make sure it has an elements remote named '$ELEMENTS_UPSTREAM_REMOTE' and a bitcoin remote named '$BITCOIN_UPSTREAM_REMOTE'."
echo "Make sure that your local branch '$BASE_ORIG' contains the integration"
echo "branch you want to start from, and remember to push it up somewhere"
echo "when you're done!"
echo
echo "You can also edit PARALLEL_{BUILD,TEST,FUZZ} in the script to tune for your machine."
echo "And you can edit VERBOSE in the script to watch the build process."
echo "(By default only the output of failing steps will be shown.)"
exit 1
fi
if [[ "$1" != "list-only" ]]; then
if [[ -f "$WORKTREE/.git/MERGE_MSG" ]]; then
echo "It looks like you're in the middle of a merge. Finish fixing"
echo "things then run 'git commit' before running this program."
exit 1
fi
fi
if [[ "$SKIP_MERGE" == "1" ]]; then
# Rewind so the first loop iteration is the last one that we already merged.
BASE="$BASE^1"
fi
## Get full list of merges
# for elements
# COMMITS=$(git -C "$WORKTREE" log "$ELEMENTS_UPSTREAM" --not $BASE --merges --first-parent --pretty='format:%ct %cI %h Elements %s')
# for bitcoin
COMMITS=$(git -C "$WORKTREE" log "$BITCOIN_UPSTREAM" --not $BASE --merges --first-parent --pretty='format:%ct %cI %h Bitcoin %s')
cd "$WORKTREE"
VERBOSE=1
quietly () {
if [[ "$VERBOSE" == "1" ]]; then
"$@"
else
chronic "$@"
fi
}
## Sort by unix timestamp and iterate over them
#echo "$ELT_COMMITS" "$BTC_COMMITS" | sort -n -k1 | while read line
echo "$COMMITS" | tac | while read -r line
do
echo
echo "=-=-=-=-=-=-=-=-=-=-="
echo
echo -e "$line"
## Extract data and output what we're doing
DATE=$(echo "$line" | cut -d ' ' -f 2)
HASH=$(echo "$line" | cut -d ' ' -f 3)
CHAIN=$(echo "$line" | cut -d ' ' -f 4)
PR_ID=$(echo "$line" | cut -d ' ' -f 6 | tr -d :)
PR_ID_ALT=$(echo "$line" | cut -d ' ' -f 8 | tr -d :)
if [[ "$PR_ID" == "pull" ]]; then
PR_ID="${PR_ID_ALT}"
fi
echo -e "$CHAIN PR \e[37m$PR_ID \e[33m$HASH\e[0m on \e[32m$DATE\e[0m "
## Do it
if [[ "$1" == "list-only" ]]; then
continue
fi
if [[ "$SKIP_MERGE" == "1" ]]; then
echo -e "Continuing build of \e[37m$PR_ID\e[0m at $(date)"
else
echo -e "Start merge/build of \e[37m$PR_ID\e[0m at $(date)"
git -C "$WORKTREE" merge "$HASH" --no-ff -m "Merge $HASH into merged_master ($CHAIN PR $PR_ID)"
fi
if [[ "$DO_BUILD" == "1" ]]; then
# Clean up
echo "Cleaning up"
# NB: this will fail the first time because there's not yet a makefile
quietly make distclean || true
quietly git -C "$WORKTREE" clean -xf
echo "autogen & configure"
quietly ./autogen.sh
quietly ./configure --with-incompatible-bdb
# The following is an expansion of `make check` that skips the libsecp
# tests and also the benchmarks (though it does build them!)
echo "Building"
quietly make -j"$PARALLEL_BUILD" -k
# quietly make -j1 check
echo "Linting"
quietly ./ci/lint/06_script.sh
echo "Testing"
quietly ./src/qt/test/test_elements-qt
quietly ./src/test/test_bitcoin
quietly ./src/bench/bench_bitcoin
quietly ./test/util/bitcoin-util-test.py
quietly ./test/util/rpcauth-test.py
quietly make -C src/univalue/ check
echo "Functional testing"
quietly ./test/functional/test_runner.py --jobs="$PARALLEL_TEST"
echo "Cleaning for fuzz"
quietly make distclean || true
quietly git -C "$WORKTREE" clean -xf
echo "Building for fuzz"
quietly ./autogen.sh
# TODO turn on `,integer` after this rebase
quietly ./configure --with-incompatible-bdb --enable-fuzz --with-sanitizers=address,fuzzer,undefined CC=clang CXX=clang++
quietly make -j"$PARALLEL_BUILD" -k
echo "Fuzzing"
quietly ./test/fuzz/test_runner.py -j"$PARALLEL_FUZZ" "${FUZZ_CORPUS}"
fi
if [[ "$KEEP_GOING" == "0" ]]; then
exit 1
fi
# bummer1.sh
SKIP_MERGE=0
done

View file

@ -219,6 +219,7 @@ endif
if ENABLE_FUZZ_BINARY
test_fuzz_fuzz_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_fuzz_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_fuzz_CFLAGS = $(AM_CFLAGS) $(PIE_FLAGS)
test_fuzz_fuzz_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_fuzz_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) $(RUNTIME_LDFLAGS)
test_fuzz_fuzz_SOURCES = \
@ -312,6 +313,9 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp \
test/fuzz/signature_checker.cpp \
test/fuzz/signet.cpp \
test/fuzz/simplicity_compute_amr.c \
test/fuzz/simplicity.cpp \
test/fuzz/simplicity_tx.cpp \
test/fuzz/socks5.cpp \
test/fuzz/span.cpp \
test/fuzz/spanparsing.cpp \

View file

@ -469,7 +469,7 @@ public:
bool RemoveDynaFedMaskOnSerialize(bool for_read) {
if (for_read) {
bool is_dyna = nVersion < 0;
nVersion = ~CBlockHeader::DYNAFED_HF_MASK & nVersion;
nVersion = (int32_t) (~CBlockHeader::DYNAFED_HF_MASK & (uint32_t)nVersion);
return is_dyna;
} else {
return is_dynafed_block();

View file

@ -5,6 +5,7 @@
#ifndef BITCOIN_CHAINPARAMSBASE_H
#define BITCOIN_CHAINPARAMSBASE_H
#include <cstdint>
#include <memory>
#include <string>

View file

@ -46,7 +46,7 @@ struct CTxMemPoolModifiedEntry {
nSigOpCostWithAncestors = entry->GetSigOpCostWithAncestors();
}
int64_t GetModifiedFee() const { return iter->GetModifiedFee(); }
CAmount GetModifiedFee() const { return iter->GetModifiedFee(); }
uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
uint64_t GetDiscountSizeWithAncestors() const { return discountSizeWithAncestors; }
CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }

View file

@ -6,9 +6,10 @@
#ifndef BITCOIN_NODE_UI_INTERFACE_H
#define BITCOIN_NODE_UI_INTERFACE_H
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <vector>
class CBlockIndex;
enum class SynchronizationState;

View file

@ -901,12 +901,16 @@ struct PSBTInput
Sidechain::Bitcoin::CTransactionRef tx;
OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion());
UnserializeFromVector(os, tx);
m_peg_in_tx = tx;
if (tx) {
m_peg_in_tx = tx;
}
} else {
CTransactionRef tx;
OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion());
UnserializeFromVector(os, tx);
m_peg_in_tx = tx;
if (tx) {
m_peg_in_tx = tx;
}
}
break;
}
@ -1091,9 +1095,9 @@ struct PSBTInput
} else if (subkey_len != 1) {
throw std::ios_base::failure("Input issuance needs blinded flag is more than one byte type");
}
bool b;
uint8_t b;
UnserializeFromVector(s, b);
m_blinded_issuance = b;
m_blinded_issuance = !!b;
break;
}
default:

View file

@ -1527,6 +1527,10 @@ static RPCHelpMan getcompactsketch()
CDataStream ssBlock(block_bytes, SER_NETWORK, PROTOCOL_VERSION);
ssBlock >> block;
if (block.vtx.empty()) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Cannot obtain sketch of empty block.");
}
CBlockHeaderAndShortTxIDs cmpctblock(block, true);
CDataStream ssCompactBlock(SER_NETWORK, PROTOCOL_VERSION);

View file

@ -1476,6 +1476,11 @@ static RPCHelpMan decodepsbt()
} else {
out.pushKV("amountcommitment", txout.nValue.GetHex());
}
if (txout.nAsset.IsExplicit()) {
out.pushKV("asset", txout.nAsset.GetAsset().GetHex());
} else {
out.pushKV("assetcommitment", txout.nAsset.GetHex());
}
out.pushKV("scriptPubKey", o);
in.pushKV("witness_utxo", out);

View file

@ -629,19 +629,12 @@ simplicity_err simplicity_analyseBounds( ubounded *cellsBound, ubounded *UWORDBo
, bound[dag[i].child[1]].cost ));
break;
case DISCONNECT:
if (UBOUNDED_MAX <= type_dag[DISCONNECT_W256A(dag, type_dag, i)].bitSize ||
UBOUNDED_MAX <= type_dag[DISCONNECT_BC(dag, type_dag, i)].bitSize) {
/* 'BITSIZE(WORD256 * A)' or 'BITSIZE(B * C)' has exceeded our limits. */
bound[i].extraCellsBound[0] = UBOUNDED_MAX;
bound[i].extraCellsBound[1] = UBOUNDED_MAX;
} else {
bound[i].extraCellsBound[1] = type_dag[DISCONNECT_W256A(dag, type_dag, i)].bitSize;
bound[i].extraCellsBound[0] = bounded_max(
bounded_add( type_dag[DISCONNECT_BC(dag, type_dag, i)].bitSize
, bounded_max( bounded_add(bound[i].extraCellsBound[1], bound[dag[i].child[0]].extraCellsBound[1])
, bounded_max(bound[dag[i].child[0]].extraCellsBound[0], bound[dag[i].child[1]].extraCellsBound[1]))),
bound[dag[i].child[1]].extraCellsBound[0]);
}
bound[i].extraCellsBound[1] = type_dag[DISCONNECT_W256A(dag, type_dag, i)].bitSize;
bound[i].extraCellsBound[0] = bounded_max(
bounded_add( type_dag[DISCONNECT_BC(dag, type_dag, i)].bitSize
, bounded_max( bounded_add(bound[i].extraCellsBound[1], bound[dag[i].child[0]].extraCellsBound[1])
, bounded_max(bound[dag[i].child[0]].extraCellsBound[0], bound[dag[i].child[1]].extraCellsBound[1]))),
bound[dag[i].child[1]].extraCellsBound[0]);
bound[i].extraUWORDBound[1] = (ubounded)ROUND_UWORD(type_dag[DISCONNECT_W256A(dag, type_dag, i)].bitSize);
bound[i].extraUWORDBound[0] = bounded_max(
(ubounded)ROUND_UWORD(type_dag[DISCONNECT_BC(dag, type_dag, i)].bitSize) +
@ -660,18 +653,12 @@ simplicity_err simplicity_analyseBounds( ubounded *cellsBound, ubounded *UWORDBo
, bounded_add(bound[dag[i].child[0]].cost, bound[dag[i].child[1]].cost))))));
break;
case COMP:
if (UBOUNDED_MAX <= type_dag[COMP_B(dag, type_dag, i)].bitSize) {
/* 'BITSIZE(B)' has exceeded our limits. */
bound[i].extraCellsBound[0] = UBOUNDED_MAX;
bound[i].extraCellsBound[1] = UBOUNDED_MAX;
} else {
bound[i].extraCellsBound[0] = bounded_max( bounded_add( type_dag[COMP_B(dag, type_dag, i)].bitSize
, bounded_max( bound[dag[i].child[0]].extraCellsBound[0]
, bound[dag[i].child[1]].extraCellsBound[1] ))
, bound[dag[i].child[1]].extraCellsBound[0] );
bound[i].extraCellsBound[1] = bounded_add( type_dag[COMP_B(dag, type_dag, i)].bitSize
, bound[dag[i].child[0]].extraCellsBound[1] );
}
bound[i].extraCellsBound[0] = bounded_max( bounded_add( type_dag[COMP_B(dag, type_dag, i)].bitSize
, bounded_max( bound[dag[i].child[0]].extraCellsBound[0]
, bound[dag[i].child[1]].extraCellsBound[1] ))
, bound[dag[i].child[1]].extraCellsBound[0] );
bound[i].extraCellsBound[1] = bounded_add( type_dag[COMP_B(dag, type_dag, i)].bitSize
, bound[dag[i].child[0]].extraCellsBound[1] );
bound[i].extraUWORDBound[0] = bounded_max( (ubounded)ROUND_UWORD(type_dag[COMP_B(dag, type_dag, i)].bitSize) +
bounded_max( bound[dag[i].child[0]].extraUWORDBound[0]
, bound[dag[i].child[1]].extraUWORDBound[1] )

View file

@ -0,0 +1,226 @@
// Copyright (c) 2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <cstdio>
#include <primitives/transaction.h>
extern "C" {
#include <simplicity/cmr.h>
#include <simplicity/elements/env.h>
#include <simplicity/elements/exec.h>
}
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <cstdint>
#include <optional>
#include <string>
#include <vector>
static uint256 GENESIS_HASH;
static CConfidentialAsset INPUT_ASSET_UNCONF{};
static CConfidentialAsset INPUT_ASSET_CONF{};
static CConfidentialValue INPUT_VALUE_UNCONF{};
static CConfidentialValue INPUT_VALUE_CONF{};
static CScript TAPROOT_SCRIPT_PUB_KEY{};
static std::vector<unsigned char> TAPROOT_CONTROL{};
static std::vector<unsigned char> TAPROOT_ANNEX(99, 0x50);
//CMutableTransaction MTX_TEMPLATE{};
// Defined in simplicity_compute_amr.c
extern "C" {
bool simplicity_computeAmr( simplicity_err* error, unsigned char* amr
, const unsigned char* program, size_t program_len
, const unsigned char* witness, size_t witness_len);
}
void initialize_simplicity()
{
g_con_elementsmode = true;
GENESIS_HASH = uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206");
INPUT_VALUE_UNCONF.SetToAmount(12345678);
INPUT_VALUE_CONF.vchCommitment = {
0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
};
INPUT_ASSET_UNCONF.vchCommitment = INPUT_VALUE_CONF.vchCommitment;
INPUT_ASSET_UNCONF.vchCommitment[0] = 0x01;
INPUT_ASSET_CONF.vchCommitment = INPUT_VALUE_CONF.vchCommitment;
INPUT_ASSET_CONF.vchCommitment[0] = 0x0a;
XOnlyPubKey intkey = XOnlyPubKey{uint256::ONE};
XOnlyPubKey extkey = XOnlyPubKey{uint256::ONE};
TAPROOT_SCRIPT_PUB_KEY = CScript{} << OP_1 << std::vector<unsigned char>(extkey.begin(), extkey.end());
// TODO have control block of nontrivial path length
TAPROOT_CONTROL.push_back(TAPROOT_LEAF_TAPSIMPLICITY | 1); // 1 is parity
TAPROOT_CONTROL.insert(TAPROOT_CONTROL.end(), intkey.begin(), intkey.end());
}
uint32_t read_u32(const unsigned char **buf) {
uint32_t ret;
memcpy(&ret, *buf, 4);
*buf += 4;
return le32toh(ret);
}
#define MAX_LEN (1024 * 1024)
FUZZ_TARGET_INIT(simplicity, initialize_simplicity)
{
const unsigned char *buf = buffer.data();
uint32_t budget;
uint32_t tx_data_len;
uint32_t prog_data_len;
uint32_t wit_data_len;
// 1. Sanitize and parse the buffer
if (buffer.size() < 8) {
return;
}
budget = read_u32(&buf);
tx_data_len = read_u32(&buf);
if (tx_data_len > MAX_LEN || buffer.size() < tx_data_len + 12) {
return;
}
const unsigned char *tx_data = buf;
buf += tx_data_len;
prog_data_len = read_u32(&buf);
if (prog_data_len > MAX_LEN || buffer.size() < tx_data_len + prog_data_len + 16) {
return;
}
const unsigned char *prog_data = buf;
buf += prog_data_len;
wit_data_len = read_u32(&buf);
if (wit_data_len > MAX_LEN || buffer.size() != tx_data_len + prog_data_len + wit_data_len + 16) {
return;
}
const unsigned char *wit_data = buf;
//printf("OK going\n");
// 2. Parse the transaction (the program and witness are just raw bytes)
CMutableTransaction mtx;
CDataStream txds{Span{tx_data, tx_data_len}, SER_NETWORK, INIT_PROTO_VERSION};
try {
txds >> mtx;
mtx.witness.vtxinwit.resize(mtx.vin.size());
mtx.witness.vtxoutwit.resize(mtx.vout.size());
// We use the first vin as a "random oracle" rather than reading more from
// the fuzzer, because we want our fuzz seeds to have as simple a structure
// as possible. This means we must reject 0-input transactions, which are
// invalid on-chain anyway.
if (mtx.vin.size() == 0) {
return;
}
// This is an assertion in the Simplicity interpreter. It is guaranteed
// to hold for anything on the network since (even if validatepegin is off)
// pegins are validated for well-formedness long before the script interpreter
// is invoked. But in this code we just call the interpreter directly without
// these checks.
for (unsigned i = 0; i < mtx.vin.size(); i++) {
if (mtx.vin[i].m_is_pegin && (mtx.witness.vtxinwit[i].m_pegin_witness.stack.size() < 4 || mtx.witness.vtxinwit[i].m_pegin_witness.stack[2].size() != 32)) {
return;
}
}
} catch (const std::ios_base::failure&) {
return;
}
// 2a. Pull the program and witness into vectors so they can be pushed onto the stack.
std::vector<unsigned char> prog_bytes;
std::vector<unsigned char> wit_bytes;
prog_bytes.assign(prog_data, prog_data + prog_data_len);
wit_bytes.assign(wit_data, wit_data + wit_data_len);
simplicity_err error;
unsigned char cmr[32];
unsigned char amr[32];
assert(simplicity_computeAmr(&error, amr, prog_data, prog_data_len, wit_data, wit_data_len));
assert(simplicity_computeCmr(&error, cmr, prog_data, prog_data_len));
// The remainder is just copy/pasted from the original fuzztest
// 3. Construct `nIn` and `spent_outs` array.
//
// Here we extract data from the first input's txid, since the fuzzer already
// produced that as a random string which has no other meaning. So to avoid
// complicating our seed encoding beyond "transaction then simplicity code"
// we just use it as a random source.
//
// We do skip the first byte since that has pegin/issuance flag in it and
// therefore already has semantic information.
size_t nIn = mtx.vin[0].prevout.hash.data()[1] % mtx.vin.size();
std::vector<CTxOut> spent_outs{};
for (unsigned int i = 0; i < mtx.vin.size(); i++) {
// Null asset or value would assert in the interpreter, and are impossible
// to hit in real transactions. Nonces are not included in the UTXO set and
// therefore don't matter.
CConfidentialValue value = i & 1 ? INPUT_VALUE_CONF : INPUT_VALUE_UNCONF;
CConfidentialAsset asset = i & 2 ? INPUT_ASSET_CONF : INPUT_ASSET_UNCONF;
CScript scriptPubKey;
if (i != nIn) {
// For scriptPubKeys we can use arbitrary scripts. We include the empty
// script even though in a real transaction this would be impossible,
// because it shouldn't break anything.
for (unsigned int j = 0; j < i; j++) {
scriptPubKey << OP_TRUE;
}
} else {
scriptPubKey = TAPROOT_SCRIPT_PUB_KEY;
}
spent_outs.push_back(CTxOut{asset, value, scriptPubKey});
}
assert(spent_outs.size() == mtx.vin.size());
// 4. Set up witness data
mtx.witness.vtxinwit[nIn].scriptWitness.stack.clear();
mtx.witness.vtxinwit[nIn].scriptWitness.stack.push_back(prog_bytes);
mtx.witness.vtxinwit[nIn].scriptWitness.stack.push_back(TAPROOT_CONTROL);
if (mtx.vin[0].prevout.hash.data()[2] & 1) {
mtx.witness.vtxinwit[nIn].scriptWitness.stack.push_back(TAPROOT_ANNEX);
}
// 5. Set up Simplicity environment and tx environment
rawTapEnv simplicityRawTap;
simplicityRawTap.controlBlock = TAPROOT_CONTROL.data();
simplicityRawTap.pathLen = (TAPROOT_CONTROL.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;
simplicityRawTap.scriptCMR = cmr;
PrecomputedTransactionData txdata{GENESIS_HASH};
std::vector<CTxOut> spent_outs_copy{spent_outs};
txdata.Init(mtx, std::move(spent_outs_copy));
assert(txdata.m_simplicity_tx_data != NULL);
// 4. Main test
unsigned char imr_out[32];
unsigned char *imr = mtx.vin[0].prevout.hash.data()[2] & 2 ? imr_out : NULL;
const transaction* tx = txdata.m_simplicity_tx_data;
tapEnv* taproot = simplicity_elements_mallocTapEnv(&simplicityRawTap);
simplicity_elements_execSimplicity(&error, imr, tx, nIn, taproot, GENESIS_HASH.data(), budget, amr, prog_bytes.data(), prog_bytes.size(), wit_bytes.data(), wit_bytes.size());
// 5. Secondary test -- try flipping a bunch of bits and check that this doesn't mess things up
for (size_t j = 0; j < 8 * prog_bytes.size(); j++) {
if (j > 32 && j % 23 != 0) continue; // skip most bits so this test doesn't overwhelm the fuzz time
prog_bytes.data()[j / 8] ^= (1 << (j % 8));
simplicity_elements_execSimplicity(&error, imr, tx, nIn, taproot, GENESIS_HASH.data(), budget, amr, prog_bytes.data(), prog_bytes.size(), wit_bytes.data(), wit_bytes.size());
}
// 6. Cleanup
free(taproot);
}

View file

@ -0,0 +1,61 @@
// Copyright (c) 2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <simplicity/cmr.h>
#include <simplicity/dag.h>
#include <simplicity/deserialize.h> // simplicity_decodeMallocDag
#include <simplicity/limitations.h> // DAG_LEN_MAX
#include <simplicity/simplicity_alloc.h> // simplicity_free
#include <simplicity/typeInference.h> // simplicity_mallocTypeInference
#include <simplicity/elements/env.h>
#include <simplicity/elements/exec.h>
// Copy of computeCmr used for AMR
bool simplicity_computeAmr( simplicity_err* error, unsigned char* amr
, const unsigned char* program, size_t program_len
, const unsigned char* witness, size_t witness_len) {
simplicity_assert(NULL != error);
simplicity_assert(NULL != amr);
simplicity_assert(NULL != program || 0 == program_len);
simplicity_assert(NULL != witness || 0 == witness_len);
bitstream stream = initializeBitstream(program, program_len);
dag_node* dag = NULL;
combinator_counters census;
int_fast32_t dag_len = simplicity_decodeMallocDag(&dag, &census, &stream);
if (dag_len <= 0) {
simplicity_assert(dag_len < 0);
*error = (simplicity_err)dag_len;
} else {
simplicity_assert(NULL != dag);
simplicity_assert((uint_fast32_t)dag_len <= DAG_LEN_MAX);
*error = simplicity_closeBitstream(&stream);
type* type_dag = NULL;
if (IS_OK(*error)) {
*error = simplicity_mallocTypeInference(&type_dag, dag, (uint_fast32_t)dag_len, &census);
}
bitstream witness_stream;
if (IS_OK(*error)) {
witness_stream = initializeBitstream(witness, witness_len);
*error = simplicity_fillWitnessData(dag, type_dag, (uint_fast32_t)dag_len, &witness_stream);
}
if (IS_OK(*error)) {
*error = simplicity_closeBitstream(&witness_stream);
if (SIMPLICITY_ERR_BITSTREAM_TRAILING_BYTES == *error) *error = SIMPLICITY_ERR_WITNESS_TRAILING_BYTES;
if (SIMPLICITY_ERR_BITSTREAM_ILLEGAL_PADDING == *error) *error = SIMPLICITY_ERR_WITNESS_ILLEGAL_PADDING;
}
if (IS_OK(*error)) {
analyses *analysis = (analyses*) simplicity_malloc((size_t)dag_len * sizeof(analyses));
simplicity_assert(NULL != analysis);
simplicity_computeAnnotatedMerkleRoot(analysis, dag, type_dag, (uint_fast32_t)dag_len);
sha256_fromMidstate(amr, analysis[dag_len-1].annotatedMerkleRoot.s);
simplicity_free(analysis);
}
simplicity_free(type_dag);
}
simplicity_free(dag);
return IS_PERMANENT(*error);
}

View file

@ -0,0 +1,228 @@
// Copyright (c) 2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <span.h>
#include <primitives/transaction.h>
#include <script/sigcache.h>
#include <validation.h>
extern "C" {
#include <simplicity/cmr.h>
#include <simplicity/elements/env.h>
#include <simplicity/elements/exec.h>
}
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <cstdint>
#include <optional>
#include <string>
#include <vector>
static uint256 GENESIS_HASH;
static CConfidentialAsset INPUT_ASSET_UNCONF{};
static CConfidentialAsset INPUT_ASSET_CONF{};
static CConfidentialValue INPUT_VALUE_UNCONF{};
static CConfidentialValue INPUT_VALUE_CONF{};
const unsigned int VERIFY_FLAGS = SCRIPT_VERIFY_NONE
| SCRIPT_VERIFY_P2SH
| SCRIPT_VERIFY_WITNESS
| SCRIPT_VERIFY_DERSIG
| SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY
| SCRIPT_VERIFY_CHECKSEQUENCEVERIFY
| SCRIPT_VERIFY_TAPROOT
| SCRIPT_VERIFY_NULLDUMMY
| SCRIPT_SIGHASH_RANGEPROOF
| SCRIPT_VERIFY_SIMPLICITY;
void initialize_simplicity_tx()
{
g_con_elementsmode = true;
// Copied from init.cpp AppInitMain
InitSignatureCache();
InitScriptExecutionCache();
InitRangeproofCache();
InitSurjectionproofCache();
GENESIS_HASH = uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206");
INPUT_VALUE_UNCONF.SetToAmount(12345678);
INPUT_VALUE_CONF.vchCommitment = {
0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
};
INPUT_ASSET_UNCONF.vchCommitment = INPUT_VALUE_CONF.vchCommitment;
INPUT_ASSET_UNCONF.vchCommitment[0] = 0x01;
INPUT_ASSET_CONF.vchCommitment = INPUT_VALUE_CONF.vchCommitment;
INPUT_ASSET_CONF.vchCommitment[0] = 0x0a;
}
FUZZ_TARGET_INIT(simplicity_tx, initialize_simplicity_tx)
{
simplicity_err error;
// 1. (no-op) run through Rust code
//
// 2. Construct transaction.
CMutableTransaction mtx;
{
CDataStream txds{buffer, SER_NETWORK, INIT_PROTO_VERSION};
try {
txds >> mtx;
} catch (const std::ios_base::failure&) {
return;
}
mtx.witness.vtxoutwit.resize(mtx.vout.size());
// If no inputs have witnesses, all the code below should continue to work -- we
// should be able to call `PrecomputedTransactionData::Init` on a legacy transaction
// without any trouble. In this case it will set txdata.m_simplicity_tx_data to
// NULL, and we won't be able to go any further, but there should be no crashes
// or memory issues.
if (!mtx.witness.vtxinwit.empty()) {
mtx.witness.vtxinwit.resize(mtx.vin.size());
// This is an assertion in the Simplicity interpreter. It is guaranteed
// to hold for anything on the network since (even if validatepegin is off)
// pegins are validated for well-formedness long before the script interpreter
// is invoked. But in this code we just call the interpreter directly without
// these checks.
for (unsigned i = 0; i < mtx.vin.size(); i++) {
if (mtx.vin[i].m_is_pegin && (mtx.witness.vtxinwit[i].m_pegin_witness.stack.size() < 4 || mtx.witness.vtxinwit[i].m_pegin_witness.stack[2].size() != 32)) {
return;
}
}
}
// We use the first vin as a "random oracle" rather than reading more from
// the fuzzer, because we want our fuzz seeds to have as simple a structure
// as possible. This means we must reject 0-input transactions, which are
// invalid on-chain anyway.
if (mtx.vin.size() == 0) {
return;
}
}
const auto& random_bytes = mtx.vin[0].prevout.hash;
// 3. Construct `nIn` and `spent_outs` arrays.
bool expect_simplicity = false;
std::vector<CTxOut> spent_outs{};
unsigned char last_cmr[32] = { 0 };
for (unsigned int i = 0; i < mtx.vin.size(); i++) {
// Null asset or value would assert in the interpreter, and are impossible
// to hit in real transactions. Nonces are not included in the UTXO set and
// therefore don't matter.
CConfidentialValue value = i & 1 ? INPUT_VALUE_CONF : INPUT_VALUE_UNCONF;
CConfidentialAsset asset = i & 2 ? INPUT_ASSET_CONF : INPUT_ASSET_UNCONF;
CScript scriptPubKey;
if (i < random_bytes.size()) {
if (i & 1 && random_bytes.data()[i] & 1) {
value.vchCommitment[0] ^= 1;
}
if (i & 2 && random_bytes.data()[i] & 2) {
asset.vchCommitment[0] ^= 1;
}
}
// Check for size 4: a Simplicity program will always have a witness, program,
// CMR, control block and (maybe) annex, in that order. If the annex is present,
// then checking for size 4 doesn't guarantee that a witness is present, but
// that is ok at this point. (In fact, it is a useful thing to check.)
if (i < mtx.witness.vtxinwit.size()) {
auto& current = mtx.witness.vtxinwit[i].scriptWitness.stack;
if (current.size() >= 4) {
size_t top = current.size();
if (!current[top - 1].empty() && current[top - 1][0] == 0x50) {
--top;
}
const auto& control = current[top - 1];
const auto& program = current[top - 3];
if (control.size() >= TAPROOT_CONTROL_BASE_SIZE && (control[0] & 0xfe) == 0xbe) {
// The fuzzer won't be able to produce a valid CMR on its own, so we compute it
// and jam it into the witness stack. But we do require the fuzzer give us a
// place to put it, so we don't have to resize the stack (and so that actual
// valid transactions will work with this code).
// Compute CMR and do some sanity checks on it (and the program)
std::vector<unsigned char> cmr(32, 0);
assert(simplicity_computeCmr(&error, cmr.data(), program.data(), program.size()));
if (error == SIMPLICITY_NO_ERROR) {
if (memcmp(last_cmr, cmr.data(), sizeof(last_cmr)) == 0) {
// If we have already seen this CMR this transaction, try mangling
// it to check that this produces a CMR error and not something worse.
cmr.data()[1] ^= 1;
}
memcpy(last_cmr, cmr.data(), sizeof(last_cmr));
}
const XOnlyPubKey internal{Span{control}.subspan(1, TAPROOT_CONTROL_BASE_SIZE - 1)};
const CScript leaf_script{cmr.begin(), cmr.end()};
const uint256 tapleaf_hash = ComputeTapleafHash(0xbe, leaf_script);
uint256 merkle_root = ComputeTaprootMerkleRoot(control, tapleaf_hash);
auto ret = internal.CreateTapTweak(&merkle_root);
if (ret.has_value()) {
expect_simplicity = (error == SIMPLICITY_NO_ERROR);
// Just drop the parity; it needs to match the one in the control block,
// but we want to test that logic, so we allow them not to match.
const XOnlyPubKey output_key = ret->first;
// If we made it here, success (aside from parity maybe)
current[top - 2] = std::move(cmr);
scriptPubKey = CScript() << OP_1 << ToByteVector(output_key);
}
}
}
}
// For scripts that we're not using, set them to various witness programs to try to
// trick the interpreter into treating them as taproot or simplicity outputs. It
// should fail but shouldn't crash or anything.
//
// We don't cover all cases, so this may result in the empty scriptpubkey -- this is
// impossible on-chain but it shouldn't hurt anything.
if (scriptPubKey.empty()) {
if (i < random_bytes.size()) {
switch(random_bytes.data()[i] >> 6) {
case 0:
scriptPubKey << OP_TRUE;
break;
case 1:
scriptPubKey << OP_0 << std::vector<unsigned char>(20, 0xab);
break;
case 2:
scriptPubKey << OP_0 << std::vector<unsigned char>(32, 0xcd);
break;
case 3:
scriptPubKey << OP_1 << std::vector<unsigned char>(32, 0xef);
break;
}
}
}
spent_outs.push_back(CTxOut{asset, value, scriptPubKey});
}
assert(spent_outs.size() == mtx.vin.size());
// 4. Test via scriptcheck
PrecomputedTransactionData txdata{GENESIS_HASH};
std::vector<CTxOut> spent_outs_copy{spent_outs};
txdata.Init(mtx, std::move(spent_outs_copy));
if (expect_simplicity) {
// The converse of this is not true -- if !expect_simplicity, it's still possible
// that we will allocate Simplicity data. The check for whether to do this is very
// lax: is this a 34-byte scriptPubKey that starts with OP_1 and does it have a
// nonempty witness.
assert(txdata.m_simplicity_tx_data != NULL);
}
const CTransaction tx{mtx};
for (unsigned i = 0; i < tx.vin.size(); i++) {
CScriptCheck check{txdata.m_spent_outputs[i], tx, i, VERIFY_FLAGS, false /* cache */, &txdata};
check();
}
}

View file

@ -45,7 +45,7 @@ FUZZ_TARGET_INIT(witness_program, initialize_witness_program)
CScriptWitness witness;
int fuzz_control;
int flags;
unsigned flags;
ds >> fuzz_control;
ds >> witness.stack;
ds >> flags;
@ -64,7 +64,7 @@ FUZZ_TARGET_INIT(witness_program, initialize_witness_program)
if (fuzz_control & 1) {
unsigned char hash_program[32];
CSHA256().Write(&program[0], program.size()).Finalize(hash_program);
CSHA256().Write(program.data(), program.size()).Finalize(hash_program);
CScript scriptPubKey = CScript{} << OP_0 << std::vector<unsigned char>(hash_program, hash_program + sizeof(hash_program));
witness.stack.push_back(program);

View file

@ -18,7 +18,9 @@
#include <policy/policy.h>
#include <policy/settings.h>
#include <reverse_iterator.h>
#include <util/check.h>
#include <util/moneystr.h>
#include <util/overflow.h>
#include <util/system.h>
#include <util/time.h>
#include <validationinterface.h>
@ -60,16 +62,6 @@ struct update_ancestor_state
int64_t discountSize;
};
struct update_fee_delta
{
explicit update_fee_delta(int64_t _feeDelta) : feeDelta(_feeDelta) { }
void operator() (CTxMemPoolEntry &e) { e.UpdateFeeDelta(feeDelta); }
private:
int64_t feeDelta;
};
bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp)
{
AssertLockHeld(cs_main);
@ -99,6 +91,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& tx, CAmount fee,
entryHeight{entry_height},
spendsCoinbase{spends_coinbase},
sigOpCost{sigops_cost},
m_modified_fee{nFee},
lockPoints{lp},
nSizeWithDescendants{GetTxSize()},
nModFeesWithDescendants{nFee},
@ -108,11 +101,11 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& tx, CAmount fee,
discountSizeWithAncestors{GetDiscountTxSize()},
setPeginsSpent(_setPeginsSpent) {}
void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta)
void CTxMemPoolEntry::UpdateModifiedFee(CAmount fee_diff)
{
nModFeesWithDescendants += newFeeDelta - feeDelta;
nModFeesWithAncestors += newFeeDelta - feeDelta;
feeDelta = newFeeDelta;
nModFeesWithDescendants = SaturatingAdd(nModFeesWithDescendants, fee_diff);
nModFeesWithAncestors = SaturatingAdd(nModFeesWithAncestors, fee_diff);
m_modified_fee = SaturatingAdd(m_modified_fee, fee_diff);
}
void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp)
@ -467,7 +460,7 @@ void CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, CAmount modifyFe
{
nSizeWithDescendants += modifySize;
assert(int64_t(nSizeWithDescendants) > 0);
nModFeesWithDescendants += modifyFee;
nModFeesWithDescendants = SaturatingAdd(nModFeesWithDescendants, modifyFee);
nCountWithDescendants += modifyCount;
assert(int64_t(nCountWithDescendants) > 0);
}
@ -476,7 +469,7 @@ void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee,
{
nSizeWithAncestors += modifySize;
assert(int64_t(nSizeWithAncestors) > 0);
nModFeesWithAncestors += modifyFee;
nModFeesWithAncestors = SaturatingAdd(nModFeesWithAncestors, modifyFee);
nCountWithAncestors += modifyCount;
assert(int64_t(nCountWithAncestors) > 0);
nSigOpCostWithAncestors += modifySigOps;
@ -519,8 +512,10 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces
// into mapTx.
CAmount delta{0};
ApplyDelta(entry.GetTx().GetHash(), delta);
// The following call to UpdateModifiedFee assumes no previous fee modifications
Assume(entry.GetFee() == entry.GetModifiedFee());
if (delta) {
mapTx.modify(newit, update_fee_delta(delta));
mapTx.modify(newit, [&delta](CTxMemPoolEntry& e) { e.UpdateModifiedFee(delta); });
}
// Update cachedInnerUsage to include contained transaction's usage.
@ -1029,10 +1024,10 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeD
{
LOCK(cs);
CAmount &delta = mapDeltas[hash];
delta += nFeeDelta;
delta = SaturatingAdd(delta, nFeeDelta);
txiter it = mapTx.find(hash);
if (it != mapTx.end()) {
mapTx.modify(it, update_fee_delta(delta));
mapTx.modify(it, [&nFeeDelta](CTxMemPoolEntry& e) { e.UpdateModifiedFee(nFeeDelta); });
// Now update all ancestors' modified fees with descendants
setEntries setAncestors;
uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();

View file

@ -102,7 +102,7 @@ private:
const unsigned int entryHeight; //!< Chain height when entering the mempool
const bool spendsCoinbase; //!< keep track of transactions that spend a coinbase
const int64_t sigOpCost; //!< Total sigop cost
int64_t feeDelta{0}; //!< Used for determining the priority of the transaction for mining in a block
CAmount m_modified_fee; //!< Used for determining the priority of the transaction for mining in a block
LockPoints lockPoints; //!< Track the height and time at which tx was final
// Information about descendants of this transaction that are in the
@ -135,7 +135,7 @@ public:
std::chrono::seconds GetTime() const { return std::chrono::seconds{nTime}; }
unsigned int GetHeight() const { return entryHeight; }
int64_t GetSigOpCost() const { return sigOpCost; }
int64_t GetModifiedFee() const { return nFee + feeDelta; }
CAmount GetModifiedFee() const { return m_modified_fee; }
size_t DynamicMemoryUsage() const { return nUsageSize; }
const LockPoints& GetLockPoints() const { return lockPoints; }
@ -143,9 +143,8 @@ public:
void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
// Adjusts the ancestor state
void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps, int64_t discountSize);
// Updates the fee delta used for mining priority score, and the
// modified fees with descendants.
void UpdateFeeDelta(int64_t feeDelta);
// Updates the modified fees with descendants/ancestors.
void UpdateModifiedFee(CAmount fee_diff);
// Update the LockPoints after a reorg
void UpdateLockPoints(const LockPoints& lp);

View file

@ -6,6 +6,7 @@
#define BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
#include <cstdint>
#include <memory>
#include <string>

View file

@ -7,6 +7,8 @@
#include <zmq/zmqabstractnotifier.h>
#include <cstdint>
class CBlockIndex;
class CZMQAbstractPublishNotifier : public CZMQAbstractNotifier

View file

@ -29,7 +29,7 @@ don't have test cases for.
- Avoid wildcard imports
- Use a module-level docstring to describe what the test is testing, and how it
is testing it.
- When subclassing the BitcoinTestFramwork, place overrides for the
- When subclassing the BitcoinTestFramework, place overrides for the
`set_test_params()`, `add_options()` and `setup_xxxx()` methods at the top of
the subclass, then locally-defined helper methods, then the `run_test()` method.
- Use `'{}'.format(x)` for string formatting, not `'%s' % x`.

View file

@ -154,7 +154,7 @@ class BlockSignTest(BitcoinTestFramework):
result = miner.combineblocksigs(block, sigs, self.witnessScript)
sigs = sigs + self.nodes[i].signblock(block, self.witnessScript)
assert_equal(result["complete"], i >= self.required_signers)
# submitting should have no effect pre-threshhold
# submitting should have no effect pre-threshold
if i < self.required_signers:
miner.submitblock(result["hex"])
self.check_height(blockcount)

File diff suppressed because one or more lines are too long

View file

@ -290,7 +290,7 @@ class TapHashPeginTest(BitcoinTestFramework):
# Test introspection opcodes
# 1a. No Pegins/issuances
self.log.info("Instrospection tests: outpoint flag")
self.log.info("Introspection tests: outpoint flag")
self.tapscript_satisfy_test(CScript([OP_0, OP_INSPECTINPUTOUTPOINT, b'\x00', OP_EQUALVERIFY, OP_DROP, OP_DROP, OP_1]))
# 1b. Add a pegin (Test pegin input must be 0x40)
self.tapscript_satisfy_test(CScript([OP_0, OP_INSPECTINPUTOUTPOINT, b'\x40', OP_EQUALVERIFY, OP_DROP, OP_DROP, OP_1]), add_pegin=True)
@ -304,7 +304,7 @@ class TapHashPeginTest(BitcoinTestFramework):
self.tapscript_satisfy_test(CScript([OP_0, OP_INSPECTINPUTOUTPOINT, b'\x00', OP_EQUALVERIFY, OP_DROP, OP_DROP, OP_1]), add_pegin = True, add_issuance=True, fail="Script failed an OP_EQUALVERIFY operation")
# Test opcode for inspecting prev tx
self.log.info("Instrospection tests: inputs")
self.log.info("Introspection tests: inputs")
self.tapscript_satisfy_test(CScript([OP_0, OP_INSPECTINPUTOUTPOINT, b'\x00', OP_EQUALVERIFY, OP_TOALTSTACK, OP_EQUALVERIFY, OP_FROMALTSTACK, OP_EQUAL]), add_prevout=True)
# Test taproot asset with blinding.
@ -351,12 +351,12 @@ class TapHashPeginTest(BitcoinTestFramework):
self.tapscript_satisfy_test(CScript([-1, OP_1, OP_INSPECTINPUTVALUE, OP_FALSE, OP_EQUAL]), fail="Introspection index out of bounds")
# Test current input
self.log.info("Instrospection tests: current input index")
self.log.info("Introspection tests: current input index")
self.tapscript_satisfy_test(CScript([OP_PUSHCURRENTINPUTINDEX, OP_0, OP_EQUAL]))
self.tapscript_satisfy_test(CScript([OP_PUSHCURRENTINPUTINDEX, OP_1, OP_EQUAL]), fail="Script evaluated without error but finished with a false/empty top stack element")
# Test Outputs
self.log.info("Instrospection tests: outputs")
self.log.info("Introspection tests: outputs")
for blind in [True, False]:
for out_pos in [0, 1]:
self.tapscript_satisfy_test(CScript([out_pos, OP_INSPECTOUTPUTASSET, OP_TOALTSTACK, OP_EQUALVERIFY, OP_FROMALTSTACK, OP_EQUAL]), blind=blind, add_out_asset=out_pos)
@ -368,8 +368,8 @@ class TapHashPeginTest(BitcoinTestFramework):
self.tapscript_satisfy_test(CScript([120, OP_INSPECTOUTPUTASSET, OP_FALSE, OP_EQUAL]), fail="Introspection index out of bounds")
self.tapscript_satisfy_test(CScript([-1, OP_INSPECTOUTPUTVALUE, OP_FALSE, OP_EQUAL]), fail="Introspection index out of bounds")
# Finally, check the tx instrospection
self.log.info("Instrospection tests: tx")
# Finally, check the tx introspection
self.log.info("Introspection tests: tx")
# Test version equality
self.tapscript_satisfy_test(CScript([OP_INSPECTVERSION, int(2).to_bytes(4, 'little'), OP_EQUAL]), ver = 2)
self.tapscript_satisfy_test(CScript([OP_INSPECTVERSION, int(5).to_bytes(4, 'little'), OP_EQUAL]), ver = 2, fail="Script evaluated without error but finished with a false/empty top stack element")

View file

@ -261,6 +261,10 @@ class PSBTTest(BitcoinTestFramework):
decoded = self.nodes[1].decodepsbt(walletsignpsbt_out['psbt'])
assert 'non_witness_utxo' in decoded['inputs'][0]
assert 'witness_utxo' in decoded['inputs'][0]
if 'asset' in decoded['inputs'][0]['witness_utxo']:
assert_equal(decoded['inputs'][0]['witness_utxo']['asset'], 'b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23')
else:
assert 'assetcommitment' in decoded['inputs'][0]['witness_utxo']
# Check decodepsbt fee calculation (input values shall only be counted once per UTXO)
#assert_equal(decoded['fee'], created_psbt['fee']) # ELEMENTS: we do not have this field. Should be fixed by #900
assert_equal(walletsignpsbt_out['complete'], True)

View file

@ -29,3 +29,4 @@ xwindows
te
ligh
atack
lsat

View file

@ -15,7 +15,7 @@ if ! command -v codespell > /dev/null; then
fi
IGNORE_WORDS_FILE=test/lint/lint-spelling.ignore-words.txt
mapfile -t FILES < <(git ls-files -- ":(exclude)build-aux/m4/" ":(exclude)contrib/seeds/*.txt" ":(exclude)depends/" ":(exclude)doc/release-notes/" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/qt/locale/" ":(exclude)src/qt/*.qrc" ":(exclude)src/secp256k1/" ":(exclude)src/minisketch/" ":(exclude)src/univalue/" ":(exclude)contrib/builder-keys/keys.txt" ":(exclude)contrib/guix/patches")
mapfile -t FILES < <(git ls-files -- ":(exclude)build-aux/m4/" ":(exclude)contrib/seeds/*.txt" ":(exclude)depends/" ":(exclude)doc/release-notes/" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/qt/locale/" ":(exclude)src/qt/*.qrc" ":(exclude)src/secp256k1/" ":(exclude)src/minisketch/" ":(exclude)src/univalue/" ":(exclude)contrib/builder-keys/keys.txt" ":(exclude)contrib/guix/patches") ":(exclude)src/simplicity/"
if ! codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=${IGNORE_WORDS_FILE} "${FILES[@]}"; then
echo "^ Warning: codespell identified likely spelling errors. Any false positives? Add them to the list of ignored words in ${IGNORE_WORDS_FILE}"
fi

View file

@ -1,10 +1,10 @@
# -fsanitize=undefined suppressions
# =================================
# This would be `signed-integer-overflow:CTxMemPool::PrioritiseTransaction`,
# The suppressions would be `sanitize-type:ClassName::MethodName`,
# however due to a bug in clang the symbolizer is disabled and thus no symbol
# names can be used.
# See https://github.com/google/sanitizers/issues/1364
signed-integer-overflow:txmempool.cpp
# https://github.com/bitcoin/bitcoin/pull/21798#issuecomment-829180719
signed-integer-overflow:policy/feerate.cpp
@ -79,5 +79,24 @@ implicit-integer-sign-change:blech32.cpp
implicit-integer-sign-change:primitives/block.h
implicit-integer-sign-change:primitives/confidential.cpp
implicit-integer-sign-change:primitives/confidential.h
shift-base:simplicity/jets.c
unsigned-integer-overflow:simplicity/jets.c
implicit-unsigned-integer-truncation:simplicity/jets.c
shift-base:simplicity/sha256.c
unsigned-integer-overflow:simplicity/sha256.c
unsigned-integer-overflow:simplicity/secp256k1/modinv64_impl.h
implicit-integer-sign-change:simplicity/secp256k1/modinv64_impl.h
implicit-unsigned-integer-truncation:simplicity/secp256k1/modinv64_impl.h
shift-base:simplicity/secp256k1/modinv64_impl.h
shift-base:simplicity/secp256k1/field_5x52_impl.h
unsigned-integer-overflow:simplicity/secp256k1/field_5x52_impl.h
shift-base:simplicity/secp256k1/scalar_4x64_impl.h
implicit-unsigned-integer-truncation:simplicity/secp256k1/scalar_4x64_impl.h
unsigned-integer-overflow:simplicity/secp256k1/scalar_4x64_impl.h
# This one, in secp256k1_ge_table_set_globalz, looks dangerous (len - 1 with
# len = 0) but is ok since the rest of the function is guarded on len > 0.
unsigned-integer-overflow:simplicity/secp256k1/group_impl.h
# This one involves careful roconnor code
shift-base:simplicity/frame.c
# See comment in simplicity/primitive/elements/env.c line 303
unsigned-integer-overflow:simplicity/primitive/elements/env.c