Skip to content

Commit 2d55dc9

Browse files
authored
Merge branch 'develop' into fix-duplicate-events-2810
2 parents 7e53a31 + ca523fb commit 2d55dc9

File tree

11 files changed

+273
-14
lines changed

11 files changed

+273
-14
lines changed

clarity/src/vm/docs/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2082,7 +2082,8 @@ type defined using `define-fungible-token`. The increased token balance is _not_
20822082
rather minted.
20832083
20842084
If a non-positive amount is provided to mint, this function returns `(err 1)`. Otherwise, on successfuly mint, it
2085-
returns `(ok true)`.
2085+
returns `(ok true)`. If this call would result in more supplied tokens than defined by the total supply in
2086+
`define-fungible-token`, then a `SupplyOverflow` runtime error is thrown.
20862087
",
20872088
example: "
20882089
(define-fungible-token stackaroo)

contrib/side-cars/fee-estimate.sh

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
#!/bin/bash
2+
3+
####################################
4+
# Usage
5+
#
6+
# $ # one-shot fee-rate calculation
7+
# $ ./fee-estimate.sh
8+
# 161
9+
#
10+
# $ # Check fees every 5 seconds and update `satoshis_per_byte` in `/path/to/miner.toml`
11+
# $ ./fee-estimate.sh watch /path/to/miner.toml 5
12+
#
13+
# $ # Run unit tests and report result (0 means success)
14+
# $ ./fee-estimate.sh test; echo $?
15+
# 0
16+
####################################
17+
18+
set -uoe pipefail
19+
20+
function exit_error() {
21+
echo >&2 "$@"
22+
exit 1
23+
}
24+
25+
####################################
26+
# Dependencies
27+
####################################
28+
for cmd in curl jq bc sed date grep head tail; do
29+
command -v "$cmd" >/dev/null 2>&1 || exit_error "Command not found: '$cmd'"
30+
done
31+
32+
33+
####################################
34+
# Functions
35+
####################################
36+
37+
# Convert a fee/kb to fee/vbyte.
38+
# If there's a fractional part of the fee/kb (i.e. if it's not divisible by 1000),
39+
# then round up.
40+
# Arguments:
41+
# $1 -- the fee per kb
42+
# Stdout: the satoshis per vbyte, as an integer
43+
# Stderr: none
44+
# Return:
45+
# 0 on success
46+
# nonzero on error
47+
function fee_per_kb_to_fee_per_vbyte() {
48+
local fee_per_kb="$1"
49+
local fee_per_vbyte_float=
50+
local fee_per_vbyte_ipart=
51+
local fee_per_vbyte_fpart=
52+
local fee_per_vbyte=
53+
54+
# must be an integer
55+
if ! [[ "$fee_per_kb" =~ ^[0-9]+$ ]]; then
56+
return 1
57+
fi
58+
59+
# NOTE: round up -- get the fractional part, and if it's anything other than 000, then add 1
60+
fee_per_vbyte_float="$(echo "scale=3; $fee_per_kb / 1000" | bc)"
61+
fee_per_vbyte_ipart="$(echo "$fee_per_vbyte_float" | sed -r 's/^([0-9]*)\..+$/\1/g')"
62+
fee_per_vbyte_fpart="$(echo "$fee_per_vbyte_float" | sed -r -e 's/.+\.([0-9]+)$/\1/g' -e 's/0//g')"
63+
fee_per_vbyte="$fee_per_vbyte_ipart"
64+
if [ -n "$fee_per_vbyte_fpart" ]; then
65+
fee_per_vbyte="$((fee_per_vbyte + 1))"
66+
fi
67+
68+
echo "$fee_per_vbyte"
69+
return 0
70+
}
71+
72+
# Query the endpoint and log HTTP errors gracefully
73+
# Arguments:
74+
# $1 endpoint to query
75+
# Stdout: the HTTP response body
76+
# Stderr: an error message, if we failed to query
77+
# Return:
78+
# 0 on success
79+
# nonzero on error
80+
function query_fee_endpoint() {
81+
local fee_endpoint="$1"
82+
local response=
83+
local http_status_code=
84+
85+
response="$(curl -sL -w "\n%{http_code}" "$fee_endpoint" || true)";
86+
http_status_code="$(echo "$response" | tail -n 1)";
87+
case $http_status_code in
88+
200)
89+
;;
90+
429)
91+
echo >&2 "WARN[$(date +%s)]: 429 Rate-Limited retreiving ${fee_endpoint}"
92+
return 1
93+
;;
94+
404)
95+
echo >&2 "WARN[$(date +%s)]: 404 Not Found retrieving ${fee_endpoint}"
96+
return 1
97+
;;
98+
**)
99+
echo >&2 "WARN[$(date +%s)]: ${http_status_code} Error retrieving ${fee_endpoint}"
100+
return 1
101+
;;
102+
esac
103+
echo "$response" | head -n -1
104+
return 0
105+
}
106+
107+
# Determine satoshis per vbyte
108+
# Arguments: none
109+
# Stdout: the satoshis per vbyte, as an integer
110+
# Stderr: none
111+
# Return:
112+
# 0 on success
113+
# nonzero on error
114+
function get_sats_per_vbyte() {
115+
local fee_endpoint="https://api.blockcypher.com/v1/btc/main"
116+
local fee_per_kb=
117+
118+
fee_per_kb="$(query_fee_endpoint "$fee_endpoint" | jq -r '.high_fee_per_kb')"
119+
if ! fee_per_kb_to_fee_per_vbyte "$fee_per_kb"; then
120+
return 1
121+
fi
122+
return 0
123+
}
124+
125+
# Update the fee rate in the config file.
126+
# Arguments:
127+
# $1 -- path to the config file
128+
# $2 -- new fee to write
129+
# Stdout: (none)
130+
# Stderr: (none)
131+
# Returns:
132+
# 0 on success
133+
# nonzero on error
134+
function update_fee() {
135+
local config_path="$1"
136+
local fee="$2"
137+
sed -i -r "s/satoshis_per_byte[ \t]+=.*$/satoshis_per_byte = ${fee}/g" "$config_path"
138+
return 0
139+
}
140+
141+
# Poll fees every so often, and update a config file.
142+
# Runs indefinitely.
143+
# If the fee estimator endpoint cannot be reached, then the file is not modified.
144+
# Arguments:
145+
# $1 -- path to file to watch
146+
# $2 -- interval at which to poll, in seconds
147+
# Stdout: (none)
148+
# Stderr: (none)
149+
# Returns: (none)
150+
function watch_fees() {
151+
local config_path="$1"
152+
local interval="$2"
153+
154+
local fee=
155+
local rc=
156+
157+
while true; do
158+
# allow poll command to fail without killing the script
159+
set +e
160+
fee="$(get_sats_per_vbyte)"
161+
rc="$?"
162+
set -e
163+
164+
if [ $rc -ne 0 ]; then
165+
echo >&2 "WARN[$(date +%s)]: failed to poll fees"
166+
else
167+
update_fee "$config_path" "$fee"
168+
fi
169+
sleep "$interval"
170+
done
171+
}
172+
173+
# Unit tests
174+
function unit_test() {
175+
local test_config="/tmp/test-miner-config-$$.toml"
176+
if [ "$(fee_per_kb_to_fee_per_vbyte 1000)" != "1" ]; then
177+
exit_error "failed -- 1000 sats/kbyte != 1 sats/vbyte"
178+
fi
179+
180+
if [ "$(fee_per_kb_to_fee_per_vbyte 1001)" != "2" ]; then
181+
exit_error "failed -- 1001 sats/vbyte != 2 sats/vbyte"
182+
fi
183+
184+
if [ "$(fee_per_kb_to_fee_per_vbyte 999)" != "1" ]; then
185+
exit_error "failed -- 999 sats/vbyte != 1 sats/vbyte"
186+
fi
187+
188+
echo "satoshis_per_byte = 123" > "$test_config"
189+
update_fee "$test_config" "456"
190+
if ! grep 'satoshis_per_byte = 456' >/dev/null "$test_config"; then
191+
exit_error "failed -- did not update satoshis_per_byte"
192+
fi
193+
194+
echo "" > "$test_config"
195+
update_fee "$test_config" "456"
196+
if grep "satoshis_per_byte" "$test_config" >/dev/null; then
197+
exit_error "failed -- updated satoshis_per_byte in a config file without it"
198+
fi
199+
200+
rm "$test_config"
201+
return 0
202+
}
203+
204+
####################################
205+
# Entry point
206+
####################################
207+
208+
# Main body
209+
# Arguments
210+
# $1: mode of operation. Can be "test" or empty
211+
# Stdout: the fee rate, in sats/vbte
212+
# Stderr: None
213+
# Return: (no return)
214+
function main() {
215+
local mode="$1"
216+
local config_path=
217+
local interval=
218+
219+
case "$mode" in
220+
"test")
221+
# run unit tests
222+
echo "Run unit tests"
223+
unit_test
224+
exit 0
225+
;;
226+
"watch")
227+
# watch and update the file
228+
if (( $# < 3 )); then
229+
exit_error "Usage: $0 watch /path/to/miner.toml interval_in_seconds"
230+
fi
231+
232+
config_path="$2"
233+
interval="$3"
234+
235+
if ! [ -f "$config_path" ]; then
236+
exit_error "No such config file: ${config_path}"
237+
fi
238+
239+
watch_fees "$config_path" "$interval"
240+
;;
241+
242+
"")
243+
# one-shot
244+
get_sats_per_vbyte
245+
;;
246+
esac
247+
exit 0
248+
}
249+
250+
if (( $# > 0 )); then
251+
# got arguments
252+
main "$@"
253+
else
254+
# no arguments
255+
main ""
256+
fi

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2108,8 +2108,8 @@ pub mod test {
21082108
);
21092109

21102110
let contracts = vec![
2111-
contract_correct.clone(),
2112-
contract_correct.clone(),
2111+
contract_correct,
2112+
contract_correct,
21132113
contract_syntax_error, // should still be mined, even though analysis fails
21142114
];
21152115

stackslib/src/net/api/tests/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ impl<'a> TestRPC<'a> {
301301
let tx_coinbase_signed = tx_signer.get_tx().unwrap();
302302

303303
// next the contract
304-
let contract = TEST_CONTRACT.clone();
304+
let contract = TEST_CONTRACT;
305305
let mut tx_contract = StacksTransaction::new(
306306
TransactionVersion::Testnet,
307307
TransactionAuth::from_p2pkh(&privk1).unwrap(),
@@ -343,7 +343,7 @@ impl<'a> TestRPC<'a> {
343343
};
344344

345345
// make an unconfirmed contract
346-
let unconfirmed_contract = TEST_CONTRACT_UNCONFIRMED.clone();
346+
let unconfirmed_contract = TEST_CONTRACT_UNCONFIRMED;
347347
let mut tx_unconfirmed_contract = StacksTransaction::new(
348348
TransactionVersion::Testnet,
349349
TransactionAuth::from_p2pkh(&privk1).unwrap(),

stackslib/src/net/atlas/download.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,7 @@ impl BatchedDNSLookupsState {
724724
match url.host() {
725725
Some(url::Host::Domain(domain)) => {
726726
let res = dns_client.queue_lookup(
727-
domain.clone(),
727+
domain,
728728
port,
729729
get_epoch_time_ms() + connection_options.dns_timeout,
730730
);

stackslib/src/net/download.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ impl BlockDownloader {
350350
match url.host() {
351351
Some(url::Host::Domain(domain)) => {
352352
match dns_client.queue_lookup(
353-
domain.clone(),
353+
domain,
354354
port,
355355
get_epoch_time_ms() + self.dns_timeout,
356356
) {

stackslib/src/net/p2p.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3483,7 +3483,7 @@ impl PeerNetwork {
34833483
if let Some(ref mut dns_client) = dns_client_opt {
34843484
// begin DNS query
34853485
match dns_client.queue_lookup(
3486-
domain.clone(),
3486+
domain,
34873487
port,
34883488
get_epoch_time_ms() + self.connection_opts.dns_timeout,
34893489
) {

stackslib/src/net/stackerdb/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
/// This file implements the interface to the StackerDB smart contract for loading the DB's config.
1818
/// The smart contract must conform to this trait:
1919
///
20+
/// ```clarity,ignore
2021
/// ;; Any StackerDB smart contract must conform to this trait.
2122
/// (define-trait stackerdb-trait
2223
///
@@ -34,6 +35,7 @@
3435
/// },
3536
/// uint))
3637
/// )
38+
/// ```
3739
use std::collections::{HashMap, HashSet};
3840
use std::mem;
3941

stackslib/src/util_lib/db.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ fn log_sql_eqp(conn: &Connection, sql_query: &str) {
353353
return;
354354
}
355355

356-
let mut parts = sql_query.clone().split(" ");
356+
let mut parts = sql_query.split(" ");
357357
let mut full_sql = if let Some(part) = parts.next() {
358358
part.to_string()
359359
} else {

stackslib/src/util_lib/strings.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,8 @@ mod test {
331331
fn tx_stacks_strings_codec() {
332332
let s = "hello-world";
333333
let stacks_str = StacksString::from_str(&s).unwrap();
334-
let clarity_str = ClarityName::try_from(s.clone()).unwrap();
335-
let contract_str = ContractName::try_from(s.clone()).unwrap();
334+
let clarity_str = ClarityName::try_from(s).unwrap();
335+
let contract_str = ContractName::try_from(s).unwrap();
336336

337337
assert_eq!(stacks_str[..], s.as_bytes().to_vec()[..]);
338338
let s2 = stacks_str.to_string();

0 commit comments

Comments
 (0)