Skip to content

Commit 6fbf7b2

Browse files
authored
Merge branch 'main' into GH-1091-block-nack
2 parents 2c1cd11 + 909603c commit 6fbf7b2

21 files changed

+330
-110
lines changed

libraries/chain/controller.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -3078,8 +3078,10 @@ struct controller_impl {
30783078
} else {
30793079
transaction_receipt_header r;
30803080
r.status = transaction_receipt::executed;
3081-
r.cpu_usage_us = trx_context.billed_cpu_time_us;
3082-
r.net_usage_words = trace->net_usage / 8;
3081+
if (!trx->is_read_only()) {
3082+
r.cpu_usage_us = trx_context.billed_cpu_time_us;
3083+
r.net_usage_words = trace->net_usage / 8;
3084+
}
30833085
trace->receipt = r;
30843086
}
30853087

@@ -4533,7 +4535,7 @@ struct controller_impl {
45334535
// validated.
45344536
if (applying_block) {
45354537
ilog("Interrupting apply block");
4536-
main_thread_timer.expire_now();
4538+
main_thread_timer.interrupt_timer();
45374539
}
45384540
}
45394541

libraries/chain/include/eosio/chain/platform_timer.hpp

+12-4
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77

88
#include <atomic>
99

10-
#include <signal.h>
11-
1210
namespace eosio { namespace chain {
1311

1412
struct platform_timer {
@@ -17,7 +15,7 @@ struct platform_timer {
1715

1816
void start(fc::time_point tp);
1917
void stop();
20-
void expire_now();
18+
void interrupt_timer();
2119

2220
/* Sets a callback for when timer expires. Be aware this could might fire from a signal handling context and/or
2321
on any particular thread. Only a single callback can be registered at once; trying to register more will
@@ -35,9 +33,19 @@ struct platform_timer {
3533
_expiration_callback_data = user;
3634
}
3735

38-
std::atomic_bool expired = true;
36+
enum class state_t {
37+
running,
38+
timed_out,
39+
interrupted,
40+
stopped
41+
};
42+
state_t timer_state() const { return _state; }
3943

4044
private:
45+
void expire_now();
46+
47+
std::atomic<state_t> _state = state_t::stopped;
48+
4149
struct impl;
4250
constexpr static size_t fwd_size = 8;
4351
fc::fwd<impl,fwd_size> my;

libraries/chain/include/eosio/chain/transaction_context.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ namespace eosio::chain {
2020
void start(fc::time_point tp);
2121
void stop();
2222

23+
platform_timer::state_t timer_state() const { return _timer.timer_state(); }
24+
2325
/* Sets a callback for when timer expires. Be aware this could might fire from a signal handling context and/or
2426
on any particular thread. Only a single callback can be registered at once; trying to register more will
2527
result in an exception. Use nullptr to disable a previously set callback. */
2628
void set_expiration_callback(void(*func)(void*), void* user);
2729

28-
std::atomic_bool& expired;
2930
private:
3031
platform_timer& _timer;
3132

libraries/chain/include/eosio/chain/wasm_interface_private.hpp

+2-6
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ struct eosvmoc_tier {
125125
if (executing_code_hash.load() == code_id) {
126126
ilog("EOS VM OC tier up interrupting ${id}", ("id", code_id));
127127
eos_vm_oc_compile_interrupt = true;
128-
main_thread_timer.expire_now();
128+
main_thread_timer.interrupt_timer();
129129
}
130130
});
131131
}
@@ -148,10 +148,6 @@ struct eosvmoc_tier {
148148
m.whitelisted = context.is_eos_vm_oc_whitelisted();
149149
m.high_priority = m.whitelisted && context.is_applying_block();
150150
m.write_window = context.control.is_write_window();
151-
auto timer_pause = fc::make_scoped_exit([&](){
152-
context.trx_context.resume_billing_timer();
153-
});
154-
context.trx_context.pause_billing_timer();
155151
cd = eosvmoc->cc.get_descriptor_for_code(m, code_hash, vm_version, failure);
156152
} catch (...) {
157153
// swallow errors here, if EOS VM OC has gone in to the weeds we shouldn't bail: continue to try and run baseline
@@ -181,7 +177,7 @@ struct eosvmoc_tier {
181177
try {
182178
get_instantiated_module(code_hash, vm_type, vm_version, context.trx_context)->apply(context);
183179
} catch (const interrupt_exception& e) {
184-
if (allow_oc_interrupt && eos_vm_oc_compile_interrupt) {
180+
if (allow_oc_interrupt && eos_vm_oc_compile_interrupt && main_thread_timer.timer_state() == platform_timer::state_t::interrupted) {
185181
++eos_vm_oc_compile_interrupt_count;
186182
dlog("EOS VM OC compile complete interrupt of ${r} <= ${a}::${act} code ${h}, interrupt #${c}",
187183
("r", context.get_receiver())("a", context.get_action().account)

libraries/chain/platform_timer_accuracy.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ void compute_and_print_timer_accuracy(platform_timer& timer) {
3939
for(unsigned int i = 0; i < loops; ++i) {
4040
auto start = std::chrono::high_resolution_clock::now();
4141
timer.start(fc::time_point(fc::time_point::now().time_since_epoch() + fc::microseconds(interval)));
42-
while(!timer.expired) {}
42+
while(timer.timer_state() == platform_timer::state_t::running) {}
4343
auto end = std::chrono::high_resolution_clock::now();
4444
int timer_slop = std::chrono::duration_cast<std::chrono::microseconds>(end-start).count() - interval;
45+
timer.stop();
4546

4647
//since more samples are run for the shorter expirations, weigh the longer expirations accordingly. This
4748
//helps to make a few results more fair. Two such examples: AWS c4&i5 xen instances being rather stable

libraries/chain/platform_timer_asio_fallback.cpp

+14-7
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ platform_timer::~platform_timer() {
5757

5858
void platform_timer::start(fc::time_point tp) {
5959
if(tp == fc::time_point::maximum()) {
60-
expired = false;
60+
_state = state_t::running;
6161
return;
6262
}
6363
fc::microseconds x = tp.time_since_epoch() - fc::time_point::now().time_since_epoch();
6464
if(x.count() <= 0)
65-
expired = true;
65+
_state = state_t::timed_out;
6666
else {
67-
expired = false;
67+
_state = state_t::running;
6868
my->timer->expires_after(std::chrono::microseconds(x.count()));
6969
my->timer->async_wait([this](const boost::system::error_code& ec) {
7070
if(ec)
@@ -75,18 +75,25 @@ void platform_timer::start(fc::time_point tp) {
7575
}
7676

7777
void platform_timer::expire_now() {
78-
bool expected = false;
79-
if (expired.compare_exchange_strong(expected, true)) {
78+
state_t expected = state_t::running;
79+
if (_state.compare_exchange_strong(expected, state_t::timed_out)) {
80+
call_expiration_callback();
81+
}
82+
}
83+
84+
void platform_timer::interrupt_timer() {
85+
state_t expected = state_t::running;
86+
if (_state.compare_exchange_strong(expected, state_t::interrupted)) {
8087
call_expiration_callback();
8188
}
8289
}
8390

8491
void platform_timer::stop() {
85-
if(expired)
92+
if(_state == state_t::stopped)
8693
return;
8794

8895
my->timer->cancel();
89-
expired = true;
96+
_state = state_t::stopped;
9097
}
9198

9299
}}

libraries/chain/platform_timer_kqueue.cpp

+11-4
Original file line numberDiff line numberDiff line change
@@ -106,20 +106,27 @@ void platform_timer::start(fc::time_point tp) {
106106
}
107107

108108
void platform_timer::expire_now() {
109-
bool expected = false;
110-
if (expired.compare_exchange_strong(expected, true)) {
109+
state_t expected = state_t::running;
110+
if (_state.compare_exchange_strong(expected, state_t::timed_out)) {
111+
call_expiration_callback();
112+
}
113+
}
114+
115+
void platform_timer::interrupt_timer() {
116+
state_t expected = state_t::running;
117+
if (_state.compare_exchange_strong(expected, state_t::interrupted)) {
111118
call_expiration_callback();
112119
}
113120
}
114121

115122
void platform_timer::stop() {
116-
if(expired)
123+
if(_state == state_t::stopped)
117124
return;
118125

119126
struct kevent64_s stop_timer_event;
120127
EV_SET64(&stop_timer_event, my->timerid, EVFILT_TIMER, EV_DELETE, 0, 0, 0, 0, 0);
121128
kevent64(kqueue_fd, &stop_timer_event, 1, NULL, 0, KEVENT_FLAG_IMMEDIATE, NULL);
122-
expired = true;
129+
_state = state_t::stopped;
123130
}
124131

125132
}}

libraries/chain/platform_timer_posix.cpp

+16-8
Original file line numberDiff line numberDiff line change
@@ -55,36 +55,44 @@ platform_timer::~platform_timer() {
5555
}
5656

5757
void platform_timer::start(fc::time_point tp) {
58+
assert(_state == state_t::stopped);
5859
if(tp == fc::time_point::maximum()) {
59-
expired = false;
60+
_state = state_t::running;
6061
return;
6162
}
6263
fc::microseconds x = tp.time_since_epoch() - fc::time_point::now().time_since_epoch();
6364
if(x.count() <= 0)
64-
expired = true;
65+
_state = state_t::timed_out;
6566
else {
6667
time_t secs = x.count() / 1000000;
6768
long nsec = (x.count() - (secs*1000000)) * 1000;
6869
struct itimerspec enable = {{0, 0}, {secs, nsec}};
69-
expired = false;
70+
_state = state_t::running;
7071
if(timer_settime(my->timerid, 0, &enable, NULL) != 0)
71-
expired = true;
72+
_state = state_t::timed_out;
7273
}
7374
}
7475

7576
void platform_timer::expire_now() {
76-
bool expected = false;
77-
if (expired.compare_exchange_strong(expected, true)) {
77+
state_t expected = state_t::running;
78+
if (_state.compare_exchange_strong(expected, state_t::timed_out)) {
79+
call_expiration_callback();
80+
}
81+
}
82+
83+
void platform_timer::interrupt_timer() {
84+
state_t expected = state_t::running;
85+
if (_state.compare_exchange_strong(expected, state_t::interrupted)) {
7886
call_expiration_callback();
7987
}
8088
}
8189

8290
void platform_timer::stop() {
83-
if(expired)
91+
if(_state == state_t::stopped)
8492
return;
8593
struct itimerspec disable = {{0, 0}, {0, 0}};
8694
timer_settime(my->timerid, 0, &disable, NULL);
87-
expired = true;
95+
_state = state_t::stopped;
8896
}
8997

9098
}

libraries/chain/transaction_context.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
namespace eosio::chain {
1515

1616
transaction_checktime_timer::transaction_checktime_timer(platform_timer& timer)
17-
: expired(timer.expired), _timer(timer) {
18-
expired = 0;
17+
: _timer(timer) {
1918
}
2019

2120
void transaction_checktime_timer::start(fc::time_point tp) {
@@ -441,10 +440,12 @@ namespace eosio::chain {
441440
void transaction_context::squash() {
442441
if (undo_session) undo_session->squash();
443442
control.apply_trx_block_context(trx_blk_context);
443+
transaction_timer.stop();
444444
}
445445

446446
void transaction_context::undo() {
447447
if (undo_session) undo_session->undo();
448+
transaction_timer.stop();
448449
}
449450

450451
void transaction_context::check_net_usage()const {
@@ -489,11 +490,12 @@ namespace eosio::chain {
489490
}
490491

491492
void transaction_context::checktime()const {
492-
if(BOOST_LIKELY(transaction_timer.expired == false))
493+
platform_timer::state_t expired = transaction_timer.timer_state();
494+
if(BOOST_LIKELY(expired == platform_timer::state_t::running))
493495
return;
494496

495497
auto now = fc::time_point::now();
496-
if (explicit_billed_cpu_time && block_deadline > now) {
498+
if (expired == platform_timer::state_t::interrupted) {
497499
EOS_THROW( interrupt_exception, "interrupt signaled, ran ${bt}us, start ${s}",
498500
("bt", now - pseudo_start)("s", start) );
499501
} else if( explicit_billed_cpu_time || deadline_exception_code == deadline_exception::code_value ) {

libraries/chain/webassembly/runtimes/eos-vm.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ namespace {
2929
guard(transaction_checktime_timer& timer, F&& func)
3030
: _timer(timer), _func(std::forward<F>(func)) {
3131
_timer.set_expiration_callback(&callback, this);
32-
if(_timer.expired) {
32+
platform_timer::state_t expired = _timer.timer_state();
33+
if(expired == platform_timer::state_t::timed_out || expired == platform_timer::state_t::interrupted) {
3334
_func(); // it's harmless if _func is invoked twice
3435
}
3536
}

plugins/net_plugin/net_plugin.cpp

+1-30
Original file line numberDiff line numberDiff line change
@@ -3410,7 +3410,6 @@ namespace eosio {
34103410
peer_fork_db_head_block_num = msg.fork_db_head_num;
34113411
fc::unique_lock g_conn( conn_mtx );
34123412
last_handshake_recv = msg;
3413-
auto c_time = last_handshake_sent.time;
34143413
g_conn.unlock();
34153414

34163415
set_state(connection_state::connected);
@@ -3452,35 +3451,7 @@ namespace eosio {
34523451
fc::unique_lock g_check_conn( check->conn_mtx );
34533452
fc_dlog( logger, "dup check: connected ${c}, ${l} =? ${r}",
34543453
("c", check->connected())("l", check->last_handshake_recv.node_id)("r", msg.node_id) );
3455-
if(check->connected() && check->last_handshake_recv.node_id == msg.node_id) {
3456-
if (net_version < proto_dup_goaway_resolution || msg.network_version < proto_dup_goaway_resolution) {
3457-
// It's possible that both peers could arrive here at relatively the same time, so
3458-
// we need to avoid the case where they would both tell a different connection to go away.
3459-
// Using the sum of the initial handshake times of the two connections, we will
3460-
// arbitrarily (but consistently between the two peers) keep one of them.
3461-
3462-
auto check_time = check->last_handshake_sent.time + check->last_handshake_recv.time;
3463-
g_check_conn.unlock();
3464-
if (msg.time + c_time <= check_time)
3465-
return false;
3466-
} else if (net_version < proto_dup_node_id_goaway || msg.network_version < proto_dup_node_id_goaway) {
3467-
if (listen_address < msg.p2p_address) {
3468-
fc_dlog( logger, "listen_address '${lhs}' < msg.p2p_address '${rhs}'",
3469-
("lhs", listen_address)( "rhs", msg.p2p_address ) );
3470-
// only the connection from lower p2p_address to higher p2p_address will be considered as a duplicate,
3471-
// so there is no chance for both connections to be closed
3472-
return false;
3473-
}
3474-
} else if (my_impl->node_id < msg.node_id) {
3475-
fc_dlog( logger, "not duplicate, my_impl->node_id '${lhs}' < msg.node_id '${rhs}'",
3476-
("lhs", my_impl->node_id)("rhs", msg.node_id) );
3477-
// only the connection from lower node_id to higher node_id will be considered as a duplicate,
3478-
// so there is no chance for both connections to be closed
3479-
return false;
3480-
}
3481-
return true;
3482-
}
3483-
return false;
3454+
return check->connected() && check->last_handshake_recv.node_id == msg.node_id;
34843455
};
34853456
if (my_impl->connections.any_of_connections(std::move(is_duplicate))) {
34863457
peer_dlog( this, "sending go_away duplicate, msg.p2p_address: ${add}", ("add", msg.p2p_address) );

plugins/producer_api_plugin/producer.swagger.yaml

+33
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,39 @@ paths:
4444
application/json:
4545
schema:
4646
$ref: "#/components/schemas/Error"
47+
/producer/pause_at_block:
48+
post:
49+
summary: pause_at_block
50+
description: |
51+
Pause node at the specified block. Use /producer/resume to un-pause. If specified block is less than head then returns an error.
52+
53+
### Usage
54+
55+
Note that this pauses all nodes not just producer nodes. The common use case is to use on non-producer nodes as a way of freezing state. For example, a user might wish to download all the rows of a table. This would allow the user to freeze at a block number and then iterate through an entire table.
56+
operationId: pause_at_block
57+
requestBody:
58+
content:
59+
application/json:
60+
schema:
61+
type: object
62+
properties:
63+
block_num:
64+
type: integer
65+
description: Block number
66+
example: 5102
67+
responses:
68+
"201":
69+
description: OK
70+
content:
71+
application/json:
72+
schema:
73+
$ref: "#/components/schemas/OK"
74+
"400":
75+
description: client error
76+
content:
77+
application/json:
78+
schema:
79+
$ref: "#/components/schemas/Error"
4780
/producer/resume:
4881
post:
4982
summary: resume

plugins/producer_api_plugin/producer_api_plugin.cpp

+3-4
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,9 @@ void producer_api_plugin::plugin_startup() {
119119
app().get_plugin<http_plugin>().add_api({
120120
CALL_WITH_400(producer, producer_rw, producer, pause,
121121
INVOKE_V_V(producer, pause), 201),
122-
// TODO: Enable for Spring 2.0.0
123-
// CALL_WITH_400(producer, producer_rw, producer, pause_at_block,
124-
// INVOKE_V_R(producer, pause_at_block, producer_plugin::pause_at_block_params), 201),
125-
CALL_WITH_400(producer, producer_rw, producer, resume,
122+
CALL_WITH_400(producer, producer_rw, producer, pause_at_block,
123+
INVOKE_V_R(producer, pause_at_block, producer_plugin::pause_at_block_params), 201),
124+
CALL_WITH_400(producer, producer_rw, producer, resume,
126125
INVOKE_V_V(producer, resume), 201),
127126
CALL_WITH_400(producer, producer_rw, producer, update_runtime_options,
128127
INVOKE_V_R(producer, update_runtime_options, producer_plugin::runtime_options), 201),

0 commit comments

Comments
 (0)