starcoin-framework

Module 0x1::Block

Block module provide metadata for generated blocks.

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;

Resource BlockMetadata

Block metadata struct.

struct BlockMetadata has key
Fields
number: u64
number of the current block
parent_hash: vector<u8>
Hash of the parent block.
author: address
Author of the current block.
uncles: u64
number of uncles.
new_block_events: Event::EventHandle<Block::NewBlockEvent>
Handle of events when new blocks are emitted

Struct NewBlockEvent

Events emitted when new block generated.

struct NewBlockEvent has drop, store
Fields
number: u64
author: address
timestamp: u64
uncles: u64

Struct Checkpoint

struct Checkpoint has copy, drop, store
Fields
block_number: u64
block_hash: vector<u8>
state_root: Option::Option<vector<u8>>

Resource Checkpoints

struct Checkpoints has store, key
Fields
checkpoints: Ring::Ring<Block::Checkpoint>
index: u64
last_number: u64

Constants

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;

Function initialize

This can only be invoked by the GENESIS_ACCOUNT at genesis

public fun initialize(account: &signer, parent_hash: vector<u8>)
Implementation
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),
        });
}
Specification
aborts_if !Timestamp::is_genesis();
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
aborts_if exists<BlockMetadata>(Signer::address_of(account));

Function get_current_block_number

Get the current block number

public fun get_current_block_number(): u64
Implementation
public fun get_current_block_number(): u64 acquires BlockMetadata {
  borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).number
}
Specification
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());

Function get_parent_hash

Get the hash of the parent block.

public fun get_parent_hash(): vector<u8>
Implementation
public fun get_parent_hash(): vector<u8> acquires BlockMetadata {
  *&borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).parent_hash
}
Specification
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());

Function get_current_author

Gets the address of the author of the current block

public fun get_current_author(): address
Implementation
public fun get_current_author(): address acquires BlockMetadata {
  borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).author
}
Specification
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());

Function 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)
Implementation
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,
      }
    );
}
Specification
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());
}

Function checkpoints_init

public fun checkpoints_init(account: &signer)
Implementation
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,
    });
}
Specification
pragma verify = false;

Function checkpoint_entry

public entry fun checkpoint_entry(_account: signer)
Implementation
public entry fun checkpoint_entry(_account: signer) acquires BlockMetadata, Checkpoints {
    checkpoint();
}
Specification
pragma verify = false;

Function checkpoint

public fun checkpoint()
Implementation
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);

}
Specification
pragma verify = false;

Function base_checkpoint

fun base_checkpoint(checkpoints: &mut Block::Checkpoints, parent_block_number: u64, parent_block_hash: vector<u8>)
Implementation
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);
    }
}
Specification
pragma verify = false;

Function latest_state_root

public fun latest_state_root(): (u64, vector<u8>)
Implementation
public fun latest_state_root():(u64,vector<u8>) acquires  Checkpoints{
    let checkpoints = borrow_global<Checkpoints>(CoreAddresses::GENESIS_ADDRESS());
    base_latest_state_root(checkpoints)
}
Specification
pragma verify = false;

Function base_latest_state_root

fun base_latest_state_root(checkpoints: &Block::Checkpoints): (u64, vector<u8>)
Implementation
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)
}
Specification
pragma verify = false;

Function update_state_root_entry

public entry fun update_state_root_entry(_account: signer, header: vector<u8>)
Implementation
public entry fun update_state_root_entry(_account: signer , header: vector<u8>)
acquires Checkpoints {
    update_state_root(header);
}
Specification
pragma verify = false;

Function update_state_root

public fun update_state_root(header: vector<u8>)
Implementation
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);
}
Specification
pragma verify = false;

Function base_update_state_root

fun base_update_state_root(checkpoints: &mut Block::Checkpoints, header: vector<u8>)
Implementation
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)
}
Specification
pragma verify = false;

Module Specification

pragma verify;
pragma aborts_if_is_strict = true;