Skip to content

Commit 4b6638a

Browse files
authored
Merge pull request #4251 from stacks-network/feat/merge-master-to-develop-20240117
Merge master to develop
2 parents e6dac0a + 9012cf7 commit 4b6638a

35 files changed

+3695
-247
lines changed

.github/workflows/bitcoin-tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ jobs:
6868
- tests::neon_integrations::test_problematic_microblocks_are_not_relayed_or_stored
6969
- tests::neon_integrations::test_problematic_txs_are_not_stored
7070
- tests::neon_integrations::use_latest_tip_integration_test
71+
- tests::neon_integrations::min_txs
7172
- tests::should_succeed_handling_malformed_and_valid_txs
7273
steps:
7374
## Setup test environment

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to the versioning scheme outlined in the [README.md](README.md).
77

8+
## [2.4.0.0.5]
9+
10+
This introduces a set of improvements to the Stacks miner behavior. In
11+
particular:
12+
* The VRF public key can be re-used across node restarts.
13+
* Settings that affect mining are hot-reloaded from the config file. They take
14+
effect once the file is updated; there is no longer a need to restart the
15+
node.
16+
* The act of changing the miner settings in the config file automatically
17+
triggers a subsequent block-build attempt, allowing the operator to force the
18+
miner to re-try building blocks.
19+
* This adds a new tip-selection algorithm that minimizes block orphans within a
20+
configurable window of time.
21+
* When configured, the node will automatically stop mining if it is not achieving a
22+
targeted win rate over a configurable window of blocks.
23+
* When configured, the node will selectively mine transactions from only certain
24+
addresses, or only of certain types (STX-transfers, contract-publishes,
25+
contract-calls).
26+
* When configured, the node will optionally only RBF block-commits if it can
27+
produce a block with strictly more transactions.
28+
829
## [2.4.0.0.4]
930

1031
This is a high-priority hotfix that addresses a bug in transaction processing which

CODE_OF_CONDUCT.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ Community leaders will follow these Community Impact Guidelines in determining t
7171

7272
**Consequence**: A permanent ban from any sort of public interaction within the community.
7373

74+
### Secret Code:
75+
The code to the contest is: BITCOINL2
76+
7477
## Attribution
7578

7679
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ You can observe the state machine in action locally by running:
6767

6868
```bash
6969
$ cd testnet/stacks-node
70-
$ cargo run --bin stacks-node -- start --config=./conf/testnet-follower-conf.toml
70+
$ cargo run --bin stacks-node -- start --config ./conf/testnet-follower-conf.toml
7171
```
7272

7373
_On Windows, many tests will fail if the line endings aren't `LF`. Please ensure that you are have git's `core.autocrlf` set to `input` when you clone the repository to avoid any potential issues. This is due to the Clarity language currently being sensitive to line endings._

clarity/src/vm/docs/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2001,7 +2001,7 @@ const DEFINE_TRAIT_API: DefineAPI = DefineAPI {
20012001
can implement a given trait and then have their contract identifier being passed as a function argument in order to be called
20022002
dynamically with `contract-call?`.
20032003
2004-
Traits are defined with a name, and a list functions, defined with a name, a list of argument types, and return type.
2004+
Traits are defined with a name, and a list of functions, where each function is defined with a name, a list of argument types, and a return type.
20052005
20062006
In Clarity 1, a trait type can be used to specify the type of a function parameter. A parameter with a trait type can
20072007
be used as the target of a dynamic `contract-call?`. A principal literal (e.g. `ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.foo`)
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Usage:
4+
This script is designed to be run from the command line. It takes one or more Bitcoin addresses
5+
and outputs the extracted block commit data for these addresses.
6+
7+
Example command line usage:
8+
python3 get_unconfirmed_block_commits.py [btcAddress1] [btcAddress2] ...
9+
"""
10+
11+
import requests
12+
import json
13+
import sys
14+
15+
def read_api_endpoint(url):
16+
"""
17+
Reads data from the specified API endpoint and returns the response.
18+
19+
Args:
20+
url (str): The API endpoint URL.
21+
22+
Returns:
23+
dict: JSON response from the API if successful, otherwise None.
24+
"""
25+
try:
26+
response = requests.get(url)
27+
response.raise_for_status() # Raise an exception for non-200 status codes
28+
return response.json() # Assuming a JSON response
29+
except requests.exceptions.RequestException as e:
30+
return None
31+
32+
def is_block_commit(txn):
33+
"""
34+
Determines whether a given transaction is a block commit.
35+
36+
Args:
37+
txn (dict): The transaction data.
38+
39+
Returns:
40+
bool: True if the transaction is a block commit, otherwise False.
41+
"""
42+
try:
43+
vout = txn['vout']
44+
45+
# Verify the number of recipients.
46+
assert(3 <= len(vout) <= 4)
47+
block_commit_txn = vout[0]
48+
to_stacker_txns = vout[1::2]
49+
50+
# Verify block commit.
51+
# TODO: Add more verification steps if necessary.
52+
assert(block_commit_txn['scriptpubkey_type'] == "op_return")
53+
54+
# Verify PoX Payouts.
55+
for to_stacker_txn in to_stacker_txns:
56+
# TODO: Add more verification steps if necessary.
57+
assert(to_stacker_txn['scriptpubkey_type'] != "op_return")
58+
59+
except (Exception, AssertionError):
60+
return False
61+
return True
62+
63+
MEMPOOL_TXN_API = "https://mempool.space/api/address/{btcAddress}/txs/mempool"
64+
def unconfirmed_block_commit_from_address(btcAddress):
65+
"""
66+
Fetches the first unconfirmed block commit for a given Bitcoin address.
67+
68+
Args:
69+
btcAddress (str): Bitcoin address.
70+
71+
Returns:
72+
dict: The first transaction that is a block commit.
73+
"""
74+
url = MEMPOOL_TXN_API.format(btcAddress=btcAddress)
75+
txns = read_api_endpoint(url)
76+
77+
# Return only the first block commit transaction. This is good enough for now.
78+
for txn in txns:
79+
if is_block_commit(txn):
80+
return txn
81+
82+
def extracted_block_commit_data(txn):
83+
"""
84+
Extracts data from a block commit transaction.
85+
86+
Args:
87+
txn (dict): Block commit transaction.
88+
89+
Returns:
90+
dict: Extracted data from the transaction, or None if extraction fails.
91+
"""
92+
try:
93+
vout_start = 1
94+
vout_end = len(txn['vout']) - 1
95+
spent_utxo = txn['vin'][0]
96+
return {
97+
'txid': txn['txid'],
98+
'burn': sum(pox_payout['value'] for pox_payout in txn['vout'][vout_start:vout_end]),
99+
'address': spent_utxo['prevout']['scriptpubkey_address'],
100+
'pox_addrs': [txn['vout'][i]['scriptpubkey'] for i in range(vout_start,vout_end)],
101+
'input_txid': spent_utxo['txid'],
102+
'input_index': spent_utxo['vout'],
103+
}
104+
except Exception as e:
105+
return None
106+
107+
def block_commit_data(btcAddresses):
108+
"""
109+
Fetches and extracts block commit data for a list of Bitcoin addresses.
110+
111+
Args:
112+
btcAddresses (list): List of Bitcoin addresses.
113+
114+
Returns:
115+
list: Extracted block commit data for each address.
116+
"""
117+
return [extracted_block_commit_data(unconfirmed_block_commit_from_address(btcAddress)) \
118+
for btcAddress in btcAddresses]
119+
120+
def main():
121+
"""
122+
Main function to run the script. Takes command line arguments as Bitcoin addresses.
123+
"""
124+
btc_addresses = sys.argv[1:]
125+
if not btc_addresses:
126+
print("No Bitcoin addresses provided. Please provide at least one address.")
127+
return
128+
129+
# Return the data by printing it to stdout.
130+
data = block_commit_data(btc_addresses)
131+
print(json.dumps([datum for datum in data if datum is not None], indent=1))
132+
133+
if __name__ == "__main__":
134+
main()

stackslib/src/burnchains/burnchain.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ impl BurnchainStateTransition {
297297
}
298298

299299
impl BurnchainSigner {
300-
#[cfg(test)]
300+
#[cfg(any(test, feature = "testing"))]
301301
pub fn mock_parts(
302302
hash_mode: AddressHashMode,
303303
num_sigs: usize,
@@ -311,7 +311,7 @@ impl BurnchainSigner {
311311
BurnchainSigner(repr)
312312
}
313313

314-
#[cfg(test)]
314+
#[cfg(any(test, feature = "testing"))]
315315
pub fn new_p2pkh(pubk: &StacksPublicKey) -> BurnchainSigner {
316316
BurnchainSigner::mock_parts(AddressHashMode::SerializeP2PKH, 1, vec![pubk.clone()])
317317
}

stackslib/src/chainstate/stacks/db/blocks.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6307,6 +6307,28 @@ impl StacksChainState {
63076307
query_row(&self.db(), sql, args).map_err(Error::DBError)
63086308
}
63096309

6310+
/// Get all possible canonical chain tips
6311+
pub fn get_stacks_chain_tips(&self, sortdb: &SortitionDB) -> Result<Vec<StagingBlock>, Error> {
6312+
let (consensus_hash, block_bhh) =
6313+
SortitionDB::get_canonical_stacks_chain_tip_hash(sortdb.conn())?;
6314+
let sql = "SELECT * FROM staging_blocks WHERE processed = 1 AND orphaned = 0 AND consensus_hash = ?1 AND anchored_block_hash = ?2";
6315+
let args: &[&dyn ToSql] = &[&consensus_hash, &block_bhh];
6316+
let Some(staging_block): Option<StagingBlock> =
6317+
query_row(&self.db(), sql, args).map_err(Error::DBError)?
6318+
else {
6319+
return Ok(vec![]);
6320+
};
6321+
self.get_stacks_chain_tips_at_height(staging_block.height)
6322+
}
6323+
6324+
/// Get all Stacks blocks at a given height
6325+
pub fn get_stacks_chain_tips_at_height(&self, height: u64) -> Result<Vec<StagingBlock>, Error> {
6326+
let sql =
6327+
"SELECT * FROM staging_blocks WHERE processed = 1 AND orphaned = 0 AND height = ?1";
6328+
let args: &[&dyn ToSql] = &[&u64_to_sql(height)?];
6329+
query_rows(&self.db(), sql, args).map_err(Error::DBError)
6330+
}
6331+
63106332
/// Get the parent block of `staging_block`.
63116333
pub fn get_stacks_block_parent(
63126334
&self,

stackslib/src/chainstate/stacks/miner.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ impl MinerStatus {
105105
pub fn get_spend_amount(&self) -> u64 {
106106
return self.spend_amount;
107107
}
108+
108109
pub fn set_spend_amount(&mut self, amt: u64) {
109110
self.spend_amount = amt;
110111
}

0 commit comments

Comments
 (0)