diff --git a/content/systems/filecoin_vm/_index.md b/content/systems/filecoin_vm/_index.md index 42dcd74e7..c24cbf9e6 100644 --- a/content/systems/filecoin_vm/_index.md +++ b/content/systems/filecoin_vm/_index.md @@ -4,11 +4,15 @@ description: VM - Virtual Machine bookCollapseSection: true weight: 3 dashboardWeight: 2 -dashboardState: wip +dashboardState: reliable dashboardAudit: missing dashboardTests: 0 --- -# VM - Virtual Machine +# Virtual Machine -{{}} +An Actor in the Filecoin Blockchain is the equivalent of the smart contract in the Ethereum Virtual Machine. Actors carry the logic needed in order to submit transactions, proofs and blocks, among other things, to the Filecoin blockchain. Every actor is identified by a unique address. + +The Filecoin Virtual Machine (VM) is the system component that is in charge of execution of all actors code. Execution of actors on the Filecoin VM (i.e., on-chain executions) incur a gas cost. + +Any operation applied (i.e., executed) on the Filecoin VM produces an output in the form of a _State Tree_ (discussed below). The latest _State Tree_ is the current source of truth in the Filecoin Blockchain. The _State Tree_ is identified by a CID, which is stored in the IPLD store. \ No newline at end of file diff --git a/content/systems/filecoin_vm/actor/_index.md b/content/systems/filecoin_vm/actor/_index.md index 785e03ddc..cd4d9a1a1 100644 --- a/content/systems/filecoin_vm/actor/_index.md +++ b/content/systems/filecoin_vm/actor/_index.md @@ -2,14 +2,21 @@ title: Actor weight: 1 dashboardWeight: 2 -dashboardState: wip +dashboardState: reliable dashboardAudit: wip dashboardTests: 0 --- # VM Actor Interface +As mentioned above, Actors are the Filecoin equivalent of smart contracts in the Ethereum Virtual Machine. As such, Actors are very central components of the system. Any change to the current state of the Filecoin blockchain has to be triggered through an actor method invocation. -{{}} +This sub-section describes the _interface_ between Actors and the Filecoin Virtual Machine. This means that most of what is described below does not strictly belong to the VM. Instead it is logic that sits on the interface between the VM and Actors logic. -{{}} +There are eleven (11) types of _builtin_ Actors in total, not all of which interact with the VM. Some Actors do not invoke changes to the StateTree of the blockchain and therefore, do not need to have an interface to the VM. We discuss the details of all System Actors later on in the System Actors subsection. + +The _actor address_ is a stable address generated by hashing the sender's public key and a creation nonce. It should be stable across chain re-organizations. The _actor ID address_ on the other hand, is an auto-incrementing address that is compact but can change in case of chain re-organizations. That being said, after being created, actors should use an _actor address_. + +{{}} + +The `ActorState` structure is composed of the actor's balance, in terms of tokens held by this actor, as well as a group of state methods used to query, inspect and interact with chain state. \ No newline at end of file diff --git a/content/systems/filecoin_vm/actor/actor.go b/content/systems/filecoin_vm/actor/actor.go deleted file mode 100644 index 569a99b57..000000000 --- a/content/systems/filecoin_vm/actor/actor.go +++ /dev/null @@ -1,16 +0,0 @@ -package actor - -import ( - util "github.com/filecoin-project/specs/util" - cid "github.com/ipfs/go-cid" -) - -var IMPL_FINISH = util.IMPL_FINISH -var IMPL_TODO = util.IMPL_TODO -var TODO = util.TODO - -type Serialization = util.Serialization - -func (st *ActorState_I) CID() cid.Cid { - panic("TODO") -} diff --git a/content/systems/filecoin_vm/actor/actor.id b/content/systems/filecoin_vm/actor/actor.id deleted file mode 100644 index 6e256595e..000000000 --- a/content/systems/filecoin_vm/actor/actor.id +++ /dev/null @@ -1,62 +0,0 @@ -// This contains actor things that are _outside_ of VM exection. -// The VM uses this to execute abi. - -import abi "github.com/filecoin-project/specs-actors/actors/abi" -import actor "github.com/filecoin-project/specs-actors/actors" -import cid "github.com/ipfs/go-cid" - -// CallSeqNum is an invocation (Call) sequence (Seq) number (Num). -// This is a value used for securing against replay attacks: -// each AccountActor (user) invocation must have a unique CallSeqNum -// value. The sequenctiality of the numbers is used to make it -// easy to verify, and to order messages. -// -// Q&A -// - > Does it have to be sequential? -// No, a random nonce could work against replay attacks, but -// making it sequential makes it much easier to verify. -// - > Can it be used to order events? -// Yes, a user may submit N separate messages with increasing -// sequence number, causing them to execute in order. -// -type CallSeqNum int64 - -// Actor is a base computation object in the Filecoin VM. Similar -// to Actors in the Actor Model (programming), or Objects in Object- -// Oriented Programming, or Ethereum Contracts in the EVM. -// -// ActorState represents the on-chain storage all actors keep. -type ActorState struct { - // Identifies the code this actor executes. - CodeID abi.ActorCodeID - // CID of the root of optional actor-specific sub-state. - State actor.ActorSubstateCID - // Balance of tokens held by this actor. - Balance abi.TokenAmount - // Expected sequence number of the next message sent by this actor. - // Initially zero, incremented when an account actor originates a top-level message. - // Always zero for other abi. - CallSeqNum -} - -type ActorSystemStateCID cid.Cid - -// ActorState represents the on-chain storage actors keep. This type is a -// union of concrete types, for each of the Actors: -// - InitActor -// - CronActor -// - AccountActor -// - PaymentChannelActor -// - StoragePowerActor -// - StorageMinerActor -// - StroageMarketActor -// -// TODO: move this into a directory inside the VM that patches in all -// the actors from across the system. this will be where we declare/mount -// all actors in the VM. -// type ActorState union { -// Init struct { -// AddressMap {addr.Address: ActorID} -// NextID ActorID -// } -// } diff --git a/content/systems/filecoin_vm/interpreter/vm_interpreter.go b/content/systems/filecoin_vm/interpreter/vm_interpreter.go deleted file mode 100644 index b0e00e550..000000000 --- a/content/systems/filecoin_vm/interpreter/vm_interpreter.go +++ /dev/null @@ -1,372 +0,0 @@ -package interpreter - -import ( - addr "github.com/filecoin-project/go-address" - abi "github.com/filecoin-project/specs-actors/actors/abi" - builtin "github.com/filecoin-project/specs-actors/actors/builtin" - initact "github.com/filecoin-project/specs-actors/actors/builtin/init" - vmr "github.com/filecoin-project/specs-actors/actors/runtime" - exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" - indices "github.com/filecoin-project/specs-actors/actors/runtime/indices" - serde "github.com/filecoin-project/specs-actors/actors/serde" - ipld "github.com/filecoin-project/specs/libraries/ipld" - chain "github.com/filecoin-project/specs/systems/filecoin_blockchain/struct/chain" - actstate "github.com/filecoin-project/specs/systems/filecoin_vm/actor" - msg "github.com/filecoin-project/specs/systems/filecoin_vm/message" - gascost "github.com/filecoin-project/specs/systems/filecoin_vm/runtime/gascost" - vmri "github.com/filecoin-project/specs/systems/filecoin_vm/runtime/impl" - st "github.com/filecoin-project/specs/systems/filecoin_vm/state_tree" - util "github.com/filecoin-project/specs/util" - cid "github.com/ipfs/go-cid" -) - -type Bytes = util.Bytes - -var Assert = util.Assert -var TODO = util.TODO -var IMPL_FINISH = util.IMPL_FINISH - -type SenderResolveSpec int - -const ( - SenderResolveSpec_OK SenderResolveSpec = 1 + iota - SenderResolveSpec_Invalid -) - -// Applies all the message in a tipset, along with implicit block- and tipset-specific state -// transitions. -func (vmi *VMInterpreter_I) ApplyTipSetMessages(inTree st.StateTree, tipset chain.Tipset, msgs TipSetMessages) (outTree st.StateTree, receipts []vmri.MessageReceipt) { - outTree = inTree - seenMsgs := make(map[cid.Cid]struct{}) // CIDs of messages already seen once. - var receipt vmri.MessageReceipt - store := vmi.Node().Repository().StateStore() - // get chain from Tipset - chainRand := &chain.Chain_I{ - HeadTipset_: tipset, - } - - for _, blk := range msgs.Blocks() { - minerAddr := blk.Miner() - util.Assert(minerAddr.Protocol() == addr.ID) // Block syntactic validation requires this. - - // Process block miner's Election PoSt. - epostMessage := _makeElectionPoStMessage(outTree, minerAddr) - outTree = _applyMessageBuiltinAssert(store, outTree, chainRand, epostMessage, minerAddr) - - minerPenaltyTotal := abi.TokenAmount(0) - var minerPenaltyCurr abi.TokenAmount - - minerGasRewardTotal := abi.TokenAmount(0) - var minerGasRewardCurr abi.TokenAmount - - // Process BLS messages from the block. - for _, m := range blk.BLSMessages() { - _, found := seenMsgs[_msgCID(m)] - if found { - continue - } - onChainMessageLen := len(msg.Serialize_UnsignedMessage(m)) - outTree, receipt, minerPenaltyCurr, minerGasRewardCurr = vmi.ApplyMessage(outTree, chainRand, m, onChainMessageLen, minerAddr) - minerPenaltyTotal += minerPenaltyCurr - minerGasRewardTotal += minerGasRewardCurr - - receipts = append(receipts, receipt) - seenMsgs[_msgCID(m)] = struct{}{} - } - - // Process SECP messages from the block. - for _, sm := range blk.SECPMessages() { - m := sm.Message() - _, found := seenMsgs[_msgCID(m)] - if found { - continue - } - onChainMessageLen := len(msg.Serialize_SignedMessage(sm)) - outTree, receipt, minerPenaltyCurr, minerGasRewardCurr = vmi.ApplyMessage(outTree, chainRand, m, onChainMessageLen, minerAddr) - minerPenaltyTotal += minerPenaltyCurr - minerGasRewardTotal += minerGasRewardCurr - - receipts = append(receipts, receipt) - seenMsgs[_msgCID(m)] = struct{}{} - } - - // transfer gas reward from BurntFundsActor to RewardActor - _withTransferFundsAssert(outTree, builtin.BurntFundsActorAddr, builtin.RewardActorAddr, minerGasRewardTotal) - - // Pay block reward. - rewardMessage := _makeBlockRewardMessage(outTree, minerAddr, minerPenaltyTotal, minerGasRewardTotal) - outTree = _applyMessageBuiltinAssert(store, outTree, chainRand, rewardMessage, minerAddr) - } - - // Invoke cron tick. - // Since this is outside any block, the top level block winner is declared as the system actor. - cronMessage := _makeCronTickMessage(outTree) - outTree = _applyMessageBuiltinAssert(store, outTree, chainRand, cronMessage, builtin.SystemActorAddr) - - return -} - -func (vmi *VMInterpreter_I) ApplyMessage(inTree st.StateTree, chain chain.Chain, message msg.UnsignedMessage, onChainMessageSize int, minerAddr addr.Address) ( - retTree st.StateTree, retReceipt vmri.MessageReceipt, retMinerPenalty abi.TokenAmount, retMinerGasReward abi.TokenAmount) { - - store := vmi.Node().Repository().StateStore() - senderAddr := _resolveSender(store, inTree, message.From()) - - vmiGasRemaining := message.GasLimit() - vmiGasUsed := msg.GasAmount_Zero() - - _applyReturn := func( - tree st.StateTree, invocOutput vmr.InvocOutput, exitCode exitcode.ExitCode, - senderResolveSpec SenderResolveSpec) { - - vmiGasRemainingFIL := _gasToFIL(vmiGasRemaining, message.GasPrice()) - vmiGasUsedFIL := _gasToFIL(vmiGasUsed, message.GasPrice()) - - switch senderResolveSpec { - case SenderResolveSpec_OK: - // In this case, the sender is valid and has already transferred funds to the burnt funds actor - // sufficient for the gas limit. Thus, we may refund the unused gas funds to the sender here. - Assert(!message.GasLimit().LessThan(vmiGasUsed)) - Assert(message.GasLimit().Equals(vmiGasUsed.Add(vmiGasRemaining))) - tree = _withTransferFundsAssert(tree, builtin.BurntFundsActorAddr, senderAddr, vmiGasRemainingFIL) - retMinerGasReward = vmiGasUsedFIL - retMinerPenalty = abi.TokenAmount(0) - - case SenderResolveSpec_Invalid: - retMinerPenalty = vmiGasUsedFIL - retMinerGasReward = abi.TokenAmount(0) - - default: - Assert(false) - } - - retTree = tree - retReceipt = vmri.MessageReceipt_Make(invocOutput, exitCode, vmiGasUsed) - } - - // TODO move this to a package with a less redundant name - _applyError := func(tree st.StateTree, errExitCode exitcode.ExitCode, senderResolveSpec SenderResolveSpec) { - _applyReturn(tree, vmr.InvocOutput_Make(nil), errExitCode, senderResolveSpec) - } - - // Deduct an amount of gas corresponding to cost about to be incurred, but not necessarily - // incurred yet. - _vmiAllocGas := func(amount msg.GasAmount) (vmiAllocGasOK bool) { - vmiGasRemaining, vmiAllocGasOK = vmiGasRemaining.SubtractIfNonnegative(amount) - vmiGasUsed = message.GasLimit().Subtract(vmiGasRemaining) - Assert(!vmiGasRemaining.LessThan(msg.GasAmount_Zero())) - Assert(!vmiGasUsed.LessThan(msg.GasAmount_Zero())) - return - } - - // Deduct an amount of gas corresponding to costs already incurred, and for which the - // gas cost must be paid even if it would cause the gas used to exceed the limit. - _vmiBurnGas := func(amount msg.GasAmount) (vmiBurnGasOK bool) { - vmiGasUsedPre := vmiGasUsed - vmiBurnGasOK = _vmiAllocGas(amount) - if !vmiBurnGasOK { - vmiGasRemaining = msg.GasAmount_Zero() - vmiGasUsed = vmiGasUsedPre.Add(amount) - } - return - } - - ok := _vmiBurnGas(gascost.OnChainMessage(onChainMessageSize)) - if !ok { - // Invalid message; insufficient gas limit to pay for the on-chain message size. - _applyError(inTree, exitcode.OutOfGas, SenderResolveSpec_Invalid) - return - } - - fromActor, ok := inTree.GetActor(senderAddr) - if !ok { - // Execution error; sender does not exist at time of message execution. - _applyError(inTree, exitcode.ActorNotFound, SenderResolveSpec_Invalid) - return - } - - // make sure this is the right message order for fromActor - if message.CallSeqNum() != fromActor.CallSeqNum() { - _applyError(inTree, exitcode.InvalidCallSeqNum, SenderResolveSpec_Invalid) - return - } - - // Check sender balance. - gasLimitCost := _gasToFIL(message.GasLimit(), message.GasPrice()) - tidx := indicesFromStateTree(inTree) - networkTxnFee := tidx.NetworkTransactionFee( - inTree.GetActorCodeID_Assert(message.To()), message.Method()) - totalCost := message.Value() + gasLimitCost + networkTxnFee - if fromActor.Balance() < totalCost { - // Execution error; sender does not have sufficient funds to pay for the gas limit. - _applyError(inTree, exitcode.InsufficientFunds_System, SenderResolveSpec_Invalid) - return - } - - // At this point, construct compTreePreSend as a state snapshot which includes - // the sender paying gas, and the sender's CallSeqNum being incremented; - // at least that much state change will be persisted even if the - // method invocation subsequently fails. - compTreePreSend := _withTransferFundsAssert(inTree, senderAddr, builtin.BurntFundsActorAddr, gasLimitCost+networkTxnFee) - compTreePreSend = compTreePreSend.Impl().WithIncrementedCallSeqNum_Assert(senderAddr) - - invoc := _makeInvocInput(message) - sendRet, compTreePostSend := _applyMessageInternal(store, compTreePreSend, chain, message.CallSeqNum(), senderAddr, invoc, vmiGasRemaining, minerAddr) - - ok = _vmiBurnGas(sendRet.GasUsed) - if !ok { - panic("Interpreter error: runtime execution used more gas than provided") - } - - ok = _vmiAllocGas(gascost.OnChainReturnValue(sendRet.ReturnValue)) - if !ok { - // Insufficient gas remaining to cover the on-chain return value; proceed as in the case - // of method execution failure. - _applyError(compTreePreSend, exitcode.OutOfGas, SenderResolveSpec_OK) - return - } - - compTreeRet := compTreePreSend - if sendRet.ExitCode.AllowsStateUpdate() { - compTreeRet = compTreePostSend - } - - _applyReturn( - compTreeRet, vmr.InvocOutput_Make(sendRet.ReturnValue), sendRet.ExitCode, SenderResolveSpec_OK) - return -} - -// Resolves an address through the InitActor's map. -// Returns the resolved address (which will be an ID address) if found, else the original address. -func _resolveSender(store ipld.GraphStore, tree st.StateTree, address addr.Address) addr.Address { - initState, ok := tree.GetActor(builtin.InitActorAddr) - util.Assert(ok) - serialized, ok := store.Get(cid.Cid(initState.State())) - var initSubState initact.InitActorState - serde.MustDeserialize(serialized, &initSubState) - return initSubState.ResolveAddress(address) -} - -func _applyMessageBuiltinAssert(store ipld.GraphStore, tree st.StateTree, chain chain.Chain, message msg.UnsignedMessage, minerAddr addr.Address) st.StateTree { - senderAddr := message.From() - Assert(senderAddr == builtin.SystemActorAddr) - Assert(senderAddr.Protocol() == addr.ID) - // Note: this message CallSeqNum is never checked (b/c it's created in this file), but probably should be. - // Since it changes state, we should be sure about the state transition. - // Alternatively we could special-case the system actor and declare that its CallSeqNumber - // never changes (saving us the state-change overhead). - tree = tree.Impl().WithIncrementedCallSeqNum_Assert(senderAddr) - - invoc := _makeInvocInput(message) - retReceipt, retTree := _applyMessageInternal(store, tree, chain, message.CallSeqNum(), senderAddr, invoc, message.GasLimit(), minerAddr) - if retReceipt.ExitCode != exitcode.OK() { - panic("internal message application failed") - } - - return retTree -} - -func _applyMessageInternal(store ipld.GraphStore, tree st.StateTree, chain chain.Chain, messageCallSequenceNumber actstate.CallSeqNum, senderAddr addr.Address, invoc vmr.InvocInput, - gasRemainingInit msg.GasAmount, topLevelBlockWinner addr.Address) (vmri.MessageReceipt, st.StateTree) { - - rt := vmri.VMContext_Make( - store, - chain, - senderAddr, - topLevelBlockWinner, - messageCallSequenceNumber, - actstate.CallSeqNum(0), - tree, - senderAddr, - abi.TokenAmount(0), - gasRemainingInit, - ) - - return rt.SendToplevelFromInterpreter(invoc) -} - -func _withTransferFundsAssert(tree st.StateTree, from addr.Address, to addr.Address, amount abi.TokenAmount) st.StateTree { - // TODO: assert amount nonnegative - retTree, err := tree.Impl().WithFundsTransfer(from, to, amount) - if err != nil { - panic("Interpreter error: insufficient funds (or transfer error) despite checks") - } else { - return retTree - } -} - -func indicesFromStateTree(st st.StateTree) indices.Indices { - TODO() - panic("") -} - -func _gasToFIL(gas msg.GasAmount, price abi.TokenAmount) abi.TokenAmount { - IMPL_FINISH() - panic("") // BigInt arithmetic - // return abi.TokenAmount(util.UVarint(gas) * util.UVarint(price)) -} - -func _makeInvocInput(message msg.UnsignedMessage) vmr.InvocInput { - return vmr.InvocInput{ - To: message.To(), // Receiver address is resolved during execution. - Method: message.Method(), - Params: message.Params(), - Value: message.Value(), - } -} - -// Builds a message for paying block reward to a miner's owner. -func _makeBlockRewardMessage(state st.StateTree, minerAddr addr.Address, penalty abi.TokenAmount, gasReward abi.TokenAmount) msg.UnsignedMessage { - params := serde.MustSerializeParams(minerAddr, penalty) - TODO() // serialize other inputs to BlockRewardMessage or get this from query in RewardActor - - sysActor, ok := state.GetActor(builtin.SystemActorAddr) - Assert(ok) - - return &msg.UnsignedMessage_I{ - From_: builtin.SystemActorAddr, - To_: builtin.RewardActorAddr, - Method_: builtin.Method_RewardActor_AwardBlockReward, - Params_: params, - CallSeqNum_: sysActor.CallSeqNum(), - Value_: 0, - GasPrice_: 0, - GasLimit_: msg.GasAmount_SentinelUnlimited(), - } -} - -// Builds a message for submitting ElectionPost on behalf of a miner actor. -func _makeElectionPoStMessage(state st.StateTree, minerActorAddr addr.Address) msg.UnsignedMessage { - sysActor, ok := state.GetActor(builtin.SystemActorAddr) - Assert(ok) - return &msg.UnsignedMessage_I{ - From_: builtin.SystemActorAddr, - To_: minerActorAddr, - Method_: builtin.Method_StorageMinerActor_OnVerifiedElectionPoSt, - Params_: nil, - CallSeqNum_: sysActor.CallSeqNum(), - Value_: 0, - GasPrice_: 0, - GasLimit_: msg.GasAmount_SentinelUnlimited(), - } -} - -// Builds a message for invoking the cron actor tick. -func _makeCronTickMessage(state st.StateTree) msg.UnsignedMessage { - sysActor, ok := state.GetActor(builtin.SystemActorAddr) - Assert(ok) - return &msg.UnsignedMessage_I{ - From_: builtin.SystemActorAddr, - To_: builtin.CronActorAddr, - Method_: builtin.Method_CronActor_EpochTick, - Params_: nil, - CallSeqNum_: sysActor.CallSeqNum(), - Value_: 0, - GasPrice_: 0, - GasLimit_: msg.GasAmount_SentinelUnlimited(), - } -} - -func _msgCID(msg msg.UnsignedMessage) cid.Cid { - panic("TODO") -} diff --git a/content/systems/filecoin_vm/interpreter/vm_interpreter.id b/content/systems/filecoin_vm/interpreter/vm_interpreter.id deleted file mode 100644 index 23fa20c5f..000000000 --- a/content/systems/filecoin_vm/interpreter/vm_interpreter.id +++ /dev/null @@ -1,44 +0,0 @@ -import addr "github.com/filecoin-project/go-address" -import msg "github.com/filecoin-project/specs/systems/filecoin_vm/message" -import st "github.com/filecoin-project/specs/systems/filecoin_vm/state_tree" -import vmri "github.com/filecoin-project/specs/systems/filecoin_vm/runtime/impl" -import node_base "github.com/filecoin-project/specs/systems/filecoin_nodes/node_base" -import chain "github.com/filecoin-project/specs/systems/filecoin_blockchain/struct/chain" -import abi "github.com/filecoin-project/specs-actors/actors/abi" - -type UInt64 UInt - -// The messages from one block in a tipset. -type BlockMessages struct { - BLSMessages [msg.UnsignedMessage] - SECPMessages [msg.SignedMessage] - Miner addr.Address // The block miner's actor address - PoStProof Bytes // The miner's Election PoSt proof output -} - -// The messages from a tipset, grouped by block. -type TipSetMessages struct { - Blocks [BlockMessages] - Epoch UInt64 // The chain epoch of the blocks -} - -type VMInterpreter struct { - Node node_base.FilecoinNode - ApplyTipSetMessages( - inTree st.StateTree - tipset chain.Tipset - msgs TipSetMessages - ) struct {outTree st.StateTree, ret [vmri.MessageReceipt]} - - ApplyMessage( - inTree st.StateTree - chain chain.Chain - msg msg.UnsignedMessage - onChainMsgSize int - minerAddr addr.Address - ) struct { - outTree st.StateTree - ret vmri.MessageReceipt - retMinerPenalty abi.TokenAmount - } -} diff --git a/content/systems/filecoin_vm/interpreter/vm_registry.go b/content/systems/filecoin_vm/interpreter/vm_registry.go deleted file mode 100644 index ae889a0f5..000000000 --- a/content/systems/filecoin_vm/interpreter/vm_registry.go +++ /dev/null @@ -1,77 +0,0 @@ -package interpreter - -import ( - "errors" - - abi "github.com/filecoin-project/specs-actors/actors/abi" - builtin "github.com/filecoin-project/specs-actors/actors/builtin" - accact "github.com/filecoin-project/specs-actors/actors/builtin/account" - cronact "github.com/filecoin-project/specs-actors/actors/builtin/cron" - initact "github.com/filecoin-project/specs-actors/actors/builtin/init" - smarkact "github.com/filecoin-project/specs-actors/actors/builtin/storage_market" - spowact "github.com/filecoin-project/specs-actors/actors/builtin/storage_power" - vmr "github.com/filecoin-project/specs-actors/actors/runtime" -) - -var ( - ErrActorNotFound = errors.New("Actor Not Found") -) - -var staticActorCodeRegistry = &actorCodeRegistry{} - -type actorCodeRegistry struct { - code map[abi.ActorCodeID]vmr.ActorCode -} - -func (r *actorCodeRegistry) _registerActor(id abi.ActorCodeID, actor vmr.ActorCode) { - r.code[id] = actor -} - -func (r *actorCodeRegistry) _loadActor(id abi.ActorCodeID) (vmr.ActorCode, error) { - a, ok := r.code[id] - if !ok { - return nil, ErrActorNotFound - } - return a, nil -} - -func RegisterActor(id abi.ActorCodeID, actor vmr.ActorCode) { - staticActorCodeRegistry._registerActor(id, actor) -} - -func LoadActor(id abi.ActorCodeID) (vmr.ActorCode, error) { - return staticActorCodeRegistry._loadActor(id) -} - -// init is called in Go during initialization of a program. -// this is an idiomatic way to do this. Implementations should approach this -// however they wish. The point is to initialize a static registry with -// built in pure types that have the code for each actor. Once we have -// a way to load code from the StateTree, use that instead. -func init() { - _registerBuiltinActors() -} - -func _registerBuiltinActors() { - // TODO - - cron := &cronact.CronActor{} - - RegisterActor(builtin.InitActorCodeID, &initact.InitActor{}) - RegisterActor(builtin.CronActorCodeID, cron) - RegisterActor(builtin.AccountActorCodeID, &accact.AccountActor{}) - RegisterActor(builtin.StoragePowerActorCodeID, &spowact.StoragePowerActor{}) - RegisterActor(builtin.StorageMarketActorCodeID, &smarkact.StorageMarketActor{}) - - // wire in CRON actions. - // TODO: move this to CronActor's constructor method - cron.Entries = append(cron.Entries, cronact.CronTableEntry{ - ToAddr: builtin.StoragePowerActorAddr, - MethodNum: builtin.Method_StoragePowerActor_OnEpochTickEnd, - }) - - cron.Entries = append(cron.Entries, cronact.CronTableEntry{ - ToAddr: builtin.StorageMarketActorAddr, - MethodNum: builtin.Method_StorageMarketActor_OnEpochTickEnd, - }) -} diff --git a/content/systems/filecoin_vm/message/message.go b/content/systems/filecoin_vm/message/message.go deleted file mode 100644 index f5cf97142..000000000 --- a/content/systems/filecoin_vm/message/message.go +++ /dev/null @@ -1,99 +0,0 @@ -package message - -import ( - filcrypto "github.com/filecoin-project/specs/algorithms/crypto" - util "github.com/filecoin-project/specs/util" -) - -var IMPL_FINISH = util.IMPL_FINISH - -type Serialization = util.Serialization - -// The maximum serialized size of a SignedMessage. -const MessageMaxSize = 32 * 1024 - -func SignedMessage_Make(message UnsignedMessage, signature filcrypto.Signature) SignedMessage { - return &SignedMessage_I{ - Message_: message, - Signature_: signature, - } -} - -func Sign(message UnsignedMessage, keyPair filcrypto.SigKeyPair) (SignedMessage, error) { - sig, err := filcrypto.Sign(keyPair, util.Bytes(Serialize_UnsignedMessage(message))) - if err != nil { - return nil, err - } - return SignedMessage_Make(message, sig), nil -} - -func SignatureVerificationError() error { - IMPL_FINISH() - panic("") -} - -func Verify(message SignedMessage, publicKey filcrypto.PublicKey) (UnsignedMessage, error) { - m := util.Bytes(Serialize_UnsignedMessage(message.Message())) - sigValid, err := filcrypto.Verify(publicKey, message.Signature(), m) - if err != nil { - return nil, err - } - if !sigValid { - return nil, SignatureVerificationError() - } - return message.Message(), nil -} - -func (x *GasAmount_I) Add(y GasAmount) GasAmount { - IMPL_FINISH() - panic("") -} - -func (x *GasAmount_I) Subtract(y GasAmount) GasAmount { - IMPL_FINISH() - panic("") -} - -func (x *GasAmount_I) SubtractIfNonnegative(y GasAmount) (ret GasAmount, ok bool) { - ret = x.Subtract(y) - ok = true - if ret.LessThan(GasAmount_Zero()) { - ret = x - ok = false - } - return -} - -func (x *GasAmount_I) LessThan(y GasAmount) bool { - IMPL_FINISH() - panic("") -} - -func (x *GasAmount_I) Equals(y GasAmount) bool { - IMPL_FINISH() - panic("") -} - -func (x *GasAmount_I) Scale(count int) GasAmount { - IMPL_FINISH() - panic("") -} - -func GasAmount_Affine(b GasAmount, x int, m GasAmount) GasAmount { - return b.Add(m.Scale(x)) -} - -func GasAmount_Zero() GasAmount { - return GasAmount_FromInt(0) -} - -func GasAmount_FromInt(x int) GasAmount { - IMPL_FINISH() - panic("") -} - -func GasAmount_SentinelUnlimited() GasAmount { - // Amount of gas larger than any feasible execution; meant to indicated unlimited gas - // (e.g., for builtin system method invocations). - return GasAmount_FromInt(1).Scale(1e9).Scale(1e9) // 10^18 -} diff --git a/content/systems/filecoin_vm/message/message.id b/content/systems/filecoin_vm/message/message.id deleted file mode 100644 index 8dd2db495..000000000 --- a/content/systems/filecoin_vm/message/message.id +++ /dev/null @@ -1,45 +0,0 @@ -import filcrypto "github.com/filecoin-project/specs/algorithms/crypto" -import addr "github.com/filecoin-project/go-address" -import actor "github.com/filecoin-project/specs/systems/filecoin_vm/actor" -import abi "github.com/filecoin-project/specs-actors/actors/abi" - -// GasAmount is a quantity of gas. -type GasAmount struct { - value BigInt - - Add(GasAmount) GasAmount - Subtract(GasAmount) GasAmount - SubtractIfNonnegative(GasAmount) (ret GasAmount, ok bool) - LessThan(GasAmount) bool - Equals(GasAmount) bool - Scale(int) GasAmount -} - -type UnsignedMessage struct { - // Version of this message (0 until we have to have a breaking change) - Version int64 - - // Address of the receiving actor. - To addr.Address - // Address of the sending actor. - From addr.Address - // Expected CallSeqNum of the sending actor (only for top-level messages). - CallSeqNum actor.CallSeqNum - - // Amount of value to transfer from sender's to receiver's balance. - Value abi.TokenAmount - - // GasPrice is a Gas-to-FIL cost - GasPrice abi.TokenAmount - GasLimit GasAmount - - // Optional method to invoke on receiver, zero for a plain value send. - Method abi.MethodNum - /// Serialized parameters to the method (if method is non-zero). - Params abi.MethodParams -} // representation tuple - -type SignedMessage struct { - Message UnsignedMessage - Signature filcrypto.Signature -} // representation tuple diff --git a/content/systems/filecoin_vm/runtime/gascost/_index.md b/content/systems/filecoin_vm/runtime/gascost/_index.md deleted file mode 100644 index 025f70edd..000000000 --- a/content/systems/filecoin_vm/runtime/gascost/_index.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Gas Costs -dashboardWeight: 1 -dashboardState: wip -dashboardAudit: missing -dashboardTests: 0 ---- - -# VM Gas Cost Constants - -{{}} diff --git a/content/systems/filecoin_vm/runtime/gascost/vm_gascosts.go b/content/systems/filecoin_vm/runtime/gascost/vm_gascosts.go deleted file mode 100644 index a114508c8..000000000 --- a/content/systems/filecoin_vm/runtime/gascost/vm_gascosts.go +++ /dev/null @@ -1,121 +0,0 @@ -package runtime - -import ( - abi "github.com/filecoin-project/specs-actors/actors/abi" - actor "github.com/filecoin-project/specs-actors/actors/builtin" - msg "github.com/filecoin-project/specs/systems/filecoin_vm/message" - util "github.com/filecoin-project/specs/util" -) - -type Bytes = util.Bytes - -var TODO = util.TODO - -var ( - // TODO: assign all of these. - GasAmountPlaceholder = msg.GasAmount_FromInt(1) - GasAmountPlaceholder_UpdateStateTree = GasAmountPlaceholder -) - -var ( - /////////////////////////////////////////////////////////////////////////// - // System operations - /////////////////////////////////////////////////////////////////////////// - - // Gas cost charged to the originator of an on-chain message (regardless of - // whether it succeeds or fails in application) is given by: - // OnChainMessageBase + len(serialized message)*OnChainMessagePerByte - // Together, these account for the cost of message propagation and validation, - // up to but excluding any actual processing by the VM. - // This is the cost a block producer burns when including an invalid message. - OnChainMessageBase = GasAmountPlaceholder - OnChainMessagePerByte = GasAmountPlaceholder - - // Gas cost charged to the originator of a non-nil return value produced - // by an on-chain message is given by: - // len(return value)*OnChainReturnValuePerByte - OnChainReturnValuePerByte = GasAmountPlaceholder - - // Gas cost for any message send execution(including the top-level one - // initiated by an on-chain message). - // This accounts for the cost of loading sender and receiver actors and - // (for top-level messages) incrementing the sender's sequence number. - // Load and store of actor sub-state is charged separately. - SendBase = GasAmountPlaceholder - - // Gas cost charged, in addition to SendBase, if a message send - // is accompanied by any nonzero currency amount. - // Accounts for writing receiver's new balance (the sender's state is - // already accounted for). - SendTransferFunds = GasAmountPlaceholder - - // Gas cost charged, in addition to SendBase, if a message invokes - // a method on the receiver. - // Accounts for the cost of loading receiver code and method dispatch. - SendInvokeMethod = GasAmountPlaceholder - - // Gas cost (Base + len*PerByte) for any Get operation to the IPLD store - // in the runtime VM context. - IpldGetBase = GasAmountPlaceholder - IpldGetPerByte = GasAmountPlaceholder - - // Gas cost (Base + len*PerByte) for any Put operation to the IPLD store - // in the runtime VM context. - // - // Note: these costs should be significantly higher than the costs for Get - // operations, since they reflect not only serialization/deserialization - // but also persistent storage of chain data. - IpldPutBase = GasAmountPlaceholder - IpldPutPerByte = GasAmountPlaceholder - - // Gas cost for updating an actor's substate (i.e., UpdateRelease). - // This is in addition to a per-byte fee for the state as for IPLD Get/Put. - UpdateActorSubstate = GasAmountPlaceholder_UpdateStateTree - - // Gas cost for creating a new actor (via InitActor's Exec method). - // Actor sub-state is charged separately. - ExecNewActor = GasAmountPlaceholder - - // Gas cost for deleting an actor. - DeleteActor = GasAmountPlaceholder - - /////////////////////////////////////////////////////////////////////////// - // Pure functions (VM ABI) - /////////////////////////////////////////////////////////////////////////// - - // Gas cost charged per public-key cryptography operation (e.g., signature - // verification). - PublicKeyCryptoOp = GasAmountPlaceholder -) - -func OnChainMessage(onChainMessageLen int) msg.GasAmount { - return msg.GasAmount_Affine(OnChainMessageBase, onChainMessageLen, OnChainMessagePerByte) -} - -func OnChainReturnValue(returnValue Bytes) msg.GasAmount { - retLen := 0 - if returnValue != nil { - retLen = len(returnValue) - } - - return msg.GasAmount_Affine(msg.GasAmount_Zero(), retLen, OnChainReturnValuePerByte) -} - -func IpldGet(dataSize int) msg.GasAmount { - return msg.GasAmount_Affine(IpldGetBase, dataSize, IpldGetPerByte) -} - -func IpldPut(dataSize int) msg.GasAmount { - return msg.GasAmount_Affine(IpldPutBase, dataSize, IpldPutPerByte) -} - -func InvokeMethod(value abi.TokenAmount, method abi.MethodNum) msg.GasAmount { - ret := SendBase - if value != abi.TokenAmount(0) { - ret = ret.Add(SendTransferFunds) - } - if method != actor.MethodSend { - ret = ret.Add(SendInvokeMethod) - } - return ret -} diff --git a/content/systems/filecoin_vm/runtime/impl/codeload.go b/content/systems/filecoin_vm/runtime/impl/codeload.go deleted file mode 100644 index f9b5d3a27..000000000 --- a/content/systems/filecoin_vm/runtime/impl/codeload.go +++ /dev/null @@ -1,17 +0,0 @@ -package impl - -import ( - abi "github.com/filecoin-project/specs-actors/actors/abi" - vmr "github.com/filecoin-project/specs-actors/actors/runtime" -) - -func loadActorCode(codeID abi.ActorCodeID) (vmr.ActorCode, error) { - - panic("TODO") - // TODO: resolve circular dependency - - // // load the code from StateTree. - // // TODO: this is going to be enabled in the future. - // // code, err := loadCodeFromStateTree(input.InTree, codeCID) - // return staticActorCodeRegistry.LoadActor(codeCID) -} diff --git a/content/systems/filecoin_vm/runtime/impl/receipt.go b/content/systems/filecoin_vm/runtime/impl/receipt.go deleted file mode 100644 index cac11966b..000000000 --- a/content/systems/filecoin_vm/runtime/impl/receipt.go +++ /dev/null @@ -1,21 +0,0 @@ -package impl - -import ( - vmr "github.com/filecoin-project/specs-actors/actors/runtime" - exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" - msg "github.com/filecoin-project/specs/systems/filecoin_vm/message" -) - -type MessageReceipt struct { - ExitCode exitcode.ExitCode - ReturnValue Bytes - GasUsed msg.GasAmount -} - -func MessageReceipt_Make(output vmr.InvocOutput, exitCode exitcode.ExitCode, gasUsed msg.GasAmount) MessageReceipt { - return MessageReceipt{ - ExitCode: exitCode, - ReturnValue: output.ReturnValue, - GasUsed: gasUsed, - } -} diff --git a/content/systems/filecoin_vm/runtime/impl/runtime.go b/content/systems/filecoin_vm/runtime/impl/runtime.go deleted file mode 100644 index 013c0c567..000000000 --- a/content/systems/filecoin_vm/runtime/impl/runtime.go +++ /dev/null @@ -1,732 +0,0 @@ -package impl - -import ( - "bytes" - "encoding/binary" - "fmt" - - addr "github.com/filecoin-project/go-address" - actor "github.com/filecoin-project/specs-actors/actors" - abi "github.com/filecoin-project/specs-actors/actors/abi" - builtin "github.com/filecoin-project/specs-actors/actors/builtin" - acctact "github.com/filecoin-project/specs-actors/actors/builtin/account" - initact "github.com/filecoin-project/specs-actors/actors/builtin/init" - vmr "github.com/filecoin-project/specs-actors/actors/runtime" - exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" - indices "github.com/filecoin-project/specs-actors/actors/runtime/indices" - ipld "github.com/filecoin-project/specs/libraries/ipld" - chain "github.com/filecoin-project/specs/systems/filecoin_blockchain/struct/chain" - actstate "github.com/filecoin-project/specs/systems/filecoin_vm/actor" - msg "github.com/filecoin-project/specs/systems/filecoin_vm/message" - gascost "github.com/filecoin-project/specs/systems/filecoin_vm/runtime/gascost" - st "github.com/filecoin-project/specs/systems/filecoin_vm/state_tree" - util "github.com/filecoin-project/specs/util" - cid "github.com/ipfs/go-cid" - cbornode "github.com/ipfs/go-ipld-cbor" - mh "github.com/multiformats/go-multihash" -) - -type ActorSubstateCID = actor.ActorSubstateCID -type ExitCode = exitcode.ExitCode -type CallerPattern = vmr.CallerPattern -type Runtime = vmr.Runtime -type InvocInput = vmr.InvocInput -type InvocOutput = vmr.InvocOutput -type ActorStateHandle = vmr.ActorStateHandle - -var EnsureErrorCode = exitcode.EnsureErrorCode - -type Bytes = util.Bytes - -var Assert = util.Assert -var IMPL_FINISH = util.IMPL_FINISH -var IMPL_TODO = util.IMPL_TODO -var TODO = util.TODO - -var EmptyCBOR cid.Cid - -type RuntimeError struct { - ExitCode ExitCode - ErrMsg string -} - -func init() { - n, err := cbornode.WrapObject(map[string]struct{}{}, mh.SHA2_256, -1) - Assert(err == nil) - EmptyCBOR = n.Cid() -} - -func (x *RuntimeError) String() string { - ret := fmt.Sprintf("Runtime error: %v", x.ExitCode) - if x.ErrMsg != "" { - ret += fmt.Sprintf(" (\"%v\")", x.ErrMsg) - } - return ret -} - -func RuntimeError_Make(exitCode ExitCode, errMsg string) *RuntimeError { - exitCode = EnsureErrorCode(exitCode) - return &RuntimeError{ - ExitCode: exitCode, - ErrMsg: errMsg, - } -} - -func ActorSubstateCID_Equals(x, y ActorSubstateCID) bool { - IMPL_FINISH() - panic("") -} - -type ActorStateHandle_I struct { - _initValue *ActorSubstateCID - _rt *VMContext -} - -func (h *ActorStateHandle_I) UpdateRelease(newStateCID ActorSubstateCID) { - h._rt._updateReleaseActorSubstate(newStateCID) -} - -func (h *ActorStateHandle_I) Release(checkStateCID ActorSubstateCID) { - h._rt._releaseActorSubstate(checkStateCID) -} - -func (h *ActorStateHandle_I) Take() ActorSubstateCID { - if h._initValue == nil { - h._rt._apiError("Must call Take() only once on actor substate object") - } - ret := *h._initValue - h._initValue = nil - return ret -} - -// Concrete instantiation of the Runtime interface. This should be instantiated by the -// interpreter once per actor method invocation, and responds to that method's Runtime -// API calls. -type VMContext struct { - _store ipld.GraphStore - _globalStateInit st.StateTree - _globalStatePending st.StateTree - _running bool - _chain chain.Chain - _actorAddress addr.Address - _actorStateAcquired bool - // Tracks whether actor substate has changed in order to charge gas just once - // regardless of how many times it's written. - _actorSubstateUpdated bool - - _immediateCaller addr.Address - // Note: This is the actor in the From field of the initial on-chain message. - // Not necessarily the immediate caller. - _toplevelSender addr.Address - _toplevelBlockWinner addr.Address - // call sequence number of the top level message that began this execution sequence - _toplevelMsgCallSeqNum actstate.CallSeqNum - // Sequence number representing the total number of calls (to any actor, any method) - // during the current top-level message execution. - // Note: resets with every top-level message, and therefore not necessarily monotonic. - _internalCallSeqNum actstate.CallSeqNum - _valueReceived abi.TokenAmount - _gasRemaining msg.GasAmount - _numValidateCalls int - _output vmr.InvocOutput -} - -func VMContext_Make( - store ipld.GraphStore, - chain chain.Chain, - toplevelSender addr.Address, - toplevelBlockWinner addr.Address, - toplevelMsgCallSeqNum actstate.CallSeqNum, - internalCallSeqNum actstate.CallSeqNum, - globalState st.StateTree, - actorAddress addr.Address, - valueReceived abi.TokenAmount, - gasRemaining msg.GasAmount) *VMContext { - - return &VMContext{ - _store: store, - _chain: chain, - _globalStateInit: globalState, - _globalStatePending: globalState, - _running: false, - _actorAddress: actorAddress, - _actorStateAcquired: false, - _actorSubstateUpdated: false, - - _toplevelSender: toplevelSender, - _toplevelBlockWinner: toplevelBlockWinner, - _toplevelMsgCallSeqNum: toplevelMsgCallSeqNum, - _internalCallSeqNum: internalCallSeqNum, - _valueReceived: valueReceived, - _gasRemaining: gasRemaining, - _numValidateCalls: 0, - _output: vmr.InvocOutput{}, - } -} - -func (rt *VMContext) AbortArgMsg(msg string) { - rt.Abort(exitcode.InvalidArguments_User, msg) -} - -func (rt *VMContext) AbortArg() { - rt.AbortArgMsg("Invalid arguments") -} - -func (rt *VMContext) AbortStateMsg(msg string) { - rt.Abort(exitcode.InconsistentState_User, msg) -} - -func (rt *VMContext) AbortState() { - rt.AbortStateMsg("Inconsistent state") -} - -func (rt *VMContext) AbortFundsMsg(msg string) { - rt.Abort(exitcode.InsufficientFunds_User, msg) -} - -func (rt *VMContext) AbortFunds() { - rt.AbortFundsMsg("Insufficient funds") -} - -func (rt *VMContext) AbortAPI(msg string) { - rt.Abort(exitcode.RuntimeAPIError, msg) -} - -func (rt *VMContext) CreateActor(codeID abi.ActorCodeID, address addr.Address) { - if rt._actorAddress != builtin.InitActorAddr { - rt.AbortAPI("Only InitActor may call rt.CreateActor") - } - if address.Protocol() != addr.ID { - rt.AbortAPI("New actor adddress must be an ID-address") - } - - rt._createActor(codeID, address) -} - -func (rt *VMContext) _createActor(codeID abi.ActorCodeID, address addr.Address) { - // Create empty actor state. - actorState := &actstate.ActorState_I{ - CodeID_: codeID, - State_: actor.ActorSubstateCID(EmptyCBOR), - Balance_: abi.TokenAmount(0), - CallSeqNum_: 0, - } - - // Put it in the state tree. - actorStateCID := actstate.ActorSystemStateCID(rt.IpldPut(actorState)) - rt._updateActorSystemStateInternal(address, actorStateCID) - - rt._rtAllocGas(gascost.ExecNewActor) -} - -func (rt *VMContext) DeleteActor(address addr.Address) { - // Only a given actor may delete itself. - if rt._actorAddress != address { - rt.AbortAPI("Invalid actor deletion request") - } - - rt._deleteActor(address) -} - -func (rt *VMContext) _deleteActor(address addr.Address) { - rt._globalStatePending = rt._globalStatePending.Impl().WithDeleteActorSystemState(address) - rt._rtAllocGas(gascost.DeleteActor) -} - -func (rt *VMContext) _updateActorSystemStateInternal(actorAddress addr.Address, newStateCID actstate.ActorSystemStateCID) { - newGlobalStatePending, err := rt._globalStatePending.Impl().WithActorSystemState(rt._actorAddress, newStateCID) - if err != nil { - panic("Error in runtime implementation: failed to update actor system state") - } - rt._globalStatePending = newGlobalStatePending -} - -func (rt *VMContext) _updateActorSubstateInternal(actorAddress addr.Address, newStateCID actor.ActorSubstateCID) { - newGlobalStatePending, err := rt._globalStatePending.Impl().WithActorSubstate(rt._actorAddress, newStateCID) - if err != nil { - panic("Error in runtime implementation: failed to update actor substate") - } - rt._globalStatePending = newGlobalStatePending -} - -func (rt *VMContext) _updateReleaseActorSubstate(newStateCID ActorSubstateCID) { - rt._checkRunning() - rt._checkActorStateAcquired() - rt._updateActorSubstateInternal(rt._actorAddress, newStateCID) - rt._actorSubstateUpdated = true - rt._actorStateAcquired = false -} - -func (rt *VMContext) _releaseActorSubstate(checkStateCID ActorSubstateCID) { - rt._checkRunning() - rt._checkActorStateAcquired() - - prevState, ok := rt._globalStatePending.GetActor(rt._actorAddress) - util.Assert(ok) - prevStateCID := prevState.State() - if !ActorSubstateCID_Equals(prevStateCID, checkStateCID) { - rt.AbortAPI("State CID differs upon release call") - } - - rt._actorStateAcquired = false -} - -func (rt *VMContext) Assert(cond bool) { - if !cond { - rt.Abort(exitcode.RuntimeAssertFailure, "Runtime assertion failed") - } -} - -func (rt *VMContext) _checkActorStateAcquiredFlag(expected bool) { - rt._checkRunning() - if rt._actorStateAcquired != expected { - rt._apiError("State updates and message sends must be disjoint") - } -} - -func (rt *VMContext) _checkActorStateAcquired() { - rt._checkActorStateAcquiredFlag(true) -} - -func (rt *VMContext) _checkActorStateNotAcquired() { - rt._checkActorStateAcquiredFlag(false) -} - -func (rt *VMContext) Abort(errExitCode exitcode.ExitCode, errMsg string) { - errExitCode = exitcode.EnsureErrorCode(errExitCode) - rt._throwErrorFull(errExitCode, errMsg) -} - -func (rt *VMContext) ImmediateCaller() addr.Address { - return rt._immediateCaller -} - -func (rt *VMContext) CurrReceiver() addr.Address { - return rt._actorAddress -} - -func (rt *VMContext) ToplevelBlockWinner() addr.Address { - return rt._toplevelBlockWinner -} - -func (rt *VMContext) ValidateImmediateCallerMatches( - callerExpectedPattern CallerPattern) { - - rt._checkRunning() - rt._checkNumValidateCalls(0) - caller := rt.ImmediateCaller() - if !callerExpectedPattern.Matches(caller) { - rt.AbortAPI("Method invoked by incorrect caller") - } - rt._numValidateCalls += 1 -} - -func CallerPattern_MakeAcceptAnyOfTypes(rt *VMContext, types []abi.ActorCodeID) CallerPattern { - return CallerPattern{ - Matches: func(y addr.Address) bool { - codeID, ok := rt.GetActorCodeID(y) - if !ok { - panic("Internal runtime error: actor not found") - } - - for _, type_ := range types { - if codeID == type_ { - return true - } - } - return false - }, - } -} - -func (rt *VMContext) ValidateImmediateCallerIs(callerExpected addr.Address) { - rt.ValidateImmediateCallerMatches(vmr.CallerPattern_MakeSingleton(callerExpected)) -} - -func (rt *VMContext) ValidateImmediateCallerInSet(callersExpected []addr.Address) { - rt.ValidateImmediateCallerMatches(vmr.CallerPattern_MakeSet(callersExpected)) -} - -func (rt *VMContext) ValidateImmediateCallerAcceptAnyOfType(type_ abi.ActorCodeID) { - rt.ValidateImmediateCallerAcceptAnyOfTypes([]abi.ActorCodeID{type_}) -} - -func (rt *VMContext) ValidateImmediateCallerAcceptAnyOfTypes(types []abi.ActorCodeID) { - rt.ValidateImmediateCallerMatches(CallerPattern_MakeAcceptAnyOfTypes(rt, types)) -} - -func (rt *VMContext) ValidateImmediateCallerAcceptAny() { - rt.ValidateImmediateCallerMatches(vmr.CallerPattern_MakeAcceptAny()) -} - -func (rt *VMContext) _checkNumValidateCalls(x int) { - if rt._numValidateCalls != x { - rt.AbortAPI("Method must validate caller identity exactly once") - } -} - -func (rt *VMContext) _checkRunning() { - if !rt._running { - panic("Internal runtime error: actor API called with no actor code running") - } -} -func (rt *VMContext) SuccessReturn() InvocOutput { - return vmr.InvocOutput_Make(nil) -} - -func (rt *VMContext) ValueReturn(value util.Bytes) InvocOutput { - return vmr.InvocOutput_Make(value) -} - -func (rt *VMContext) _throwError(exitCode ExitCode) { - rt._throwErrorFull(exitCode, "") -} - -func (rt *VMContext) _throwErrorFull(exitCode ExitCode, errMsg string) { - panic(RuntimeError_Make(exitCode, errMsg)) -} - -func (rt *VMContext) _apiError(errMsg string) { - rt._throwErrorFull(exitcode.RuntimeAPIError, errMsg) -} - -func _gasAmountAssertValid(x msg.GasAmount) { - if x.LessThan(msg.GasAmount_Zero()) { - panic("Interpreter error: negative gas amount") - } -} - -// Deduct an amount of gas corresponding to cost about to be incurred, but not necessarily -// incurred yet. -func (rt *VMContext) _rtAllocGas(x msg.GasAmount) { - _gasAmountAssertValid(x) - var ok bool - rt._gasRemaining, ok = rt._gasRemaining.SubtractIfNonnegative(x) - if !ok { - rt._throwError(exitcode.OutOfGas) - } -} - -func (rt *VMContext) _transferFunds(from addr.Address, to addr.Address, amount abi.TokenAmount) error { - rt._checkRunning() - rt._checkActorStateNotAcquired() - - newGlobalStatePending, err := rt._globalStatePending.Impl().WithFundsTransfer(from, to, amount) - if err != nil { - return err - } - - rt._globalStatePending = newGlobalStatePending - return nil -} - -func (rt *VMContext) GetActorCodeID(actorAddr addr.Address) (ret abi.ActorCodeID, ok bool) { - IMPL_FINISH() - panic("") -} - -type ErrorHandlingSpec int - -const ( - PropagateErrors ErrorHandlingSpec = 1 + iota - CatchErrors -) - -// TODO: This function should be private (not intended to be exposed to actors). -// (merging runtime and interpreter packages should solve this) -// TODO: this should not use the MessageReceipt return type, even though it needs the same triple -// of values. This method cannot compute the total gas cost and the returned receipt will never -// go on chain. -func (rt *VMContext) SendToplevelFromInterpreter(input InvocInput) (MessageReceipt, st.StateTree) { - - rt._running = true - ret := rt._sendInternal(input, CatchErrors) - rt._running = false - return ret, rt._globalStatePending -} - -func _catchRuntimeErrors(f func() InvocOutput) (output InvocOutput, exitCode exitcode.ExitCode) { - defer func() { - if r := recover(); r != nil { - switch r.(type) { - case *RuntimeError: - output = vmr.InvocOutput_Make(nil) - exitCode = (r.(*RuntimeError).ExitCode) - default: - panic(r) - } - } - }() - - output = f() - exitCode = exitcode.OK() - return -} - -func _invokeMethodInternal( - rt *VMContext, - actorCode vmr.ActorCode, - method abi.MethodNum, - params abi.MethodParams) ( - ret InvocOutput, exitCode exitcode.ExitCode, internalCallSeqNumFinal actstate.CallSeqNum) { - - if method == builtin.MethodSend { - ret = vmr.InvocOutput_Make(nil) - return - } - - rt._running = true - ret, exitCode = _catchRuntimeErrors(func() InvocOutput { - IMPL_TODO("dispatch to actor code") - var methodOutput vmr.InvocOutput // actorCode.InvokeMethod(rt, method, params) - if rt._actorSubstateUpdated { - rt._rtAllocGas(gascost.UpdateActorSubstate) - } - rt._checkActorStateNotAcquired() - rt._checkNumValidateCalls(1) - return methodOutput - }) - rt._running = false - - internalCallSeqNumFinal = rt._internalCallSeqNum - - return -} - -func (rtOuter *VMContext) _sendInternal(input InvocInput, errSpec ErrorHandlingSpec) MessageReceipt { - rtOuter._checkRunning() - rtOuter._checkActorStateNotAcquired() - - initGasRemaining := rtOuter._gasRemaining - - rtOuter._rtAllocGas(gascost.InvokeMethod(input.Value, input.Method)) - - receiver, receiverAddr := rtOuter._resolveReceiver(input.To) - receiverCode, err := loadActorCode(receiver.CodeID()) - if err != nil { - rtOuter._throwError(exitcode.ActorCodeNotFound) - } - - err = rtOuter._transferFunds(rtOuter._actorAddress, receiverAddr, input.Value) - if err != nil { - rtOuter._throwError(exitcode.InsufficientFunds_System) - } - - rtInner := VMContext_Make( - rtOuter._store, - rtOuter._chain, - rtOuter._toplevelSender, - rtOuter._toplevelBlockWinner, - rtOuter._toplevelMsgCallSeqNum, - rtOuter._internalCallSeqNum+1, - rtOuter._globalStatePending, - receiverAddr, - input.Value, - rtOuter._gasRemaining, - ) - - invocOutput, exitCode, internalCallSeqNumFinal := _invokeMethodInternal( - rtInner, - receiverCode, - input.Method, - input.Params, - ) - - _gasAmountAssertValid(rtOuter._gasRemaining.Subtract(rtInner._gasRemaining)) - rtOuter._gasRemaining = rtInner._gasRemaining - gasUsed := initGasRemaining.Subtract(rtOuter._gasRemaining) - _gasAmountAssertValid(gasUsed) - - rtOuter._internalCallSeqNum = internalCallSeqNumFinal - - if exitCode == exitcode.OutOfGas { - // OutOfGas error cannot be caught - rtOuter._throwError(exitCode) - } - - if errSpec == PropagateErrors && exitCode.IsError() { - rtOuter._throwError(exitcode.MethodSubcallError) - } - - if exitCode.AllowsStateUpdate() { - rtOuter._globalStatePending = rtInner._globalStatePending - } - - return MessageReceipt_Make(invocOutput, exitCode, gasUsed) -} - -// Loads a receiving actor state from the state tree, resolving non-ID addresses through the InitActor state. -// If it doesn't exist, and the message is a simple value send to a pubkey-style address, -// creates the receiver as an account actor in the returned state. -// Aborts otherwise. -func (rt *VMContext) _resolveReceiver(targetRaw addr.Address) (actstate.ActorState, addr.Address) { - // Resolve the target address via the InitActor, and attempt to load state. - initSubState := rt._loadInitActorState() - targetIdAddr := initSubState.ResolveAddress(targetRaw) - act, found := rt._globalStatePending.GetActor(targetIdAddr) - if found { - return act, targetIdAddr - } - - if targetRaw.Protocol() != addr.SECP256K1 && targetRaw.Protocol() != addr.BLS { - // Don't implicitly create an account actor for an address without an associated key. - rt._throwError(exitcode.ActorNotFound) - } - - // Allocate an ID address from the init actor and map the pubkey To address to it. - newIdAddr := initSubState.MapAddressToNewID(targetRaw) - rt._saveInitActorState(initSubState) - - // Create new account actor (charges gas). - rt._createActor(builtin.AccountActorCodeID, newIdAddr) - - // Initialize account actor substate with it's pubkey address. - substate := &acctact.AccountActorState{ - Address: targetRaw, - } - rt._saveAccountActorState(newIdAddr, *substate) - act, _ = rt._globalStatePending.GetActor(newIdAddr) - return act, newIdAddr -} - -func (rt *VMContext) _loadInitActorState() initact.InitActorState { - initState, ok := rt._globalStatePending.GetActor(builtin.InitActorAddr) - util.Assert(ok) - var initSubState initact.InitActorState - ok = rt.IpldGet(cid.Cid(initState.State()), &initSubState) - util.Assert(ok) - return initSubState -} - -func (rt *VMContext) _saveInitActorState(state initact.InitActorState) { - // Gas is charged here separately from _actorSubstateUpdated because this is a different actor - // than the receiver. - rt._rtAllocGas(gascost.UpdateActorSubstate) - rt._updateActorSubstateInternal(builtin.InitActorAddr, actor.ActorSubstateCID(rt.IpldPut(&state))) -} - -func (rt *VMContext) _saveAccountActorState(address addr.Address, state acctact.AccountActorState) { - // Gas is charged here separately from _actorSubstateUpdated because this is a different actor - // than the receiver. - rt._rtAllocGas(gascost.UpdateActorSubstate) - rt._updateActorSubstateInternal(address, actor.ActorSubstateCID(rt.IpldPut(state))) -} - -func (rt *VMContext) _sendInternalOutputs(input InvocInput, errSpec ErrorHandlingSpec) (InvocOutput, exitcode.ExitCode) { - ret := rt._sendInternal(input, errSpec) - return vmr.InvocOutput_Make(ret.ReturnValue), ret.ExitCode -} - -func (rt *VMContext) Send( - toAddr addr.Address, methodNum abi.MethodNum, params abi.MethodParams, value abi.TokenAmount) InvocOutput { - - return rt.SendPropagatingErrors(vmr.InvocInput_Make(toAddr, methodNum, params, value)) -} - -func (rt *VMContext) SendQuery(toAddr addr.Address, methodNum abi.MethodNum, params abi.MethodParams) util.Serialization { - invocOutput := rt.Send(toAddr, methodNum, params, abi.TokenAmount(0)) - ret := invocOutput.ReturnValue - Assert(ret != nil) - return ret -} - -func (rt *VMContext) SendFunds(toAddr addr.Address, value abi.TokenAmount) { - rt.Send(toAddr, builtin.MethodSend, nil, value) -} - -func (rt *VMContext) SendPropagatingErrors(input InvocInput) InvocOutput { - ret, _ := rt._sendInternalOutputs(input, PropagateErrors) - return ret -} - -func (rt *VMContext) SendCatchingErrors(input InvocInput) (InvocOutput, exitcode.ExitCode) { - rt.ValidateImmediateCallerIs(builtin.CronActorAddr) - return rt._sendInternalOutputs(input, CatchErrors) -} - -func (rt *VMContext) CurrentBalance() abi.TokenAmount { - IMPL_FINISH() - panic("") -} - -func (rt *VMContext) ValueReceived() abi.TokenAmount { - return rt._valueReceived -} - -func (rt *VMContext) GetRandomness(epoch abi.ChainEpoch) abi.RandomnessSeed { - return rt._chain.RandomnessSeedAtEpoch(epoch) -} - -func (rt *VMContext) NewActorAddress() addr.Address { - addrBuf := new(bytes.Buffer) - - senderState, ok := rt._globalStatePending.GetActor(rt._toplevelSender) - util.Assert(ok) - var aast acctact.AccountActorState - ok = rt.IpldGet(cid.Cid(senderState.State()), &aast) - util.Assert(ok) - err := aast.Address.MarshalCBOR(addrBuf) - util.Assert(err == nil) - err = binary.Write(addrBuf, binary.BigEndian, rt._toplevelMsgCallSeqNum) - util.Assert(err != nil) - err = binary.Write(addrBuf, binary.BigEndian, rt._internalCallSeqNum) - util.Assert(err != nil) - - newAddr, err := addr.NewActorAddress(addrBuf.Bytes()) - util.Assert(err == nil) - return newAddr -} - -func (rt *VMContext) IpldPut(x ipld.Object) cid.Cid { - IMPL_FINISH() // Serialization - serialized := []byte{} - cid := rt._store.Put(serialized) - rt._rtAllocGas(gascost.IpldPut(len(serialized))) - return cid -} - -func (rt *VMContext) IpldGet(c cid.Cid, o ipld.Object) bool { - serialized, ok := rt._store.Get(c) - if ok { - rt._rtAllocGas(gascost.IpldGet(len(serialized))) - } - IMPL_FINISH() // Deserialization into o - return ok -} - -func (rt *VMContext) CurrEpoch() abi.ChainEpoch { - IMPL_FINISH() - panic("") -} - -func (rt *VMContext) CurrIndices() indices.Indices { - // TODO: compute from state tree (rt._globalStatePending), using individual actor - // state helper functions when possible - TODO() - panic("") -} - -func (rt *VMContext) AcquireState() ActorStateHandle { - rt._checkRunning() - rt._checkActorStateNotAcquired() - rt._actorStateAcquired = true - - state, ok := rt._globalStatePending.GetActor(rt._actorAddress) - util.Assert(ok) - - stateRef := state.State().Ref() - return &ActorStateHandle_I{ - _initValue: &stateRef, - _rt: rt, - } -} - -func (rt *VMContext) Compute(f ComputeFunctionID, args []util.Any) Any { - def, found := _computeFunctionDefs[f] - if !found { - rt.AbortAPI("Function definition in rt.Compute() not found") - } - gasCost := def.GasCostFn(args) - rt._rtAllocGas(gasCost) - return def.Body(args) -} diff --git a/content/systems/filecoin_vm/runtime/impl/runtime_compute.go b/content/systems/filecoin_vm/runtime/impl/runtime_compute.go deleted file mode 100644 index ebed733e9..000000000 --- a/content/systems/filecoin_vm/runtime/impl/runtime_compute.go +++ /dev/null @@ -1,62 +0,0 @@ -package impl - -import filcrypto "github.com/filecoin-project/specs/algorithms/crypto" -import gascost "github.com/filecoin-project/specs/systems/filecoin_vm/runtime/gascost" -import msg "github.com/filecoin-project/specs/systems/filecoin_vm/message" -import util "github.com/filecoin-project/specs/util" -import vmr "github.com/filecoin-project/specs-actors/actors/runtime" - -type Any = util.Any -type Int = util.Int -type ComputeFunctionID = vmr.ComputeFunctionID - -type ComputeFunctionBody = func([]Any) Any -type ComputeFunctionGasCostFn = func([]Any) msg.GasAmount - -type ComputeFunctionDef struct { - Body ComputeFunctionBody - GasCostFn ComputeFunctionGasCostFn -} - -var _computeFunctionDefs = map[ComputeFunctionID]ComputeFunctionDef{} - -func init() { - // VerifySignature - _computeFunctionDefs[vmr.Compute_VerifySignature] = ComputeFunctionDef{ - Body: func(args []Any) Any { - if len(args) != 3 { - return nil - } - i := 0 - - pk, ok := args[i].(filcrypto.PublicKey) - i++ - if !ok { - return nil - } - sig, ok := args[i].(filcrypto.Signature) - i++ - if !ok { - return nil - } - m, ok := args[i].(filcrypto.Message) - i++ - if !ok { - return nil - } - - if i != len(args) { - return nil - } - - valid, err := filcrypto.Verify(pk, sig, m) - if err != nil { - return nil - } - return valid - }, - GasCostFn: func(args []Any) msg.GasAmount { - return gascost.PublicKeyCryptoOp - }, - } -} diff --git a/content/systems/filecoin_vm/state_tree/convenience_api.id b/content/systems/filecoin_vm/state_tree/convenience_api.id deleted file mode 100644 index 08978fb95..000000000 --- a/content/systems/filecoin_vm/state_tree/convenience_api.id +++ /dev/null @@ -1,18 +0,0 @@ -// Things we may add to statetree: -// -// number of sectors -// number of miners -// number of deals? -// number of actors -// -// number of addresses -// token stats -// storage power stats -// -// $head/state/sectors/count -// $head/state/sectors/ (cid) -// $head/state/sectors//size -// $head/state/sectors//pieces/count -// $head/state/sectors//pieces/ (cid) -// $head/state/pieces/count -// $head/state/pieces/ (cid) diff --git a/content/systems/filecoin_vm/state_tree/state_tree.go b/content/systems/filecoin_vm/state_tree/state_tree.go deleted file mode 100644 index 1772b56c4..000000000 --- a/content/systems/filecoin_vm/state_tree/state_tree.go +++ /dev/null @@ -1,116 +0,0 @@ -package state_tree - -import ( - addr "github.com/filecoin-project/go-address" - actor "github.com/filecoin-project/specs-actors/actors" - "github.com/filecoin-project/specs-actors/actors/abi" - actstate "github.com/filecoin-project/specs/systems/filecoin_vm/actor" - "github.com/filecoin-project/specs/util" - cid "github.com/ipfs/go-cid" -) - -var Assert = util.Assert -var IMPL_FINISH = util.IMPL_FINISH -var IMPL_TODO = util.IMPL_TODO - -func (st *StateTree_I) RootCID() cid.Cid { - IMPL_FINISH() - panic("") -} - -func (st *StateTree_I) GetActor(a addr.Address) (actstate.ActorState, bool) { - as, found := st.ActorStates()[a] - return as, found -} - -func (st *StateTree_I) GetActorCodeID_Assert(a addr.Address) abi.ActorCodeID { - ret, found := st.GetActor(a) - Assert(found) - return ret.CodeID() -} - -func (st *StateTree_I) WithActorSubstate(a addr.Address, actorState actor.ActorSubstateCID) (StateTree, error) { - IMPL_FINISH() - panic("") -} - -func (st *StateTree_I) WithDeleteActorSystemState(a addr.Address) StateTree { - IMPL_FINISH() - panic("") -} - -func (st *StateTree_I) WithActorSystemState(a addr.Address, actorState actstate.ActorSystemStateCID) (StateTree, error) { - IMPL_FINISH() - panic("") -} - -func (st *StateTree_I) WithFundsTransfer(from addr.Address, to addr.Address, amount abi.TokenAmount) (StateTree, error) { - IMPL_FINISH() - panic("") -} - -func (st *StateTree_I) WithNewAccountActor(a addr.Address) (StateTree, actstate.ActorState, error) { - IMPL_FINISH() - panic("") -} - -func (st *StateTree_I) WithIncrementedCallSeqNum(a addr.Address) (StateTree, error) { - IMPL_FINISH() - panic("") -} - -func (st *StateTree_I) WithIncrementedCallSeqNum_Assert(a addr.Address) StateTree { - ret, err := st.WithIncrementedCallSeqNum(a) - if err != nil { - panic("Error incrementing actor call sequence number") - } - return ret -} - -/* -TODO: finish - - -func treeIncrementActorSeqNo(inTree StateTree, a actor.Actor) (outTree StateTree) { - panic("todo") -} - -func treeDeductFunds(inTree StateTree, a actor.Actor, amt abi.TokenAmount) (outTree StateTree) { - // TODO: turn this into a single transfer call. - panic("todo") -} - -func treeDepositFunds(inTree StateTree, a actor.Actor, amt abi.TokenAmount) (outTree StateTree) { - // TODO: turn this into a single transfer call. - panic("todo") -} - -func treeGetOrCreateAccountActor(inTree StateTree, a addr.Address) (outTree StateTree, _ actor.Actor, err error) { - - toActor := inTree.GetActor(a) - if toActor != nil { // found - return inTree, toActor, nil - } - - switch a.Type().Which() { - case addr.Address_Type_Case_BLS: - return treeNewBLSAccountActor(inTree, a) - case addr.Address_Type_Case_Secp256k1: - return treeNewSecp256k1AccountActor(inTree, a) - case addr.Address_Type_Case_ID: - return inTree, nil, errors.New("no actor with given ID") - case addr.Address_Type_Case_Actor: - return inTree, nil, errors.New("no such actor") - default: - return inTree, nil, errors.New("unknown address type") - } -} - -func treeNewBLSAccountActor(inTree StateTree, addr addr.Address) (outTree StateTree, _ actor.Actor, err error) { - panic("todo") -} - -func treeNewSecp256k1AccountActor(inTree StateTree, addr addr.Address) (outTree StateTree, _ actor.Actor, err error) { - panic("todo") -} -*/ diff --git a/content/systems/filecoin_vm/vm.id b/content/systems/filecoin_vm/vm.id deleted file mode 100644 index d39d93677..000000000 --- a/content/systems/filecoin_vm/vm.id +++ /dev/null @@ -1,26 +0,0 @@ -import msg "github.com/filecoin-project/specs/systems/filecoin_vm/message" -import st "github.com/filecoin-project/specs/systems/filecoin_vm/state_tree" - -// VM is the object that controls execution. -// It is a stateless, pure function. It uses no local storage. -// -// TODO: make it just a function: VMExec(...) ? -type VM struct { - // Execute computes and returns outTree, a new StateTree which is the - // application of msgs to inTree. - // - // *Important:* Execute is intended to be a pure function, with no side-effects. - // however, storage of the new parts of the computed outTree may exist in - // local storage. - // - // *TODO:* define whether this should take 0, 1, or 2 IpldStores: - // - (): storage of IPLD datastructures is assumed implicit - // - (store): get and put to same IpldStore - // - (inStore, outStore): get from inStore, put new structures into outStore - // - // This decision impacts callers, and potentially impacts how we reason about - // local storage, and intermediate storage. It is definitely the case that - // implementations may want to operate on this differently, depending on - // how their IpldStores work. - Execute(inTree st.StateTree, msgs [msg.UnsignedMessage]) union {outTree st.StateTree, err error} -}