2016-09-08 21:13:10 +04:00
|
|
|
(**************************************************************************)
|
|
|
|
(* *)
|
|
|
|
(* Copyright (c) 2014 - 2016. *)
|
|
|
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
|
|
|
(* *)
|
|
|
|
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
|
|
|
(* *)
|
|
|
|
(**************************************************************************)
|
|
|
|
|
|
|
|
(** Tezos Protocol Implementation - Main Entry Points *)
|
|
|
|
|
|
|
|
open Tezos_context
|
|
|
|
|
2017-03-20 21:11:43 +04:00
|
|
|
type error += Wrong_voting_period of Voting_period.t * Voting_period.t (* `Temporary *)
|
|
|
|
type error += Wrong_endorsement_predecessor of Block_hash.t * Block_hash.t (* `Temporary *)
|
|
|
|
|
|
|
|
let () =
|
|
|
|
register_error_kind
|
|
|
|
`Temporary
|
|
|
|
~id:"operation.wrong_endorsement_predecessor"
|
|
|
|
~title:"Wrong endorsement predecessor"
|
|
|
|
~description:"Trying to include an endorsement in a block \
|
|
|
|
that is not the successor of the endorsed one"
|
|
|
|
~pp:(fun ppf (e, p) ->
|
|
|
|
Format.fprintf ppf "Wrong predecessor %a, expected %a"
|
|
|
|
Block_hash.pp p Block_hash.pp e)
|
|
|
|
Data_encoding.(obj2
|
|
|
|
(req "expected" Block_hash.encoding)
|
|
|
|
(req "provided" Block_hash.encoding))
|
|
|
|
(function Wrong_endorsement_predecessor (e, p) -> Some (e, p) | _ -> None)
|
|
|
|
(fun (e, p) -> Wrong_endorsement_predecessor (e, p)) ;
|
|
|
|
register_error_kind
|
|
|
|
`Temporary
|
|
|
|
~id:"operation.wrong_voting_period"
|
|
|
|
~title:"Wrong voting period"
|
|
|
|
~description:"Trying to onclude a proposal or ballot \
|
|
|
|
meant for another voting period"
|
|
|
|
~pp:(fun ppf (e, p) ->
|
|
|
|
Format.fprintf ppf "Wrong voting period %a, current is %a"
|
|
|
|
Voting_period.pp p Voting_period.pp e)
|
|
|
|
Data_encoding.(obj2
|
|
|
|
(req "current" Voting_period.encoding)
|
|
|
|
(req "provided" Voting_period.encoding))
|
|
|
|
(function Wrong_voting_period (e, p) -> Some (e, p) | _ -> None)
|
|
|
|
(fun (e, p) -> Wrong_voting_period (e, p))
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
|
|
let apply_delegate_operation_content
|
|
|
|
ctxt delegate pred_block block_priority = function
|
|
|
|
| Endorsement { block ; slot } ->
|
|
|
|
fail_unless
|
2017-03-20 21:11:43 +04:00
|
|
|
(Block_hash.equal block pred_block)
|
|
|
|
(Wrong_endorsement_predecessor (pred_block, block)) >>=? fun () ->
|
2016-09-08 21:13:10 +04:00
|
|
|
Mining.check_signing_rights ctxt slot delegate >>=? fun () ->
|
2017-04-10 14:14:11 +04:00
|
|
|
let ctxt = Fitness.increase ctxt in
|
2016-09-08 21:13:10 +04:00
|
|
|
Mining.pay_endorsement_bond ctxt delegate >>=? fun (ctxt, bond) ->
|
|
|
|
Mining.endorsement_reward ~block_priority >>=? fun reward ->
|
2017-04-10 15:01:22 +04:00
|
|
|
let { cycle = current_cycle } : Level.t = Level.current ctxt in
|
2016-09-08 21:13:10 +04:00
|
|
|
Lwt.return Tez.(reward +? bond) >>=? fun full_reward ->
|
|
|
|
Reward.record ctxt delegate current_cycle full_reward
|
|
|
|
| Proposals { period ; proposals } ->
|
2017-04-10 15:01:22 +04:00
|
|
|
let level = Level.current ctxt in
|
2016-09-08 21:13:10 +04:00
|
|
|
fail_unless Voting_period.(level.voting_period = period)
|
2017-03-20 21:11:43 +04:00
|
|
|
(Wrong_voting_period (level.voting_period, period)) >>=? fun () ->
|
2016-09-08 21:13:10 +04:00
|
|
|
Amendment.record_proposals ctxt delegate proposals
|
|
|
|
| Ballot { period ; proposal ; ballot } ->
|
2017-04-10 15:01:22 +04:00
|
|
|
let level = Level.current ctxt in
|
2016-09-08 21:13:10 +04:00
|
|
|
fail_unless Voting_period.(level.voting_period = period)
|
2017-03-20 21:11:43 +04:00
|
|
|
(Wrong_voting_period (level.voting_period, period)) >>=? fun () ->
|
2016-09-08 21:13:10 +04:00
|
|
|
Amendment.record_ballot ctxt delegate proposal ballot
|
|
|
|
|
|
|
|
type error += Non_scripted_contract_with_parameter
|
|
|
|
type error += Scripted_contract_without_paramater
|
|
|
|
|
2016-10-20 20:54:16 +04:00
|
|
|
let apply_manager_operation_content
|
|
|
|
ctxt origination_nonce source = function
|
2016-09-08 21:13:10 +04:00
|
|
|
| Transaction { amount ; parameters ; destination } -> begin
|
|
|
|
Contract.spend ctxt source amount >>=? fun ctxt ->
|
|
|
|
Contract.credit ctxt destination amount >>=? fun ctxt ->
|
|
|
|
Contract.get_script ctxt destination >>=? function
|
2017-03-09 22:17:13 +04:00
|
|
|
| None -> begin
|
2016-09-08 21:13:10 +04:00
|
|
|
match parameters with
|
2017-02-16 22:01:35 +04:00
|
|
|
| None | Some (Prim (_, "Unit", [])) ->
|
2016-10-20 20:54:16 +04:00
|
|
|
return (ctxt, origination_nonce, None)
|
2016-09-08 21:13:10 +04:00
|
|
|
| Some _ -> fail Non_scripted_contract_with_parameter
|
|
|
|
end
|
2017-03-09 22:17:13 +04:00
|
|
|
| Some { code ; storage } ->
|
2016-09-08 21:13:10 +04:00
|
|
|
match parameters with
|
|
|
|
| None -> fail Scripted_contract_without_paramater
|
|
|
|
| Some parameters ->
|
|
|
|
Script_interpreter.execute
|
2017-02-16 22:01:35 +04:00
|
|
|
origination_nonce
|
2016-09-08 21:13:10 +04:00
|
|
|
source destination ctxt storage code amount parameters
|
|
|
|
(Constants.instructions_per_transaction ctxt)
|
|
|
|
>>= function
|
2017-02-16 22:01:35 +04:00
|
|
|
| Ok (storage_res, _res, _steps, ctxt, origination_nonce) ->
|
2016-09-08 21:13:10 +04:00
|
|
|
(* TODO: pay for the steps and the storage diff:
|
|
|
|
update_script_storage checks the storage cost *)
|
2017-03-09 22:17:13 +04:00
|
|
|
Contract.update_script_storage_and_fees
|
|
|
|
ctxt destination
|
|
|
|
Script_interpreter.dummy_storage_fee storage_res >>=? fun ctxt ->
|
2016-10-20 20:54:16 +04:00
|
|
|
return (ctxt, origination_nonce, None)
|
2016-09-08 21:13:10 +04:00
|
|
|
| Error err ->
|
2016-10-20 20:54:16 +04:00
|
|
|
return (ctxt, origination_nonce, Some err)
|
2016-09-08 21:13:10 +04:00
|
|
|
end
|
|
|
|
| Origination { manager ; delegate ; script ;
|
2017-03-09 22:17:13 +04:00
|
|
|
spendable ; delegatable ; credit } ->
|
|
|
|
let script = match script with
|
|
|
|
| None -> None
|
|
|
|
| Some script ->
|
|
|
|
Some (script, (Script_interpreter.dummy_code_fee, Script_interpreter.dummy_storage_fee)) in
|
2017-03-20 17:37:01 +04:00
|
|
|
Contract.spend ctxt source Constants.origination_burn >>=? fun ctxt ->
|
2016-09-08 21:13:10 +04:00
|
|
|
Contract.spend ctxt source credit >>=? fun ctxt ->
|
|
|
|
Contract.originate ctxt
|
2017-02-16 22:01:35 +04:00
|
|
|
origination_nonce
|
2017-03-20 17:37:01 +04:00
|
|
|
~manager ~delegate ~balance:credit
|
2017-03-09 22:17:13 +04:00
|
|
|
?script
|
|
|
|
~spendable ~delegatable >>=? fun (ctxt, _, origination_nonce) ->
|
2016-10-20 20:54:16 +04:00
|
|
|
return (ctxt, origination_nonce, None)
|
2016-09-08 21:13:10 +04:00
|
|
|
| Delegation delegate ->
|
2017-02-16 22:01:35 +04:00
|
|
|
Contract.set_delegate ctxt source delegate >>=? fun ctxt ->
|
2016-10-20 20:54:16 +04:00
|
|
|
return (ctxt, origination_nonce, None)
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
|
|
let check_signature_and_update_public_key ctxt id public_key op =
|
|
|
|
begin
|
|
|
|
match public_key with
|
|
|
|
| None -> return ctxt
|
|
|
|
| Some public_key ->
|
2017-03-15 21:00:27 +04:00
|
|
|
Public_key.reveal ctxt id public_key
|
2016-09-08 21:13:10 +04:00
|
|
|
end >>=? fun ctxt ->
|
|
|
|
Public_key.get ctxt id >>=? fun public_key ->
|
|
|
|
Operation.check_signature public_key op >>=? fun () ->
|
|
|
|
return ctxt
|
|
|
|
|
|
|
|
let apply_sourced_operation
|
2016-10-20 20:54:16 +04:00
|
|
|
ctxt miner_contract pred_block block_prio
|
2017-02-16 22:01:35 +04:00
|
|
|
operation origination_nonce ops =
|
2016-09-08 21:13:10 +04:00
|
|
|
match ops with
|
|
|
|
| Manager_operations { source ; public_key ; fee ; counter ; operations = contents } ->
|
2017-03-09 22:17:13 +04:00
|
|
|
Contract.must_exist ctxt source >>=? fun () ->
|
2016-09-08 21:13:10 +04:00
|
|
|
Contract.get_manager ctxt source >>=? fun manager ->
|
|
|
|
check_signature_and_update_public_key
|
|
|
|
ctxt manager public_key operation >>=? fun ctxt ->
|
|
|
|
Contract.check_counter_increment
|
|
|
|
ctxt source counter >>=? fun () ->
|
|
|
|
Contract.increment_counter ctxt source >>=? fun ctxt ->
|
|
|
|
Contract.spend ctxt source fee >>=? fun ctxt ->
|
|
|
|
(match miner_contract with
|
|
|
|
| None -> return ctxt
|
|
|
|
| Some contract ->
|
|
|
|
Contract.credit ctxt contract fee) >>=? fun ctxt ->
|
2016-10-20 20:54:16 +04:00
|
|
|
fold_left_s (fun (ctxt, origination_nonce, err) content ->
|
|
|
|
match err with
|
|
|
|
| Some _ -> return (ctxt, origination_nonce, err)
|
|
|
|
| None ->
|
|
|
|
Contract.must_exist ctxt source >>=? fun () ->
|
|
|
|
apply_manager_operation_content
|
|
|
|
ctxt origination_nonce source content)
|
|
|
|
(ctxt, origination_nonce, None) contents
|
2016-09-08 21:13:10 +04:00
|
|
|
| Delegate_operations { source ; operations = contents } ->
|
2017-02-28 05:56:40 +04:00
|
|
|
let delegate = Ed25519.Public_key.hash source in
|
2016-09-08 21:13:10 +04:00
|
|
|
check_signature_and_update_public_key
|
|
|
|
ctxt delegate (Some source) operation >>=? fun ctxt ->
|
|
|
|
(* TODO, see how to extract the public key hash after this operation to
|
|
|
|
pass it to apply_delegate_operation_content *)
|
|
|
|
fold_left_s (fun ctxt content ->
|
|
|
|
apply_delegate_operation_content
|
|
|
|
ctxt delegate pred_block block_prio content)
|
|
|
|
ctxt contents >>=? fun ctxt ->
|
2016-10-20 20:54:16 +04:00
|
|
|
return (ctxt, origination_nonce, None)
|
2017-02-27 21:24:26 +04:00
|
|
|
| Dictator_operation (Activate hash) ->
|
|
|
|
let dictator_pubkey = Constants.dictator_pubkey ctxt in
|
|
|
|
Operation.check_signature dictator_pubkey operation >>=? fun () ->
|
|
|
|
activate ctxt hash >>= fun ctxt ->
|
2016-10-20 20:54:16 +04:00
|
|
|
return (ctxt, origination_nonce, None)
|
2017-02-27 21:24:26 +04:00
|
|
|
| Dictator_operation (Activate_testnet hash) ->
|
|
|
|
let dictator_pubkey = Constants.dictator_pubkey ctxt in
|
|
|
|
Operation.check_signature dictator_pubkey operation >>=? fun () ->
|
|
|
|
set_test_protocol ctxt hash >>= fun ctxt ->
|
|
|
|
fork_test_network ctxt >>= fun ctxt ->
|
2016-10-20 20:54:16 +04:00
|
|
|
return (ctxt, origination_nonce, None)
|
2016-09-08 21:13:10 +04:00
|
|
|
|
2017-02-28 05:48:51 +04:00
|
|
|
let apply_anonymous_operation ctxt miner_contract origination_nonce kind =
|
2016-09-08 21:13:10 +04:00
|
|
|
match kind with
|
|
|
|
| Seed_nonce_revelation { level ; nonce } ->
|
|
|
|
let level = Level.from_raw ctxt level in
|
2016-10-20 20:54:16 +04:00
|
|
|
Nonce.reveal ctxt level nonce
|
|
|
|
>>=? fun (ctxt, delegate_to_reward, reward_amount) ->
|
2016-09-08 21:13:10 +04:00
|
|
|
Reward.record ctxt
|
|
|
|
delegate_to_reward level.cycle reward_amount >>=? fun ctxt ->
|
2017-02-28 05:48:51 +04:00
|
|
|
begin
|
|
|
|
match miner_contract with
|
|
|
|
| None -> return (ctxt, origination_nonce)
|
|
|
|
| Some contract ->
|
|
|
|
Contract.credit
|
|
|
|
ctxt contract Constants.seed_nonce_revelation_tip >>=? fun ctxt ->
|
|
|
|
return (ctxt, origination_nonce)
|
|
|
|
end
|
|
|
|
| Faucet { id = manager } ->
|
|
|
|
(* Free tez for all! *)
|
|
|
|
begin
|
|
|
|
match miner_contract with
|
|
|
|
| None -> return None
|
|
|
|
| Some contract -> Contract.get_delegate_opt ctxt contract
|
|
|
|
end >>=? fun delegate ->
|
|
|
|
Contract.originate ctxt
|
|
|
|
origination_nonce
|
2017-03-09 22:17:13 +04:00
|
|
|
~manager ~delegate ~balance:Constants.faucet_credit ?script:None
|
2017-02-28 05:48:51 +04:00
|
|
|
~spendable:true ~delegatable:true >>=? fun (ctxt, _, origination_nonce) ->
|
|
|
|
return (ctxt, origination_nonce)
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
|
|
let apply_operation
|
2016-10-20 20:54:16 +04:00
|
|
|
ctxt miner_contract pred_block block_prio operation =
|
2016-09-08 21:13:10 +04:00
|
|
|
match operation.contents with
|
|
|
|
| Anonymous_operations ops ->
|
2017-02-28 05:48:51 +04:00
|
|
|
let origination_nonce = Contract.initial_origination_nonce operation.hash in
|
2016-09-08 21:13:10 +04:00
|
|
|
fold_left_s
|
2017-02-28 05:48:51 +04:00
|
|
|
(fun (ctxt, origination_nonce) ->
|
|
|
|
apply_anonymous_operation ctxt miner_contract origination_nonce)
|
|
|
|
(ctxt, origination_nonce) ops >>=? fun (ctxt, origination_nonce) ->
|
2016-10-20 20:54:16 +04:00
|
|
|
return (ctxt, Contract.originated_contracts origination_nonce, None)
|
2016-09-08 21:13:10 +04:00
|
|
|
| Sourced_operations op ->
|
2017-02-16 22:01:35 +04:00
|
|
|
let origination_nonce = Contract.initial_origination_nonce operation.hash in
|
2016-09-08 21:13:10 +04:00
|
|
|
apply_sourced_operation
|
2016-10-20 20:54:16 +04:00
|
|
|
ctxt miner_contract pred_block block_prio
|
|
|
|
operation origination_nonce op >>=? fun (ctxt, origination_nonce, err) ->
|
|
|
|
return (ctxt, Contract.originated_contracts origination_nonce, err)
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
|
|
let may_start_new_cycle ctxt =
|
|
|
|
Mining.dawn_of_a_new_cycle ctxt >>=? function
|
|
|
|
| None -> return ctxt
|
2017-04-10 15:01:22 +04:00
|
|
|
| Some last_cycle ->
|
|
|
|
let new_cycle = Cycle.succ last_cycle in
|
2017-02-24 20:14:20 +04:00
|
|
|
Bootstrap.refill ctxt >>=? fun ctxt ->
|
2016-09-08 21:13:10 +04:00
|
|
|
Seed.clear_cycle ctxt last_cycle >>=? fun ctxt ->
|
|
|
|
Seed.compute_for_cycle ctxt (Cycle.succ new_cycle) >>=? fun ctxt ->
|
|
|
|
Roll.clear_cycle ctxt last_cycle >>=? fun ctxt ->
|
2016-10-26 19:02:10 +04:00
|
|
|
Roll.freeze_rolls_for_cycle ctxt (Cycle.succ new_cycle) >>=? fun ctxt ->
|
2017-04-10 14:14:11 +04:00
|
|
|
let timestamp = Timestamp.current ctxt in
|
2016-09-08 21:13:10 +04:00
|
|
|
Lwt.return (Timestamp.(timestamp +? (Constants.time_before_reward ctxt)))
|
|
|
|
>>=? fun reward_date ->
|
|
|
|
Reward.set_reward_time_for_cycle
|
|
|
|
ctxt last_cycle reward_date >>=? fun ctxt ->
|
|
|
|
return ctxt
|
|
|
|
|
2016-10-20 20:54:16 +04:00
|
|
|
let begin_construction ctxt =
|
|
|
|
Fitness.increase ctxt
|
|
|
|
|
|
|
|
let begin_application ctxt block pred_timestamp =
|
2016-10-19 22:47:04 +04:00
|
|
|
Mining.check_proof_of_work_stamp ctxt block >>=? fun () ->
|
|
|
|
Mining.check_fitness_gap ctxt block >>=? fun () ->
|
2016-10-20 20:54:16 +04:00
|
|
|
Mining.check_mining_rights ctxt block pred_timestamp >>=? fun miner ->
|
|
|
|
Mining.check_signature ctxt block miner >>=? fun () ->
|
|
|
|
Mining.pay_mining_bond ctxt block miner >>=? fun ctxt ->
|
2017-04-10 14:14:11 +04:00
|
|
|
let ctxt = Fitness.increase ctxt in
|
2016-10-20 20:54:16 +04:00
|
|
|
return (ctxt, miner)
|
|
|
|
|
2017-04-10 14:14:11 +04:00
|
|
|
let finalize_application ctxt block miner =
|
2016-09-08 21:13:10 +04:00
|
|
|
(* end of level (from this point nothing should fail) *)
|
2017-04-10 15:01:22 +04:00
|
|
|
let priority = block.Block.proto.priority in
|
2017-04-02 18:07:19 +04:00
|
|
|
let reward = Mining.base_mining_reward ctxt ~priority in
|
2016-09-08 21:13:10 +04:00
|
|
|
Nonce.record_hash ctxt
|
2016-10-20 20:54:16 +04:00
|
|
|
miner reward block.proto.seed_nonce_hash >>=? fun ctxt ->
|
2016-09-08 21:13:10 +04:00
|
|
|
Reward.pay_due_rewards ctxt >>=? fun ctxt ->
|
|
|
|
(* end of cycle *)
|
|
|
|
may_start_new_cycle ctxt >>=? fun ctxt ->
|
|
|
|
Amendment.may_start_new_voting_cycle ctxt >>=? fun ctxt ->
|
2017-04-10 14:14:11 +04:00
|
|
|
return ctxt
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
|
|
let compare_operations op1 op2 =
|
|
|
|
match op1.contents, op2.contents with
|
|
|
|
| Anonymous_operations _, Anonymous_operations _ -> 0
|
2017-03-02 18:45:06 +04:00
|
|
|
| Anonymous_operations _, Sourced_operations _ -> -1
|
|
|
|
| Sourced_operations _, Anonymous_operations _ -> 1
|
2016-09-08 21:13:10 +04:00
|
|
|
| Sourced_operations op1, Sourced_operations op2 ->
|
|
|
|
match op1, op2 with
|
2017-02-27 21:24:26 +04:00
|
|
|
| Delegate_operations _, (Manager_operations _ | Dictator_operation _) -> -1
|
|
|
|
| Manager_operations _, Dictator_operation _ -> -1
|
|
|
|
| Dictator_operation _, Manager_operations _ -> 1
|
|
|
|
| (Manager_operations _ | Dictator_operation _), Delegate_operations _ -> 1
|
2016-09-08 21:13:10 +04:00
|
|
|
| Delegate_operations _, Delegate_operations _ -> 0
|
2017-02-27 21:24:26 +04:00
|
|
|
| Dictator_operation _, Dictator_operation _ -> 0
|
2016-09-08 21:13:10 +04:00
|
|
|
| Manager_operations op1, Manager_operations op2 -> begin
|
|
|
|
(* Manager operations with smaller counter are pre-validated first. *)
|
|
|
|
Int32.compare op1.counter op2.counter
|
|
|
|
end
|