574 lines
17 KiB
OCaml
574 lines
17 KiB
OCaml
(**************************************************************************)
|
|
(* *)
|
|
(* Copyright (c) 2014 - 2016. *)
|
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
|
(* *)
|
|
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
|
(* *)
|
|
(**************************************************************************)
|
|
|
|
open Tezos_hash
|
|
open Storage_functors
|
|
|
|
(* This key should always be populated for every version of the
|
|
protocol. It's absence meaning that the context is empty. *)
|
|
let version_key = ["version"]
|
|
let version_value = "alpha"
|
|
|
|
type error += Incompatiple_protocol_version
|
|
|
|
let is_first_block ctxt =
|
|
Context.get ctxt version_key >>= function
|
|
| None ->
|
|
return true
|
|
| Some bytes ->
|
|
let s = MBytes.to_string bytes in
|
|
if Compare.String.(s = version_value) then
|
|
return false
|
|
else if Compare.String.(s = "genesis") then
|
|
return true
|
|
else
|
|
fail Incompatiple_protocol_version
|
|
|
|
let version = "v1"
|
|
let first_level_key = [ version ; "first_level" ]
|
|
let sandboxed_key = [ version ; "sandboxed" ]
|
|
|
|
type t = Storage_functors.context
|
|
|
|
type error += Invalid_sandbox_parameter
|
|
|
|
let current_level { level } = level
|
|
let current_timestamp { timestamp } = timestamp
|
|
let current_fitness { fitness } = fitness
|
|
let set_current_fitness c fitness = { c with fitness }
|
|
|
|
let get_first_level ctxt =
|
|
Context.get ctxt first_level_key >>= function
|
|
| None -> failwith "Invalid context"
|
|
| Some bytes ->
|
|
match
|
|
Data_encoding.Binary.of_bytes Raw_level_repr.encoding bytes
|
|
with
|
|
| None -> failwith "Invalid context"
|
|
| Some level -> return level
|
|
|
|
let set_first_level ctxt level =
|
|
let bytes =
|
|
Data_encoding.Binary.to_bytes Raw_level_repr.encoding level in
|
|
Context.set ctxt first_level_key bytes >>= fun ctxt ->
|
|
return ctxt
|
|
|
|
let get_sandboxed c =
|
|
Context.get c sandboxed_key >>= function
|
|
| None -> return None
|
|
| Some bytes ->
|
|
match Data_encoding.Binary.of_bytes Data_encoding.json bytes with
|
|
| None -> fail Invalid_sandbox_parameter
|
|
| Some json -> return (Some json)
|
|
|
|
let set_sandboxed c json =
|
|
Context.set c sandboxed_key
|
|
(Data_encoding.Binary.to_bytes Data_encoding.json json)
|
|
|
|
let may_tag_first_block ctxt level =
|
|
is_first_block ctxt >>=? function
|
|
| false ->
|
|
get_first_level ctxt >>=? fun level ->
|
|
return (ctxt, false, level)
|
|
| true ->
|
|
Context.set ctxt version_key
|
|
(MBytes.of_string version_value) >>= fun ctxt ->
|
|
set_first_level ctxt level >>=? fun ctxt ->
|
|
return (ctxt, true, level)
|
|
|
|
let prepare ~level ~timestamp ~fitness ctxt =
|
|
Lwt.return (Raw_level_repr.of_int32 level ) >>=? fun level ->
|
|
Lwt.return (Fitness_repr.to_int64 fitness) >>=? fun fitness ->
|
|
may_tag_first_block ctxt level >>=? fun (ctxt, first_block, first_level) ->
|
|
get_sandboxed ctxt >>=? fun sandbox ->
|
|
Constants_repr.read sandbox >>=? function constants ->
|
|
let level =
|
|
Level_repr.from_raw
|
|
~first_level
|
|
~cycle_length:constants.Constants_repr.cycle_length
|
|
~voting_period_length:constants.Constants_repr.voting_period_length
|
|
level in
|
|
return ({ context = ctxt ; constants ; level ;
|
|
timestamp ; fitness ; first_level},
|
|
first_block)
|
|
let recover { context } : Context.t = context
|
|
|
|
let first_level { first_level } = first_level
|
|
let constants { constants } = constants
|
|
|
|
module Key = struct
|
|
|
|
let store_root tail = version :: "store" :: tail
|
|
|
|
let global_counter = store_root ["global_counter"]
|
|
|
|
let faucet_counter = store_root ["faucet_counter"]
|
|
|
|
let next_cycle_to_be_rewarded = store_root ["next_cycle_to_be_rewarded"]
|
|
let rewards = store_root ["rewards"]
|
|
|
|
let public_keys = ["public_keys" ; "ed25519"]
|
|
|
|
module Roll = struct
|
|
let store_root l = store_root ("rolls" :: l)
|
|
let next = store_root [ "next" ]
|
|
let limbo = store_root [ "limbo" ]
|
|
let roll_store roll l =
|
|
store_root @@ Int32.to_string (Roll_repr.to_int32 roll) :: l
|
|
let successor r = roll_store r ["successor"]
|
|
let owner r = roll_store r ["owner"]
|
|
end
|
|
|
|
module Cycle = struct
|
|
let store_root l = store_root ("cycles" :: l)
|
|
let cycle_store c l =
|
|
store_root @@ Int32.to_string (Cycle_repr.to_int32 c) :: l
|
|
let last_roll c = cycle_store c [ "last_roll" ]
|
|
let random_seed c = cycle_store c [ "random_seed" ]
|
|
let reward_date c = cycle_store c [ "reward_date" ]
|
|
let roll_owner (c, r) =
|
|
cycle_store c [ "roll_owners" ; Int32.to_string (Roll_repr.to_int32 r)]
|
|
let unrevealed_nonce_hash l =
|
|
let c = l.Level_repr.cycle in
|
|
cycle_store c [ "unrevealed_nonce_hash" ;
|
|
Int32.to_string l.Level_repr.cycle_position ]
|
|
end
|
|
|
|
module Contract = struct
|
|
|
|
let store_root l = store_root ("contracts" :: l)
|
|
let set = store_root ["set"]
|
|
let pubkey_contract l = store_root ("pubkey" :: l)
|
|
let generic_contract l = store_root ("generic" :: l)
|
|
let contract_store c l =
|
|
match c with
|
|
| Contract_repr.Default k ->
|
|
pubkey_contract @@ Ed25519.Public_key_hash.to_path k @ l
|
|
| Contract_repr.Originated h ->
|
|
generic_contract @@ Contract_hash.to_path h @ l
|
|
let roll_list c = contract_store c ["roll_list"]
|
|
let change c = contract_store c ["change"]
|
|
let balance c = contract_store c ["balance"]
|
|
let manager c = contract_store c ["manager"]
|
|
let spendable c = contract_store c ["spendable"]
|
|
let delegatable c = contract_store c ["delegatable"]
|
|
let delegate c = contract_store c ["delegate"]
|
|
let counter c = contract_store c ["counter"]
|
|
let code c = contract_store c ["code"]
|
|
let storage c = contract_store c ["storage"]
|
|
let code_fees c = contract_store c ["code_fees"]
|
|
let storage_fees c = contract_store c ["storage_fees"]
|
|
end
|
|
|
|
module Vote = struct
|
|
let store_root l = store_root ("votes" :: l)
|
|
let period_kind = store_root ["current_period_kind"]
|
|
let quorum = store_root ["current_quorum"]
|
|
let proposition = store_root ["current_proposition"]
|
|
let proposals = store_root ["proposals"]
|
|
let ballots = store_root ["ballots"]
|
|
let listings_size = store_root ["listings_size"]
|
|
let listings = store_root ["listings"]
|
|
end
|
|
|
|
end
|
|
|
|
(** Rolls *)
|
|
|
|
module Roll = struct
|
|
|
|
module Next =
|
|
Make_single_data_storage(struct
|
|
type value = Roll_repr.t
|
|
let name = "next fresh roll"
|
|
let key = Key.Roll.next
|
|
let encoding = Roll_repr.encoding
|
|
end)
|
|
|
|
module Limbo =
|
|
Make_single_optional_data_storage(struct
|
|
type value = Roll_repr.t
|
|
let name = "limbo"
|
|
let key = Key.Roll.limbo
|
|
let encoding = Roll_repr.encoding
|
|
end)
|
|
|
|
module Last_for_cycle =
|
|
Make_indexed_data_storage(struct
|
|
type key = Cycle_repr.t
|
|
type value = Roll_repr.t
|
|
let name = "last roll for current cycle"
|
|
let key = Key.Cycle.last_roll
|
|
let encoding = Roll_repr.encoding
|
|
end)
|
|
|
|
module Successor =
|
|
Make_indexed_optional_data_storage(struct
|
|
type key = Roll_repr.t
|
|
type value = Roll_repr.t
|
|
let name = "roll successor"
|
|
let key = Key.Roll.successor
|
|
let encoding = Roll_repr.encoding
|
|
end)
|
|
|
|
module Owner =
|
|
Make_indexed_data_storage(struct
|
|
type key = Roll_repr.t
|
|
type value = Contract_repr.t
|
|
let name = "roll owner"
|
|
let key = Key.Roll.owner
|
|
let encoding = Contract_repr.encoding
|
|
end)
|
|
|
|
module Owner_for_cycle =
|
|
Make_indexed_data_storage(struct
|
|
type key = Cycle_repr.t * Roll_repr.t
|
|
type value = Ed25519.Public_key_hash.t
|
|
let name = "roll owner for current cycle"
|
|
let key = Key.Cycle.roll_owner
|
|
let encoding = Ed25519.Public_key_hash.encoding
|
|
end)
|
|
|
|
module Contract_roll_list =
|
|
Make_indexed_optional_data_storage(struct
|
|
type key = Contract_repr.t
|
|
type value = Roll_repr.t
|
|
let name = "contract roll list"
|
|
let key = Key.Contract.roll_list
|
|
let encoding = Roll_repr.encoding
|
|
end)
|
|
|
|
module Contract_change =
|
|
Make_indexed_data_storage(struct
|
|
type key = Contract_repr.t
|
|
type value = Tez_repr.t
|
|
let name = "contract change"
|
|
let key = Key.Contract.change
|
|
let encoding = Tez_repr.encoding
|
|
end)
|
|
|
|
end
|
|
|
|
(** Contracts handling *)
|
|
|
|
module Contract = struct
|
|
|
|
module Global_counter =
|
|
Make_single_data_storage(struct
|
|
type value = int32
|
|
let name = "global counter"
|
|
let key = Key.global_counter
|
|
let encoding = Data_encoding.int32
|
|
end)
|
|
|
|
module Faucet_counter =
|
|
Make_single_data_storage(struct
|
|
type value = int32
|
|
let name = "faucet counter"
|
|
let key = Key.faucet_counter
|
|
let encoding = Data_encoding.int32
|
|
end)
|
|
|
|
(** FIXME REMOVE : use 'list' *)
|
|
module Set =
|
|
Make_data_set_storage(struct
|
|
type value = Contract_repr.t
|
|
let name = "contract set"
|
|
let key = Key.Contract.set
|
|
let encoding = Contract_repr.encoding
|
|
end)
|
|
|
|
module Balance =
|
|
Make_indexed_data_storage(
|
|
struct
|
|
type key = Contract_repr.t
|
|
type value = Tez_repr.t
|
|
let name = "contract balance"
|
|
let key = Key.Contract.balance
|
|
let encoding = Tez_repr.encoding
|
|
end)
|
|
|
|
module Manager =
|
|
Make_indexed_data_storage(struct
|
|
type key = Contract_repr.t
|
|
type value = Ed25519.Public_key_hash.t
|
|
let name = "contract manager"
|
|
let key = Key.Contract.manager
|
|
let encoding = Ed25519.Public_key_hash.encoding
|
|
end)
|
|
|
|
module Spendable =
|
|
Make_indexed_data_storage(struct
|
|
type key = Contract_repr.t
|
|
type value = bool
|
|
let name = "contract spendable"
|
|
let key = Key.Contract.spendable
|
|
let encoding = Data_encoding.bool
|
|
end)
|
|
|
|
module Delegatable =
|
|
Make_indexed_data_storage(struct
|
|
type key = Contract_repr.t
|
|
type value = bool
|
|
let name = "contract delegatable"
|
|
let key = Key.Contract.delegatable
|
|
let encoding = Data_encoding.bool
|
|
end)
|
|
|
|
module Delegate =
|
|
Make_indexed_data_storage(struct
|
|
type key = Contract_repr.t
|
|
type value = Ed25519.Public_key_hash.t
|
|
let name = "contract delegate"
|
|
let key = Key.Contract.delegate
|
|
let encoding = Ed25519.Public_key_hash.encoding
|
|
end)
|
|
|
|
module Counter =
|
|
Make_indexed_data_storage(struct
|
|
type key = Contract_repr.t
|
|
type value = Int32.t
|
|
let name = "contract counter"
|
|
let key = Key.Contract.counter
|
|
let encoding = Data_encoding.int32
|
|
end)
|
|
|
|
module Code =
|
|
Make_indexed_data_storage(struct
|
|
type key = Contract_repr.t
|
|
type value = Script_repr.code
|
|
let name = "contract code"
|
|
let key = Key.Contract.code
|
|
let encoding = Script_repr.code_encoding
|
|
end)
|
|
|
|
module Storage =
|
|
Make_indexed_data_storage(struct
|
|
type key = Contract_repr.t
|
|
type value = Script_repr.storage
|
|
let name = "contract storage"
|
|
let key = Key.Contract.storage
|
|
let encoding = Script_repr.storage_encoding
|
|
end)
|
|
|
|
module Code_fees =
|
|
Make_indexed_data_storage(struct
|
|
type key = Contract_repr.t
|
|
type value = Tez_repr.t
|
|
let name = "contract code fees"
|
|
let key = Key.Contract.code_fees
|
|
let encoding = Tez_repr.encoding
|
|
end)
|
|
|
|
module Storage_fees =
|
|
Make_indexed_data_storage(struct
|
|
type key = Contract_repr.t
|
|
type value = Tez_repr.t
|
|
let name = "contract storage fees"
|
|
let key = Key.Contract.storage_fees
|
|
let encoding = Tez_repr.encoding
|
|
end)
|
|
|
|
end
|
|
|
|
(** Votes **)
|
|
|
|
module Vote = struct
|
|
|
|
module Current_period_kind =
|
|
Make_single_data_storage(struct
|
|
type value = Voting_period_repr.kind
|
|
let name = "current period kind"
|
|
let key = Key.Vote.period_kind
|
|
let encoding = Voting_period_repr.kind_encoding
|
|
end)
|
|
|
|
module Current_quorum =
|
|
Make_single_data_storage(struct
|
|
type value = int32
|
|
let name = "current quorum"
|
|
let key = Key.Vote.quorum
|
|
let encoding = Data_encoding.int32
|
|
end)
|
|
|
|
module Current_proposal =
|
|
Make_single_data_storage(struct
|
|
type value = Protocol_hash.t
|
|
let name = "current proposal"
|
|
let key = Key.Vote.proposition
|
|
let encoding = Protocol_hash.encoding
|
|
end)
|
|
|
|
module Listings_size =
|
|
Make_single_data_storage(struct
|
|
type value = int32
|
|
let name = "listing size"
|
|
let key = Key.Vote.listings_size
|
|
let encoding = Data_encoding.int32
|
|
end)
|
|
|
|
module Listings =
|
|
Make_iterable_data_storage (Ed25519.Public_key_hash)
|
|
(struct
|
|
type value = int32
|
|
let key = Key.Vote.listings
|
|
let name = "listings"
|
|
let encoding = Data_encoding.int32
|
|
end)
|
|
|
|
module Proposals =
|
|
Make_data_set_storage
|
|
(struct
|
|
type value = Protocol_hash.t * Ed25519.Public_key_hash.t
|
|
let name = "proposals"
|
|
let encoding =
|
|
Data_encoding.tup2
|
|
Protocol_hash.encoding Ed25519.Public_key_hash.encoding
|
|
let key = Key.Vote.proposals
|
|
end)
|
|
|
|
module Ballots =
|
|
Make_iterable_data_storage (Ed25519.Public_key_hash)
|
|
(struct
|
|
type value = Vote_repr.ballot
|
|
let key = Key.Vote.ballots
|
|
let name = "ballot"
|
|
let encoding = Vote_repr.ballot_encoding
|
|
end)
|
|
|
|
end
|
|
|
|
(** Keys *)
|
|
|
|
module Public_key =
|
|
Make_iterable_data_storage (Ed25519.Public_key_hash)
|
|
(struct
|
|
type value = Ed25519.Public_key.t
|
|
let key = Key.public_keys
|
|
let name = "public keys"
|
|
let encoding = Ed25519.Public_key.encoding
|
|
end)
|
|
|
|
(** Seed *)
|
|
|
|
module Seed = struct
|
|
|
|
type nonce_status =
|
|
| Unrevealed of {
|
|
nonce_hash: Tezos_hash.Nonce_hash.t ;
|
|
delegate_to_reward: Ed25519.Public_key_hash.t ;
|
|
reward_amount: Tez_repr.t ;
|
|
}
|
|
| Revealed of Seed_repr.nonce
|
|
|
|
module Nonce =
|
|
Make_indexed_data_storage(struct
|
|
type key = Level_repr.level
|
|
type value = nonce_status
|
|
let name = "unrevealed nonce hash"
|
|
let key = Key.Cycle.unrevealed_nonce_hash
|
|
let encoding =
|
|
let open Data_encoding in
|
|
union [
|
|
case ~tag:0
|
|
(tup3
|
|
Nonce_hash.encoding
|
|
Ed25519.Public_key_hash.encoding
|
|
Tez_repr.encoding
|
|
)
|
|
(function
|
|
| Unrevealed { nonce_hash ; delegate_to_reward ; reward_amount } ->
|
|
Some (nonce_hash, delegate_to_reward, reward_amount)
|
|
| _ -> None)
|
|
(fun (nonce_hash, delegate_to_reward, reward_amount) ->
|
|
Unrevealed { nonce_hash ; delegate_to_reward ; reward_amount }) ;
|
|
case ~tag:1
|
|
Seed_repr.nonce_encoding
|
|
(function
|
|
| Revealed nonce -> Some nonce
|
|
| _ -> None)
|
|
(fun nonce -> Revealed nonce)
|
|
]
|
|
end)
|
|
|
|
module For_cycle =
|
|
Make_indexed_data_storage(struct
|
|
type key = Cycle_repr.t
|
|
type value = Seed_repr.seed
|
|
let name = "cycle random seed"
|
|
let key = Key.Cycle.random_seed
|
|
let encoding = Seed_repr.seed_encoding
|
|
end)
|
|
|
|
end
|
|
|
|
(** Rewards *)
|
|
|
|
module Rewards = struct
|
|
|
|
module Next =
|
|
Make_single_data_storage(struct
|
|
type value = Cycle_repr.t
|
|
let name = "reward cycle"
|
|
let key = Key.next_cycle_to_be_rewarded
|
|
let encoding = Cycle_repr.encoding
|
|
end)
|
|
|
|
module Date =
|
|
Make_indexed_data_storage(struct
|
|
type key = Cycle_repr.t
|
|
type value = Time_repr.t
|
|
let name = "reward timestamp"
|
|
let key = Key.Cycle.reward_date
|
|
let encoding = Time_repr.encoding
|
|
end)
|
|
|
|
module Amount =
|
|
Raw_make_iterable_data_storage(struct
|
|
type t = Ed25519.Public_key_hash.t * Cycle_repr.t
|
|
let prefix = Key.rewards
|
|
let length = Ed25519.Public_key_hash.path_length + 1
|
|
let to_path (pkh, c) =
|
|
Ed25519.Public_key_hash.to_path pkh @
|
|
[Int32.to_string (Cycle_repr.to_int32 c)]
|
|
let of_path p =
|
|
match List.rev p with
|
|
| [] -> assert false
|
|
| cycle :: rev_pkh ->
|
|
(Ed25519.Public_key_hash.of_path_exn (List.rev rev_pkh),
|
|
Cycle_repr.of_int32_exn @@ Int32.of_string cycle)
|
|
let compare (pkh1, c1) (pkh2, c2) =
|
|
let cmp1 = Ed25519.Public_key_hash.compare pkh1 pkh2 in
|
|
if Compare.Int.(cmp1 = 0) then Cycle_repr.compare c1 c2
|
|
else cmp1
|
|
end)(struct
|
|
type value = Tez_repr.t
|
|
let name = "level miner contract"
|
|
let encoding = Tez_repr.encoding
|
|
end)
|
|
|
|
end
|
|
|
|
let activate ({ context = c } as s) h =
|
|
Updater.activate c h >>= fun c -> Lwt.return { s with context = c }
|
|
let fork_test_network ({ context = c } as s) protocol expiration =
|
|
Updater.fork_test_network c ~protocol ~expiration >>= fun c ->
|
|
Lwt.return { s with context = c }
|
|
|
|
(** Resolver *)
|
|
|
|
let () =
|
|
Storage_functors.register_resolvers
|
|
(module Contract_hash)
|
|
[ Key.Contract.generic_contract [] ] ;
|
|
Storage_functors.register_resolvers
|
|
(module Ed25519.Public_key_hash)
|
|
[ Key.Contract.pubkey_contract [] ;
|
|
Key.public_keys ]
|