0x1::Block
Block module provide metadata for generated blocks.
BlockMetadata
NewBlockEvent
Checkpoint
Checkpoints
initialize
get_current_block_number
get_parent_hash
get_current_author
process_block_metadata
checkpoints_init
checkpoint_entry
checkpoint
base_checkpoint
latest_state_root
base_latest_state_root
update_state_root_entry
update_state_root
base_update_state_root
use 0x1::BCS;
use 0x1::CoreAddresses;
use 0x1::Errors;
use 0x1::Event;
use 0x1::Hash;
use 0x1::Option;
use 0x1::Ring;
use 0x1::Timestamp;
use 0x1::Vector;
BlockMetadata
Block metadata struct.
struct BlockMetadata has key
number: u64
parent_hash: vector<u8>
author: address
uncles: u64
new_block_events: Event::EventHandle<Block::NewBlockEvent>
NewBlockEvent
Events emitted when new block generated.
struct NewBlockEvent has drop, store
number: u64
author: address
timestamp: u64
uncles: u64
Checkpoint
struct Checkpoint has copy, drop, store
block_number: u64
block_hash: vector<u8>
state_root: Option::Option<vector<u8>>
Checkpoints
struct Checkpoints has store, key
checkpoints: Ring::Ring<Block::Checkpoint>
index: u64
last_number: u64
const BLOCK_HEADER_LENGTH: u64 = 247;
const BLOCK_INTERVAL_NUMBER: u64 = 5;
const CHECKPOINT_LENGTH: u64 = 60;
const EBLOCK_NUMBER_MISMATCH: u64 = 17;
const ERROR_INTERVAL_TOO_LITTLE: u64 = 20;
const ERROR_NOT_BLOCK_HEADER: u64 = 19;
const ERROR_NO_HAVE_CHECKPOINT: u64 = 18;
initialize
This can only be invoked by the GENESIS_ACCOUNT at genesis
public fun initialize(account: &signer, parent_hash: vector<u8>)
public fun initialize(account: &signer, parent_hash: vector<u8>) {
Timestamp::assert_genesis();
CoreAddresses::assert_genesis_address(account);
move_to<BlockMetadata>(
account,
BlockMetadata {
number: 0,
parent_hash: parent_hash,
author: CoreAddresses::GENESIS_ADDRESS(),
uncles: 0,
new_block_events: Event::new_event_handle<Self::NewBlockEvent>(account),
});
}
aborts_if !Timestamp::is_genesis();
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
aborts_if exists<BlockMetadata>(Signer::address_of(account));
get_current_block_number
Get the current block number
public fun get_current_block_number(): u64
public fun get_current_block_number(): u64 acquires BlockMetadata {
borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).number
}
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
get_parent_hash
Get the hash of the parent block.
public fun get_parent_hash(): vector<u8>
public fun get_parent_hash(): vector<u8> acquires BlockMetadata {
*&borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).parent_hash
}
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
get_current_author
Gets the address of the author of the current block
public fun get_current_author(): address
public fun get_current_author(): address acquires BlockMetadata {
borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).author
}
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
process_block_metadata
Call at block prologue
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>, author: address, timestamp: u64, uncles: u64, number: u64)
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>,author: address, timestamp: u64, uncles:u64, number:u64) acquires BlockMetadata{
CoreAddresses::assert_genesis_address(account);
let block_metadata_ref = borrow_global_mut<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
assert!(number == (block_metadata_ref.number + 1), Errors::invalid_argument(EBLOCK_NUMBER_MISMATCH));
block_metadata_ref.number = number;
block_metadata_ref.author= author;
block_metadata_ref.parent_hash = parent_hash;
block_metadata_ref.uncles = uncles;
Event::emit_event<NewBlockEvent>(
&mut block_metadata_ref.new_block_events,
NewBlockEvent {
number: number,
author: author,
timestamp: timestamp,
uncles: uncles,
}
);
}
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
aborts_if number != global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).number + 1;
schema AbortsIfBlockMetadataNotExist {
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
}
checkpoints_init
public fun checkpoints_init(account: &signer)
public fun checkpoints_init(account: &signer){
CoreAddresses::assert_genesis_address(account);
let checkpoints = Ring::create_with_capacity<Checkpoint>(CHECKPOINT_LENGTH);
move_to<Checkpoints>(
account,
Checkpoints {
checkpoints,
index : 0,
last_number : 0,
});
}
pragma verify = false;
checkpoint_entry
public entry fun checkpoint_entry(_account: signer)
public entry fun checkpoint_entry(_account: signer) acquires BlockMetadata, Checkpoints {
checkpoint();
}
pragma verify = false;
checkpoint
public fun checkpoint()
public fun checkpoint() acquires BlockMetadata, Checkpoints{
let parent_block_number = get_current_block_number() - 1;
let parent_block_hash = get_parent_hash();
let checkpoints = borrow_global_mut<Checkpoints>(CoreAddresses::GENESIS_ADDRESS());
base_checkpoint(checkpoints, parent_block_number, parent_block_hash);
}
pragma verify = false;
base_checkpoint
fun base_checkpoint(checkpoints: &mut Block::Checkpoints, parent_block_number: u64, parent_block_hash: vector<u8>)
fun base_checkpoint(checkpoints: &mut Checkpoints, parent_block_number: u64, parent_block_hash:vector<u8>){
assert!(checkpoints.last_number + BLOCK_INTERVAL_NUMBER <= parent_block_number || checkpoints.last_number == 0, Errors::invalid_argument(ERROR_INTERVAL_TOO_LITTLE));
checkpoints.index = checkpoints.index + 1;
checkpoints.last_number = parent_block_number;
let op_checkpoint = Ring::push<Checkpoint>(&mut checkpoints.checkpoints, Checkpoint {
block_number: parent_block_number,
block_hash: parent_block_hash,
state_root: Option::none<vector<u8>>(),
} );
if(Option::is_some(&op_checkpoint)){
Option::destroy_some(op_checkpoint);
}else{
Option::destroy_none(op_checkpoint);
}
}
pragma verify = false;
latest_state_root
public fun latest_state_root(): (u64, vector<u8>)
public fun latest_state_root():(u64,vector<u8>) acquires Checkpoints{
let checkpoints = borrow_global<Checkpoints>(CoreAddresses::GENESIS_ADDRESS());
base_latest_state_root(checkpoints)
}
pragma verify = false;
base_latest_state_root
fun base_latest_state_root(checkpoints: &Block::Checkpoints): (u64, vector<u8>)
fun base_latest_state_root(checkpoints: &Checkpoints):(u64,vector<u8>){
let len = Ring::capacity<Checkpoint>(&checkpoints.checkpoints);
let j = if(checkpoints.index < len - 1){
checkpoints.index
}else{
len
};
let i = checkpoints.index;
while( j > 0){
let op_checkpoint = Ring::borrow(&checkpoints.checkpoints, i - 1 );
if( Option::is_some(op_checkpoint) && Option::is_some(&Option::borrow(op_checkpoint).state_root) ) {
let state_root = Option::borrow(&Option::borrow(op_checkpoint).state_root);
return (Option::borrow(op_checkpoint).block_number, *state_root)
};
j = j - 1;
i = i - 1;
};
abort Errors::invalid_state(ERROR_NO_HAVE_CHECKPOINT)
}
pragma verify = false;
update_state_root_entry
public entry fun update_state_root_entry(_account: signer, header: vector<u8>)
public entry fun update_state_root_entry(_account: signer , header: vector<u8>)
acquires Checkpoints {
update_state_root(header);
}
pragma verify = false;
update_state_root
public fun update_state_root(header: vector<u8>)
public fun update_state_root(header: vector<u8>) acquires Checkpoints {
let checkpoints = borrow_global_mut<Checkpoints>(CoreAddresses::GENESIS_ADDRESS());
base_update_state_root(checkpoints, header);
}
pragma verify = false;
base_update_state_root
fun base_update_state_root(checkpoints: &mut Block::Checkpoints, header: vector<u8>)
fun base_update_state_root(checkpoints: &mut Checkpoints, header: vector<u8>){
let prefix = Hash::sha3_256(b"STARCOIN::BlockHeader");
//parent_hash
let new_offset = BCS::skip_bytes(&header,0);
//timestamp
let new_offset = BCS::skip_u64(&header,new_offset);
//number
let (number,new_offset) = BCS::deserialize_u64(&header,new_offset);
//author
new_offset = BCS::skip_address(&header,new_offset);
//author_auth_key
new_offset = BCS::skip_option_bytes(&header,new_offset);
//txn_accumulator_root
new_offset = BCS::skip_bytes(&header,new_offset);
//block_accumulator_root
new_offset = BCS::skip_bytes(&header,new_offset);
//state_root
let (state_root,_new_offset) = BCS::deserialize_bytes(&header,new_offset);
Vector::append(&mut prefix,header);
let block_hash = Hash::sha3_256(prefix);
let len = Ring::capacity<Checkpoint>(&checkpoints.checkpoints);
let j = if(checkpoints.index < len - 1){
checkpoints.index
}else{
len
};
let i = checkpoints.index;
while( j > 0){
let op_checkpoint = Ring::borrow_mut(&mut checkpoints.checkpoints, i - 1);
if( Option::is_some(op_checkpoint) && &Option::borrow(op_checkpoint).block_hash == &block_hash && Option::borrow<Checkpoint>(op_checkpoint).block_number == number) {
let op_state_root = &mut Option::borrow_mut<Checkpoint>(op_checkpoint).state_root;
if(Option::is_some(op_state_root)){
Option::swap(op_state_root, state_root);
}else{
Option::fill(op_state_root, state_root);
};
return
};
j = j - 1;
i = i - 1;
};
abort Errors::invalid_state(ERROR_NO_HAVE_CHECKPOINT)
}
pragma verify = false;
pragma verify;
pragma aborts_if_is_strict = true;