Skip to content

Commit 2b85452

Browse files
authored
Merge pull request #1057 from AntelopeIO/GH-570-pause-at-block-test
Enable `/v1/producer/pause_at_block`
2 parents 154e8e6 + b3b0b5a commit 2b85452

File tree

4 files changed

+139
-4
lines changed

4 files changed

+139
-4
lines changed

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),

tests/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/production_pause_vote_timeout.py ${CM
8282
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/production_pause_vote_timeout_test_shape.json ${CMAKE_CURRENT_BINARY_DIR}/production_pause_vote_timeout_test_shape.json COPYONLY)
8383
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/production_restart.py ${CMAKE_CURRENT_BINARY_DIR}/production_restart.py COPYONLY)
8484
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/production_restart_test_shape.json ${CMAKE_CURRENT_BINARY_DIR}/production_restart_test_shape.json COPYONLY)
85+
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pause_at_block_test.py ${CMAKE_CURRENT_BINARY_DIR}/pause_at_block_test.py COPYONLY)
8586
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/trx_finality_status_test.py ${CMAKE_CURRENT_BINARY_DIR}/trx_finality_status_test.py COPYONLY)
8687
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/trx_finality_status_forked_test.py ${CMAKE_CURRENT_BINARY_DIR}/trx_finality_status_forked_test.py COPYONLY)
8788
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/plugin_http_api_test.py ${CMAKE_CURRENT_BINARY_DIR}/plugin_http_api_test.py COPYONLY)
@@ -225,6 +226,8 @@ add_test(NAME subjective_billing_test COMMAND tests/subjective_billing_test.py -
225226
set_property(TEST subjective_billing_test PROPERTY LABELS nonparallelizable_tests)
226227
add_test(NAME get_account_test COMMAND tests/get_account_test.py -v -p 2 -n 3 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
227228
set_property(TEST get_account_test PROPERTY LABELS nonparallelizable_tests)
229+
add_test(NAME pause_at_block_test COMMAND tests/pause_at_block_test.py -v ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
230+
set_property(TEST pause_at_block_test PROPERTY LABELS nonparallelizable_tests)
228231

229232
add_test(NAME distributed-transactions-test COMMAND tests/distributed-transactions-test.py -d 2 -p 4 -n 6 -v ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
230233
set_property(TEST distributed-transactions-test PROPERTY LABELS nonparallelizable_tests)

tests/pause_at_block_test.py

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/usr/bin/env python3
2+
3+
import json
4+
import signal
5+
6+
from TestHarness import Account, Cluster, Node, ReturnType, TestHelper, Utils, WalletMgr
7+
from TestHarness.TestHelper import AppArgs
8+
9+
###############################################################
10+
# pause_at_block_test
11+
#
12+
# Verify /v1/producer/pause_at_block pauses node in all read modes
13+
#
14+
###############################################################
15+
16+
# Parse command line arguments
17+
args = TestHelper.parse_args({"-v","--dump-error-details","--leave-running","--keep-logs","--unshared"})
18+
Utils.Debug = args.v
19+
dumpErrorDetails=args.dump_error_details
20+
dontKill=args.leave_running
21+
keepLogs=args.keep_logs
22+
23+
walletMgr=WalletMgr(True)
24+
cluster=Cluster(unshared=args.unshared, keepRunning=args.leave_running, keepLogs=args.keep_logs)
25+
cluster.setWalletMgr(walletMgr)
26+
27+
testSuccessful = False
28+
try:
29+
TestHelper.printSystemInfo("BEGIN")
30+
31+
specificNodeosArgs = {
32+
0 : "--enable-stale-production",
33+
34+
3 : "--read-mode head",
35+
4 : "--read-mode speculative",
36+
5 : "--read-mode irreversible"
37+
}
38+
assert cluster.launch(
39+
pnodes=3,
40+
prodCount=3,
41+
totalProducers=3,
42+
totalNodes=6,
43+
loadSystemContract=False,
44+
activateIF=True)
45+
46+
prodNode = cluster.getNode(0)
47+
prodNode2 = cluster.getNode(1)
48+
headNode = cluster.getNode(3)
49+
specNode = cluster.getNode(4)
50+
irrvNode = cluster.getNode(5)
51+
52+
prodNode.waitForProducer("defproducerb");
53+
prodNode.waitForProducer("defproducera");
54+
55+
blockNum = prodNode.getHeadBlockNum()
56+
57+
blockNum += 5
58+
59+
Utils.Print(f"Pausing at block {blockNum}")
60+
prodNode2.processUrllibRequest("producer", "pause_at_block", {"block_num":blockNum}),
61+
headNode.processUrllibRequest("producer", "pause_at_block", {"block_num":blockNum}),
62+
specNode.processUrllibRequest("producer", "pause_at_block", {"block_num":blockNum}),
63+
irrvNode.processUrllibRequest("producer", "pause_at_block", {"block_num":blockNum}),
64+
65+
assert prodNode.waitForLibToAdvance(), "LIB did not advance with paused nodes"
66+
assert prodNode2.waitForBlock(blockNum), f"Block {blockNum} did not arrive after pausing"
67+
68+
Utils.Print(f"Verify paused at block {blockNum}")
69+
assert prodNode2.getHeadBlockNum() == blockNum, "Prod Node_01 did not pause at block"
70+
assert headNode.getHeadBlockNum() == blockNum, "Head Node_03 did not pause at block"
71+
assert specNode.getHeadBlockNum() == blockNum, "Speculative Node_04 did not pause at block"
72+
assert irrvNode.getHeadBlockNum() == blockNum, "Irreversible Node_05 did not pause at block"
73+
74+
Utils.Print(f"Verify prod node still producing blocks")
75+
assert prodNode.waitForLibToAdvance(), "LIB did not advance with paused nodes"
76+
77+
Utils.Print(f"Verify still paused at block {blockNum}")
78+
assert prodNode2.getHeadBlockNum() == blockNum, "Prod Node_01 did not pause at block"
79+
assert headNode.getHeadBlockNum() == blockNum, "Head Node_03 did not pause at block"
80+
assert specNode.getHeadBlockNum() == blockNum, "Speculative Node_04 did not pause at block"
81+
assert irrvNode.getHeadBlockNum() == blockNum, "Irreversible Node_05 did not pause at block"
82+
83+
Utils.Print(f"Resume paused nodes")
84+
prodNode2.processUrllibRequest("producer", "resume", {})
85+
headNode.processUrllibRequest("producer", "resume", {})
86+
specNode.processUrllibRequest("producer", "resume",{})
87+
irrvNode.processUrllibRequest("producer", "resume", {})
88+
89+
Utils.Print(f"Verify nodes resumed")
90+
assert prodNode2.waitForLibToAdvance(), "Prod Node_01 did not resume"
91+
assert headNode.waitForLibToAdvance(), "Head Node_03 did not resume"
92+
assert specNode.waitForLibToAdvance(), "Speculative Node_04 did not resume"
93+
assert irrvNode.waitForLibToAdvance(), "Irreversible Node_05 did not resume"
94+
95+
testSuccessful = True
96+
finally:
97+
TestHelper.shutdown(cluster, walletMgr, testSuccessful, dumpErrorDetails)
98+
99+
exitCode = 0 if testSuccessful else 1
100+
exit(exitCode)

0 commit comments

Comments
 (0)