AntelopeIO / leap

C++ implementation of the Antelope protocol
Other
116 stars 68 forks source link

LocalHosted Test Node Does not Suppoprt get_block_header_state #1206

Closed ericpassmore closed 1 year ago

ericpassmore commented 1 year ago

When running on a local hosted single producer node, the called to get_block_header_state never works. Want to get this working so I can run tests on my local nodeos.

Example Curl Requests

curl -X POST http://10.3.0.1:8888/v1/chain/get_info | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   909  100   909    0     0  2845k      0 --:--:-- --:--:-- --:--:--  887k
{
  "server_version": "0d8de6cc",
  "chain_id": "8a34ec7df1b8cd06ff4a8abbaa7cc50300823350cadc59ab296cb00d104d2b8f",
  "head_block_num": 19641,
  "last_irreversible_block_num": 19640,
  "last_irreversible_block_id": "00004cb82a12425df6971a2c82a8cd528181f6f728887f47b301cdcdba61ea7c",
  "head_block_id": "00004cb97a0ee5558f4f9321a94c758e5dec4e8d7f4ed19b863fe7f26d5f9089",
  "head_block_time": "2023-05-19T19:42:59.500",
  "head_block_producer": "eosio",
  "virtual_block_cpu_limit": 200000000,
  "virtual_block_net_limit": 1048576000,
  "block_cpu_limit": 199900,
  "block_net_limit": 1048576,
  "server_version_string": "v4.0.1",
  "fork_db_head_block_num": 19641,
  "fork_db_head_block_id": "00004cb97a0ee5558f4f9321a94c758e5dec4e8d7f4ed19b863fe7f26d5f9089",
  "server_full_version_string": "v4.0.1-0d8de6cc5d50ee5544d544f1d6ddbbb5b02763a6",
  "total_cpu_weight": 0,
  "total_net_weight": 0,
  "earliest_available_block_num": 1,
  "last_irreversible_block_time": "2023-05-19T19:42:59.000"
}

 curl -X POST http://10.3.0.1:8888/v1/chain/get_block_header_state -d '{"block_num_or_id":"19641"}'| jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   290  100   263  100    27   701k  73770 --:--:-- --:--:-- --:--:--  283k
{
  "code": 400,
  "message": "Unknown Block",
  "error": {
    "code": 3100002,
    "name": "unknown_block_exception",
    "what": "Unknown block",
    "details": [
      {
        "message": "Could not find reversible block: 19641",
        "file": "chain_plugin.cpp",
        "line_number": 2071,
        "method": "get_block_header_state"
      }
    ]
  }
}

Config

wasm-runtime = eos-vm
abi-serializer-max-time-ms = 15
chain-state-db-size-mb = 65536
# chain-threads = 2
contracts-console = true
http-server-address = 0.0.0.0:8888
p2p-listen-endpoint = 0.0.0.0:9876
state-history-endpoint = 0.0.0.0:8080
verbose-http-errors = true
# http-threads = 2
agent-name = "Eric Latest Nodeos"
net-threads = 2
max-transaction-time = 100
producer-name = eosio
enable-stale-production = true
# producer-threads = 2
# trace-history = false
# chain-state-history = false
resource-monitor-not-shutdown-on-threshold-exceeded=true
read-only-read-window-time-us = 150000
read-only-write-window-time-us = 50000

plugin = eosio::chain_api_plugin
plugin = eosio::chain_plugin
plugin = eosio::http_plugin
plugin = eosio::producer_plugin
plugin = eosio::producer_api_plugin
spoonincode commented 1 year ago

get_block_header_state can only return reversible blocks. While in your curl examples you do request the sole reversible block, it's not clear how back-to-back you made those requests: with a single producer a block becomes irreversible in 500ms, so there is only a valid block this endpoint can be used with for 500ms

Can you try something like

curl -d "{\"block_num_or_id\":$(curl -s http://127.0.0.1:8888/v1/chain/get_info | jq .fork_db_head_block_num)}" http://127.0.0.1:8888/v1/chain/get_block_header_state

This makes the request back-to-back so there is a higher (but not 100%) chance of success.

ericpassmore commented 1 year ago

Yep, the back to back requests worked on the command line.

When I run test for eosjs it still fails. The calls are one after another, but there is too much lag between the calls.

I recompiling with an increased block time of 2000ms, by updating libraries/chain/include/eosio/chain/config.hpp. That didn't work. It failed 33 tests, and once the chain was running I found it was still going producing blocks very quickly.

I'm guessing the only option is to speed up the eosjs code, to be as fast as possible.

spoonincode commented 1 year ago

If you need to keep using get_block_header_state (without knowing more details about the test it's difficult for me to know if there is a better alternative), one fairly easy workaround here is to simply run multiple producers. Running even 3 or 4 producers will increase the reversible time to many seconds. You can run multiple producers with a single node instance, you'd just

producer-name = eosio
producer-name = rick
producer-name = morty
producer-name = summer

or such.

The slightly more difficult part is you'll need to set the old bios contract so you can setprods the new producer schedule.

You'll need to do something like

cleos create account eosio rick EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
cleos create account eosio morty EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
cleos create account eosio summer EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV

Then install the old bios contract

cleos set contract eosio libraries/testing/contracts/old_versions/v1.6.0-rc3/eosio.bios

Then create a prods.json file like

{
  "schedule": [
   {"producer_name":"eosio","block_signing_key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"},
   {"producer_name":"rick","block_signing_key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"},
   {"producer_name":"morty","block_signing_key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"},
   {"producer_name":"summer","block_signing_key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"}
  ]
}

Then setprods

cleos push action eosio setprods "$(cat prods.json)" -p eosio@active

Now you should have a 4 producer chain thus a lot more leeway to call get_block_header_state

ericpassmore commented 1 year ago

Thanks, I did get the code to work, at the expense of a extra get_block_header_state call for send_transaction2. I'm closing this issue as not planned.

In eosjs, the refBlock from get_block_header_state is used to calculate and expiration and a prefix used in the transaction header. I feel comfortable calculating an expiration time without the refBlock timestamp. I don't understand what the prefix is or how it is used. Something to look into later.

/** TAPoS: Return transaction fields which reference `refBlock` and expire `expireSeconds` after `timestamp` */
export function transactionHeader(refBlock: BlockTaposInfo, expireSeconds: number) {
    const timestamp = refBlock.header ? refBlock.header.timestamp : refBlock.timestamp;
    const prefix = parseInt(reverseHex(refBlock.id.substring(16, 24)), 16);

    return {
        expiration: timePointSecToDate(dateToTimePointSec(timestamp) + expireSeconds),
        ref_block_num: refBlock.block_num & 0xffff,
        ref_block_prefix: prefix,
    };
}