-
Notifications
You must be signed in to change notification settings - Fork 1
GenerateToMany: custom outputs scripts split + equal split of the remainder #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: generatetomany
Are you sure you want to change the base?
GenerateToMany: custom outputs scripts split + equal split of the remainder #1
Conversation
polespinasa
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I'm not wrong this doesn't allow an address to be added with a fixed input + reminder. Should be focused that way imo.
This is the use case supertestnet referred to, and in this case you'd want to specify a fixed amount for some addresses, and then split the remaining block reward to other addresses if I am not missing anything. |
That's just the example he gives but a user could want to do something else. We shouldn't limit it this way. |
|
@polespinasa I think this is closer to what you had envisioned. |
9143274 to
5a5ff2a
Compare
Can you please squash commits so it's easier to check the code? Also, I think this will have to be rebased based on this review bitcoin#32468 (comment) |
39028d7 to
551f5a2
Compare
|
Rebased on your new "RPC centric" approach. |
cd8c13c to
8b5dd8a
Compare
|
@lollerfirst seems that we're moving it to Would you like to continue working on the fee collector part and rebase it or should I do it? |
|
@polespinasa Yes will rebase. |
4ff4e01 to
2c85569
Compare
f426866 to
d89b900
Compare
67dc752 cmake, test: Disable tests instead of ignoring them (Hennadii Stepanov) bb9157d cmake, refactor: Switch to `Python3::Interpreter` imported target (Hennadii Stepanov) Pull request description: This PR: 1. Switches to a modern CMake approach by using the `Python3::Interpreter` imported target, which is more robust than using variables. 2. Disables the `util_rpcauth_test` test explicitly instead of silently ignoring it. A build and test log for the case when Python is unavailable is provided below: ``` $ cmake -B build $ cmake --build build -j 16 $ ctest --test-dir build -j $(nproc) -R "^util" Internal ctest changing into directory: /bitcoin/build Test project /bitcoin/build Start 115: util_tests Start 117: util_trace_tests Start 114: util_string_tests Start 116: util_threadnames_tests Start 1: util_rpcauth_test 1/5 Test #1: util_rpcauth_test ................***Not Run (Disabled) 0.00 sec 2/5 Test bitcoin#114: util_string_tests ................ Passed 0.11 sec 3/5 Test bitcoin#117: util_trace_tests ................. Passed 0.11 sec 4/5 Test bitcoin#116: util_threadnames_tests ........... Passed 0.11 sec 5/5 Test bitcoin#115: util_tests ....................... Passed 0.13 sec 100% tests passed, 0 tests failed out of 4 Total Test time (real) = 0.13 sec The following tests did not run: 1 - util_rpcauth_test (Disabled) ``` ACKs for top commit: purpleKarrot: ACK 67dc752 janb84: tACK 67dc752 Tree-SHA512: 5fc7ebe31ac03f4b8a53ecfcfc1cace0f647a1d2c989651988edae96bdfbbe2dee171714e57cb028e65ead1bb40806a82d9821746451dbf005538601fd33ea88
…xec in RunCommandJSON" faa1c3e Revert "Merge bitcoin#32343: common: Close non-std fds before exec in RunCommandJSON" (MarcoFalke) Pull request description: After a fork() in a multithreaded program, the child can safely call only async-signal-safe functions (see [signal-safety(7)](https://www.man7.org/linux/man-pages/man7/signal-safety.7.html)) until such time as it calls execv. The standard library (`std` namespace) is not async-signal-safe. Also, `throw`, isn't. There was an alternative implementation using `readdir` (bitcoin#32529), but that isn't async-signal-safe either, and that implementation was still using `throw`. So temporarily revert this feature. A follow-up in the future can add it back, using only async-signal-safe functions, or by using a different approach. Fixes bitcoin#32524 Fixes bitcoin#33015 Fixes bitcoin#32855 For reference, a failure can manifest in the GCC debug mode: * While `fork`ing, a debug mode mutex is held (by any other thread). * The `fork`ed child tries to use the stdard libary before `execv` and deadlocks. This may look like the following: ``` (gdb) thread apply all bt Thread 1 (Thread 0xf58f4b40 (LWP 774911) "b-httpworker.2"): #0 0xf7f4f589 in __kernel_vsyscall () #1 0xf79e467e in ?? () from /lib32/libc.so.6 #2 0xf79eb582 in pthread_mutex_lock () from /lib32/libc.so.6 #3 0xf7d93bf2 in ?? () from /lib32/libstdc++.so.6 bitcoin#4 0xf7d93f36 in __gnu_debug::_Safe_iterator_base::_M_attach(__gnu_debug::_Safe_sequence_base*, bool) () from /lib32/libstdc++.so.6 bitcoin#5 0x5668810a in __gnu_debug::_Safe_iterator_base::_Safe_iterator_base (this=0xf58f13ac, __seq=0xf58f13f8, __constant=false) at /bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/debug/safe_base.h:91 bitcoin#6 0x56ddfb50 in __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<int*, std::__cxx1998::vector<int, std::allocator<int> > >, std::__debug::vector<int, std::allocator<int> >, std::forward_iterator_tag>::_Safe_iterator (this=0xf58f13a8, __i=3, __seq=0xf58f13f8) at /bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/debug/safe_iterator.h:162 bitcoin#7 0x56ddfacb in __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<int*, std::__cxx1998::vector<int, std::allocator<int> > >, std::__debug::vector<int, std::allocator<int> >, std::bidirectional_iterator_tag>::_Safe_iterator (this=0xf58f13a8, __i=3, __seq=0xf58f13f8) at /bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/debug/safe_iterator.h:539 bitcoin#8 0x56ddfa5b in __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<int*, std::__cxx1998::vector<int, std::allocator<int> > >, std::__debug::vector<int, std::allocator<int> >, std::random_access_iterator_tag>::_Safe_iterator (this=0xf58f13a8, __i=3, __seq=0xf58f13f8) at /bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/debug/safe_iterator.h:687 bitcoin#9 0x56ddd3f6 in std::__debug::vector<int, std::allocator<int> >::begin (this=0xf58f13f8) at /bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/debug/vector:300 bitcoin#10 0x57d83701 in subprocess::detail::Child::execute_child (this=0xf58f156c) at ./util/subprocess.h:1372 bitcoin#11 0x57d80a7c in subprocess::Popen::execute_process (this=0xf58f1cd8) at ./util/subprocess.h:1231 bitcoin#12 0x57d6d2b4 in subprocess::Popen::Popen<subprocess::input, subprocess::output, subprocess::error, subprocess::close_fds> (this=0xf58f1cd8, cmd_args="fake.py enumerate", args=..., args=..., args=..., args=...) at ./util/subprocess.h:964 bitcoin#13 0x57d6b597 in RunCommandParseJSON (str_command="fake.py enumerate", str_std_in="") at ./common/run_command.cpp:27 bitcoin#14 0x57a90547 in ExternalSigner::Enumerate (command="fake.py", signers=std::__debug::vector of length 0, capacity 0, chain="regtest") at ./external_signer.cpp:28 bitcoin#15 0x56defdab in enumeratesigners()::$_0::operator()(RPCHelpMan const&, JSONRPCRequest const&) const (this=0xf58f2ba0, self=..., request=...) at ./rpc/external_signer.cpp:51 ... (truncated, only one thread exists) ``` ACKs for top commit: fanquake: ACK faa1c3e darosior: ACK faa1c3e Tree-SHA512: 602da5f2eba08d7fe01ba19baf411e287ae27fe2d4b82f41734e05b7b1d938ce94cc0041e86ba677284fa92838e96ebee687023ff28047e2b036fd9a53567e0a
The `-assumevalid` option skips script verification for a specified block and all its ancestors during Initial Block Download. Many new users are surprised when this suddenly slows their node to a halt. This commit adds a log message to clearly indicate when this optimization ends and full validation begins (and vice versa). When using `-assumeutxo`, logging is suppressed for the active assumed-valid chainstate and for the background validation chainstate to avoid the confusing toggles. ------- > cmake -B build && cmake --build build && mkdir -p demo && build/bin/bitcoind -datadir=demo -stopatheight=500 | grep 'signature validation' ``` 2025-08-08T20:59:21Z Disabling signature validations at block #1 (00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048). 2025-08-08T20:59:21Z Enabling signature validations at block bitcoin#100 (000000007bc154e0fa7ea32218a72fe2c1bb9f86cf8c9ebf9a715ed27fdb229a). 2025-08-08T20:59:21Z Disabling signature validations at block bitcoin#200 (000000008f1a7008320c16b8402b7f11e82951f44ca2663caf6860ab2eeef320). 2025-08-08T20:59:21Z Enabling signature validations at block bitcoin#300 (0000000062b69e4a2c3312a5782d7798b0711e9ebac065cd5d19f946439f8609). ```
…hange fab2980 assumevalid: log every script validation state change (Lőrinc) Pull request description: The `-assumevalid` option skips script verification for a specified block and all its ancestors during Initial Block Download. Many new [users are surprised](bitcoin#32832) when this suddenly slows their node to a halt. This commit adds a log message to clearly indicate when this optimization ends and full validation begins (and vice versa). <details> <summary>Testing instructions</summary> The behavior can easily be tested by adding this before the new log: ```C++ // TODO hack to enable/disable script checks based on block height for testing purposes if (pindex->nHeight < 100) fScriptChecks = false; else if (pindex->nHeight < 200) fScriptChecks = true; else if (pindex->nHeight < 300) fScriptChecks = false; else if (pindex->nHeight < 400) fScriptChecks = true; ``` and exercise the new code with: ```bash cmake -B build && cmake --build build && mkdir -p demo && build/bin/bitcoind -datadir=demo -stopatheight=500 | grep 'signature validation' ``` showing something like: * Disabling signature validations at block #1 (00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048). * Enabling signature validations at block bitcoin#100 (000000007bc154e0fa7ea32218a72fe2c1bb9f86cf8c9ebf9a715ed27fdb229a). * Disabling signature validations at block bitcoin#200 (000000008f1a7008320c16b8402b7f11e82951f44ca2663caf6860ab2eeef320). * Enabling signature validations at block bitcoin#300 (0000000062b69e4a2c3312a5782d7798b0711e9ebac065cd5d19f946439f8609). </details> ACKs for top commit: achow101: ACK fab2980 ajtowns: crACK fab2980 davidgumberg: untested crACK bitcoin@fab2980 Tree-SHA512: e90b66f7423b639356daace476942ce83e65e70466544394cbe2f15738bdbf716163eaf590c64c5448f9b41aeeaafe3342c48c6a7a478678a70b0310ca94e11d
912d9cb to
847fd39
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I couldn't review earlier :(
This has to be rebased again, there were merge conflicts with Core Master Branch.
The rebase of the original PR bitcoin#32468 broke one test for some reason I don't understand. Checking it is appreciated :)
adc76f7 to
ae33a56
Compare
ae33a56 to
0d55bc4
Compare
9d30e01 to
b3538dd
Compare
polespinasa
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Half reviewed, will continue soon. Looks good for the moment.
| "If only one output is desired a simple address or descriptor can be provided without using JSON format", | ||
| { | ||
| {"output", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A valid address or descriptor"}, | ||
| {"address_or_descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The address or descriptor"}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this set to Optional::NO? It should be OMITTED and fallback to OP_RETURN if not specified.
| [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue | ||
| { | ||
| UniValue address_or_descriptor = UniValue(UniValue::VARR); | ||
| std::vector<std::pair<std::string, CAmount>> aod_to_amount; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: aod is not clear without context. I would use address_or_descriptor or just use a generic name like destination
| if (!request.params[0].isNull() && parsed.read(request.params[0].get_str())) { | ||
| if (!parsed.isArray()) { | ||
| if (parsed.isArray()) { | ||
| for (std::size_t i = 0; i < parsed.size(); ++i) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest adding a comment here explaining what are we doing. It's not really clear just reading the code. Maybe something like:
// If a list of addresses or descriptor is provided, add the destination and the amount, if a single address is provided add amount 0.
polespinasa
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's looking great!
Left some comments with nits and possible improvements.
| if (!getScriptFromDescriptor(address_or_descriptor[i].get_str(), coinbase_output_script, error)) { | ||
| const auto destination = DecodeDestination(address_or_descriptor[i].get_str()); | ||
| for (const auto& aod : aod_to_amount) { | ||
| const auto [script_or_descriptor, reward_split] = aod; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the need for this? you can just use aod. Although the variable needs a better name following the contributing guide. https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md
| for (const auto& aod : aod_to_amount) { | ||
| const auto [script_or_descriptor, reward_split] = aod; | ||
| CScript temp_script_from_descriptor; | ||
| if (reward_split < 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be checked before (to avoid running useless code). For example before line 353
b3538dd#diff-ccc24453c13307f815879738d3bf00eec351417537fbf10dde1468180cacd2f1R353
| if (reward_split < 0) { | ||
| throw JSONRPCError(RPC_INVALID_PARAMETER, "Error: Parted reward amount cannot be negative"); | ||
| } | ||
| if (!getScriptFromDescriptor(script_or_descriptor, temp_script_from_descriptor, error)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same for this checks. I think the two loops could be done in one. You don't need to iterate the same items twice, just parse them in the first place directly.
| CAmount total_reward = block.vtx[0]->vout[0].nValue; | ||
| CAmount reward_parted = total_reward / num_outputs; | ||
| CAmount remainder = total_reward % num_outputs; | ||
| CAmount total_unassigned_reward = block.vtx[0]->vout[0].nValue - total_assigned_reward; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's something with the variable names that don't convince me, but I'm unable to suggest new names :/
| size_t i = 0; | ||
| for (const auto& coinbase_output_script : coinbase_outputs_scripts) { | ||
| CAmount out_reward = coinbase_output_script.second | ||
| + ((i++) < static_cast<size_t>(remainder) ? unassigned_reward_parted + 1 : unassigned_reward_parted); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like ternary operations but this is confusing. I think is more clean to show that there's no remainder left than using an aux variable i.
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 1c0db4d35d..27ae6045e7 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -459,10 +459,11 @@ static RPCHelpMan generateblock()
}
mutable_coinbase.vout.clear();
- size_t i = 0;
for (const auto& coinbase_output_script : coinbase_outputs_scripts) {
- CAmount out_reward = coinbase_output_script.second
- + ((i++) < static_cast<size_t>(remainder) ? unassigned_reward_parted + 1 : unassigned_reward_parted);
+ CAmount out_reward = coinbase_output_script.second + unassigned_reward_parted;
+ if (remainder > 0) {
+ out_reward++;
+ remainder--;
CTxOut new_tx_out(out_reward, coinbase_output_script.first);
mutable_coinbase.vout.push_back(new_tx_out);
}
| self.log.info('Generate an empty block to a list of addresses and custom reward split') | ||
| address2 = miniwallet.get_address() | ||
| address3 = miniwallet.get_address() | ||
| hash = self.generateblock(node, outputs=json.dumps([{address: 100000000}, {address2: 0}, {address3: 0}]), transactions=[])['hash'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the test is good but we should add some other address with a reward, not only address1 and then all the others 0. Maybe give 3 a reward?
| assert_equal(block['tx'][0]['vout'][2]['scriptPubKey']['address'], address3) | ||
| assert_equal(block['tx'][0]['vout'][0]['value'], Decimal('9.00000000')) | ||
| assert_equal(block['tx'][0]['vout'][1]['value'], Decimal('8.00000000')) | ||
| assert_equal(block['tx'][0]['vout'][2]['value'], Decimal('8.00000000')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two more test cases should be added.
We must check that we cannot add more rewards than the max block reward and that we cannot assign negative rewards. (Basically assert that the JSONRPC errors are thrown)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
ee72e34 to
30244fb
Compare
|
Hey are you still working on this? @a1denvalu3 |
… corruption check in fees.dat fa1d17d refactor: Use uint64_t over size_t for serialize corruption check in fees.dat (MarcoFalke) Pull request description: Serialization should not behave differently on different architectures. See also the related commit 3789215. However, on fees.dat file corruption, 32-bit builds may run into an unsigned integer overflow and report the wrong corruption reason, or may even silently continue after the corruption. This is a bit hard to reproduce, because 32-bit platforms are rare and most of them don't support running the unsigned integer overflow sanitizer. So the possible options to reproduce are: * Run on armhf and manually annotate the code to detect the overflow * Run on i386 with the integer sanitizer (possibly via `podman run -it --rm --platform linux/i386 'debian:trixie'`) * Run the integer sanitizer on any 64-bit platform and manually replace type in the affected line by `uint32_t` Afterwards, the steps to reproduce are: ``` export DEBIAN_FRONTEND=noninteractive && apt update && apt install curl wget htop git vim ccache -y && git clone https://github.com/bitcoin/bitcoin.git --depth=1 ./b-c && cd b-c && apt install build-essential cmake pkg-config python3-zmq libzmq3-dev libevent-dev libboost-dev libsqlite3-dev systemtap-sdt-dev libcapnp-dev capnproto libqrencode-dev qt6-tools-dev qt6-l10n-tools qt6-base-dev clang llvm libc++-dev libc++abi-dev -y cmake -B ./bld-cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER='clang' -DCMAKE_CXX_COMPILER='clang++' -DSANITIZERS=undefined,integer,float-divide-by-zero --preset=dev-mode cmake --build ./bld-cmake --parallel $(nproc) curl -fLO 'https://github.com/bitcoin-core/qa-assets/raw/b5ad78e070e4cf36beb415d7b490d948d70ba73f/fuzz_corpora/policy_estimator_io/607473137013139e3676e30ec4b29639e673fa9b' UBSAN_OPTIONS="suppressions=$(pwd)/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1" FUZZ=policy_estimator_io ./bld-cmake/bin/fuzz ./607473137013139e3676e30ec4b29639e673fa9b ``` The output will be something like: ``` /b-c/src/policy/fees/block_policy_estimator.cpp:448:25: runtime error: unsigned integer overflow: 346685954 * 219 cannot be represented in type 'unsigned int' #0 0x5b0b1bbe in TxConfirmStats::Read(AutoFile&, unsigned int) /b-c/bld-cmake/src/./policy/fees/block_policy_estimator.cpp:448:25 #1 0x5b0b7d3f in CBlockPolicyEstimator::Read(AutoFile&) /b-c/bld-cmake/src/./policy/fees/block_policy_estimator.cpp:1037:29 #2 0x592a9783 in policy_estimator_io_fuzz_target(std::span<unsigned char const, 4294967295u>) /b-c/bld-cmake/src/test/fuzz/./test/fuzz/policy_estimator_io.cpp:32:32 #3 0x5896ba8e in void std::__invoke_impl<void, void (*&)(std::span<unsigned char const, 4294967295u>), std::span<unsigned char const, 4294967295u>>(std::__invoke_other, void (*&)(std::span<unsigned char const, 4294967295u>), std::span<unsigned char const, 4294967295u>&&) /usr/lib/gcc/i686-linux-gnu/14/../../../../include/c++/14/bits/invoke.h:61:14 bitcoin#4 0x5896b8eb in std::enable_if<is_invocable_r_v<void, void (*&)(std::span<unsigned char const, 4294967295u>), std::span<unsigned char const, 4294967295u>>, void>::type std::__invoke_r<void, void (*&)(std::span<unsigned char const, 4294967295u>), std::span<unsigned char const, 4294967295u>>(void (*&)(std::span<unsigned char const, 4294967295u>), std::span<unsigned char const, 4294967295u>&&) /usr/lib/gcc/i686-linux-gnu/14/../../../../include/c++/14/bits/invoke.h:111:2 bitcoin#5 0x5896b44b in std::_Function_handler<void (std::span<unsigned char const, 4294967295u>), void (*)(std::span<unsigned char const, 4294967295u>)>::_M_invoke(std::_Any_data const&, std::span<unsigned char const, 4294967295u>&&) /usr/lib/gcc/i686-linux-gnu/14/../../../../include/c++/14/bits/std_function.h:290:9 bitcoin#6 0x59845c95 in std::function<void (std::span<unsigned char const, 4294967295u>)>::operator()(std::span<unsigned char const, 4294967295u>) const /usr/lib/gcc/i686-linux-gnu/14/../../../../include/c++/14/bits/std_function.h:591:9 bitcoin#7 0x5983a0da in test_one_input(std::span<unsigned char const, 4294967295u>) /b-c/bld-cmake/src/test/fuzz/util/./test/fuzz/fuzz.cpp:88:5 bitcoin#8 0x5983cb80 in main /b-c/bld-cmake/src/test/fuzz/util/./test/fuzz/fuzz.cpp:271:13 bitcoin#9 0xf75aecc2 (/lib/i386-linux-gnu/libc.so.6+0x24cc2) (BuildId: 2dc5f2945fad35c1b07d1a5a32520b3c41afaa75) bitcoin#10 0xf75aed87 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x24d87) (BuildId: 2dc5f2945fad35c1b07d1a5a32520b3c41afaa75) bitcoin#11 0x58932db6 in _start (/b-c/bld-cmake/bin/fuzz+0x235ddb6) (BuildId: 7d8d83a77923f14e99c0de64acbc5f5bfc2cce9b) SUMMARY: UndefinedBehaviorSanitizer: unsigned-integer-overflow /b-c/src/policy/fees/block_policy_estimator.cpp:448:25 ``` Note: This is marked a "refactor", because the code change does not affect 64-bit builds, and on the still remaining rare 32-bit builds today it is extremely unlikely to happen in production. ACKs for top commit: bensig: ACK fa1d17d ismaelsadeeq: utACK fa1d17d luke-jr: Also, utACK fa1d17d as an improvement. Tree-SHA512: 696bf8e0dbe4777c84cb90e313c7f8f9ee90d4b3e64de1222f8472b2d9d0f3a0f6f027fda743dd6ca8c6aab94f404db7a65bb562a76000d9c33a8a39de28d8d4
Can assign a custom amount split to every output or "remainder" to indicate that said output should be assigned an equal split of whatever is left.
In the case the custom splits exceed the block reward, throw a runtime error.