Design and Implementation of Data Structure of EOCS Cross Chain Contract Zone

Core data structure analysis

1
2
3
< span class="line">4
5
6
struct { 
block_timestamp_type timestamp;
account_name producer;

static uint32_t num_from_id(const block_id_type& id);
}

The timestamp in the structure is the timestamp of the block packed, and the previous is the previous The id of a block, transaction_mroot represents the merkle root of all transactions, and action_root represents The merkle root of the action.
num_from_id find blocknum through blockid.

1
2
3
4
struct signed_block_header : block_header {
signature producer_signature;
EOSLIB_SERIALIZE_DERIVED(signed_block_header, block_header, (producer_signature))
};

struct signed_block_header :
This structure inherits block_header, contains producer_signature inside, and provides the signature of the producer
struct block_header_state:
Includes basic block information, blockid, blocknum, and signed_block_header signature header information.

struct block_header_with_merkle_path:
Include block_header of type block_header_state and merkle_path composed of id sequence. The blockid in this merkle_path needs to be linked one by one without interruption. In addition, the last blockid needs to point to the previous one of block_header id.

struct action_receipt :
Receipts for an action, including recipients, summary information, authorization order, acceptance order, encoding order, etc.
Using UML diagrams to indicate the relationship between the above categories:
1.jpg

Core api analysis

1
2
3
4
uint32_t block_header::num_from_id(const block_id_type& id)
{
?? return endian_reverse_u32(uint32_t(*reinterpret_cast<< span class="keyword">const uint64_t*>(id.hash)));
}

Take out the hash value of id, and then invert the upper 32 bits to obtain blocknum

1
2
3
4
5
6
checksum256 block_header::id() const {
auto result = sha256(*this);
*reinterpret_cast<uint64_t*>(result.hash) &= 0xffffffff00000000;
*reinterpret_cast< /span><uint64_t*>(result.hash) += endian_reverse_u32(block_num());
return result;
}

When calculating the id, set itself The 256hash value goes to the high 32 bits, inverted with the high 32 bits of blocknum() obtained before, and added to obtain the id number.

1< br>2
3
digest_type block_header::digest() const {
return sha256(*this);
}

To get the summary, it means to perform 256hash to get the summary.

1< br>2
3
4
5
6
7
template <typename T>
checksum256 sha256( const T& value) {
auto< /span> digest = pack(value);
checksum256 hash;
::sha256(digest.data (), uint32_t(digest.size()), &hash);
return hash;
}

Sha256 is a hash function based on a universal type template encapsulated by our eocs team. First, package the value, and then The hash result is stored in the variable hash, and this result is returned as the digest.

1< br>2
3
4
5
6
void block_header_state::validate() const {
< span class="line">auto d = sig_digest();
assert_recover_key(&d, (const char*)(header.producer_signature.data), 66, (const char*)(block_signing_key.data), 34);

eosio_assert(header.id() == id, "invalid block id" ); // TODO: necessary?
}

This function first calculates the digest, and then removes the producer signature information and block signature of the header according to the digest key value.
Next, determine whether the id of the header matches your id.

1< br>2
3
4
5
6
producer_key block_header_state::get_scheduled_producer(block_timestamp_type t)const {
// TODO: block_interval_ms/block_timestamp_epoch configurable?
auto index = t.slot% (active_schedule.producers.size() * producer_repetitions);
index /= producer_repetitions;
return active_schedule.producers[index];
}

This function gets polled producers, producer_repetitions is the number of repeated producers, index is divided by this number to get the number of polls, and then the corresponding producer is taken out according to the index in the polling table.

1
< span class="line">2
3
4
5
6
7
8
9
10
11
uint32_t block_header_state ::calc_dpos_last_irreversible()const {
vector<uint32_t> blocknums;
blocknums.reserve(producer_to_last_implied_irb.size());
for (auto& i: producer_to_last_implied_irb) {
blocknums.push_back(i .second);
}

if (blocknums.size() == 0) return 0;
std::sort(blocknums.begin(), blocknums.end());
return blocknums[(blocknums.size()-1) / 3];
}

This function calculates the last irreversible block num, first defines the sequence of blocknums, and then according to producer_to_last_implied_irb (containing irreversible blocks Producer map), put the corresponding block nums into the blocknums sequence, and then divide by three according to the sequence size -1 to get the block index, which is the final irreversible block number.

End here

Original text: Big column Design and implementation of eocs cross-chain contract block data structure

Leave a Comment

Your email address will not be published.