Closed willscott closed 6 years ago
cc @kostko @ryscheng
Notes:
claim
calls.Do we want to be ERC-20 compliant? https://theethereum.wiki/w/index.php/ERC20_Token_Standard
If so, aren't stake() and withdraw() sufficiently handled by the transfer() function? Similarly, isn't claim() sufficiently handled by the transferFrom() function? The only thing we need to add is the escrow() function, which serves a different purpose than approve()
Is it worth adding an explicit stake(), withdraw(), and claim()?
claim()
as used above is not quite a transferFrom()
in that it pairs with escrow()
, where the destination address is not known at the time of approve
, (can't be explicitly pre-approved by the escrow-er)
claim() as used above is not quite a transferFrom() in that it pairs with escrow(), where the destination address is not known at the time of approve, (can't be explicitly pre-approved by the escrow-er)
Okay, that makes sense for escrow/claim. But I'm not sure I understand Deposit/Withdraw stake. Who calls that and how? How do I get tokens in the first place? Does it make more sense to support ERC-20 style transfer() instead so that we can interact with existing exchanges?
yes. i agree that we should start with an ERC-20 token for depost/withdraw, and then mold the escrow methods onto that
The Deposit/Withdraw methods were in the Rust API, but have been removed from the Solidity version (https://github.com/oasislabs/ekiden/pull/355). There is only initial allocation, transfer, and burn operations now.
The Stake contract does not know about time. None of the ERC20 tokens do. Allowances do not have any kind of expiry, and escrows do not either. The idea is that the escrow account can be closed by the registry for whatever reason -- if the entity wishes her/his machine to be deregistered, then it's a call to the registry which allows it to close the escrow account and return the entire escrowed stake back to the entity.
Generally, I don't think we should have multi-party contracts when 2-party contracts will do -- like in protocol design, that dramatically increases complexity; instead, telescoping/nested contracts should do.
As discussed, the stakeholder who is entering into escrow with the registry is making a claim that a particular machine is "good for computation". The stakeholder has no idea what consensus mechanism will be used, and minimally the size of the consensus groups are parameterized. The scheduler gets job requirements -- security level needed (hw vs sw, minimum stake, committee sizes, etc) -- and queries the registry for a list of machines that satisfy the security needs. The registry is advertising (on the behalf of the respective stakeholders) the claim that the machines satisfy the requirements. The scheduler needs to know when the computation is done, so that a machine would not get another job assigned to it -- that would increase the chances of forfeiture due to the machine being too slow -- so I think we should view the scheduler as "renting" the compute node from the registry, and it should "return" or "release" the compute node when the job is done. NB: do we allow a job to span an epoch? In a short-epoch world this is likely to be the case (esp since we are targeting more compute-intensive workloads), and the scheduler/registry has to ensure that a machine is not overloaded. We do not want to take an entity's stake because we overloaded their machine; that makes for unhappy users. The rent-out/return model makes a lot of sense in this context.
If we ever implement Quinn-style execution trace comparisons, we may not want to release a compute node back to the worker pool until we are sure that no discrepancy was detected. This way we can have compute nodes log data to make execution trace comparisons, and allow this log to be deleted when the discrepancy detection/resolution is complete.
Back to multi-party contracts. If we might have multiple consensus mechanisms (contracts), then there is no way for the escrow mechanism to predict which consensus mechanism might find fault with the machine. This may argue for either that there is only one consensus mechanism or that the stakeholder gets to specify which consensus mechanisms are acceptable to her/him, since the consensus contract determines when the stakeholder's escrow is forfeit. Do we want to have a version of escrow creation that accepts a list of addresses which may decide on the outcome when the escrow account is closed?
When we think about this, we'll also need to think about what we mean by 'addresses'. A contract has an address, and we can set up the stake contract so it only allows operations from a set of authorized other contracts, but contract addresses can't sign things, in same way that an entity can.
I wonder if we can hard-code authorized contracts to make changes in the stake contract, where changes to that list are performed by re-deploying a new version of the contract?
@ryscheng pointed out that our discrepancy detection probability calculations are based on the binomial distribution, or that the sample set is large enough that sampling-with-replacement is a good enough approximation. the idea of overloaded compute nodes that get dinged (slow, so smaller gas payout, or too slow, and [partial?] stake forfeiture) because they are assigned to multiple committees and the interaction with being listed as available (stateful) or not needs more thought.
also, the economics of our staking token -- needed to participate as a compute node -- implies that our network should keep compute nodes as busy as possible, i.e., so that their ability to earn gas should be maximized; otherwise the ROI for the stake is low, and the value of the staking token goes down, and the value of the stake goes down, and the required stake for "high-stakes" computation (pun intended) as per forfeit factor analysis would make users require more stake tokens, etc. This can lead to a bad negative feedback cycle, where the number of nodes that can satisfy user security requirements diminish, and the network ends up with very little work, though it may also settle into an equilibrium position as well. but because we want to maximize ROI for stakeholders, that hopefully mean that the number of "free" compute nodes (where no computation is assigned yet) should be low. If the compute node utilization fraction is close to 1.0, then if we further only assigned jobs to the remaining free compute nodes, then the assumption that sampling-with-replacement is good enough may not be valid, since high utilization means that an adversary could wait until the bad nodes under their control is a high fraction of the remaining free nodes, skewing the adversary fraction to be much higher than anticipated. (should some of this be analyzed & put into an RFC?)
anyhow, the escrow account has an arbitrary address that decides whether how much of the escrowed amount to claim and take, with the remainder of the escrow returning to the stakeholder. that address can be the consensus contract, or a proxy for all possible consensus contracts, rather than the registry; @willscott , with the registry being able to use the new "aux" uint256 escrow account info to ensure that an escrow is not doubly used (tied to a compute node), is the staking/escrow interface is okay now for the registry's needs?
Yep. I think we're good for Registry needs. We can refer back to this issue as yawning finishes the design for consensus, but I think we've got a plan 👍
In trying to wire up stake in registry, it looks like we'll need to refactor that API
Here's the process that needs to be enabled:
Stake()
as a value transfer to the contract (doesn't need to be a method in rust / can be a testing method in dummy implementation)escrow(eth_address, amount,number_epochs, authorization)
where authorization is a signed validation by eth_address that the stake contract can validate. (the contract will check that a digest signed by eth_address matches the keccak hash of the epoch, length of time, and amount). NOTE: it seems like it's going to be pragmatic to registry be for an amount of time, where the entity is able to withdraw its remaining stake after a given number of epochs. Otherwise, we can't tell easily when the node is on committees / what it's allowed to withdraw from escrow at a given time. By knowing in advance how long it's committed, the scheduler can make sure it's not scheduled for committees after that given time.claim(eth_address, amount, destination_account)
where that call must come from the consensus contract.There's a second half of this contract as well that this implies, which is the accounting around running contracts. that can also use the same
escrow
andclaim
process, with the caveat that client escrows will need to be in the context of a single contract, to prevent double spending. As such theescrow()
call probably also takes acontext
parameter of the account where the escrow is made. For clients, this is the contract. For entity/compute nodes, this could be a special 0 designation or similar.All of these are on-chain actions, so we may not need the rust interface at the moment, because it becomes quite hard to validate these actions when the call flows out to individual nodes and back in to ethereum.