libplanet
libplanet copied to clipboard
🛑 Remove `PreEvaluationBlock`
Context
PreEvaluationBlock played an important role in the days when Libplanet ran on PoW. The idea of ​​HashRandom, which determines the Hash before executing a transaction and uses it as a Random Seed, has always been a core concept of Libplanet.
However, now that the PBFT consensus algorithm has been adopted, there is less reason to use this method. Rather, the problem is that Hash is easy to manipulate, making it easy to use the transaction results as desired.
We attempted to introduce VRF to solve this problem, but it is difficult to introduce VRF in its current form as the StateRootHash of the nth block contains the execution result of the nth block.
Therefore, we would like to proceed with a more flexible and reliable chain consensus by deleting PreEvaluationBlock and making StateRootHash look at the execution results of the previous block.
Rationale
We must check the point below.
- Meaning of genesis block.
- How to store the nth block's state root hash.
- Side effect of changes.
Meaning of genesis block
For now, Block.StateRootHash is a root hash of the state after state transition, which is triggered by Block.Transactions.
So, Block proves the result of the Block.Transaction, so if someone finds state whose root hash is equal to Block.StateRootHash, he can believe that state is result state of Block.
After above change applied, there's no way to prove some state is a result state of Block, without computing state transition, so meaning of Block has been changed slightly.
Now Block means a set of previous state and transactions, which was a set of transactions and result state (a, s') => (s, a), which means almost same as current PreEvaluationBlock.
For the genesis block, it meant "world setter transactions" and "state after world setter transactions" previously, but this have to be redefined.
IMO, What we have to decide is, whether define genesis block as
Empty state + World setter transactionsorState after world setter transactions + Empty transactions-> (I think it doesn't have to be empty though)
From a different point of view, we can remove genesis block, starting 1st block with consensus.
How to store the nth block's state root hash
Below methods will be added to IStore interface.
void PutNextStateRootHash(BlockHash hash, HashDigest<SHA256> stateRootHash)HashDigest<SHA256> GetNextStateRootHash(BlockHash hash)
BlockChain.Append() will check below additionally.
GetNextStateRootHash(block.PreviousHash).Equals(block.StateRootHash)
BlockChain will hold additional event handler.
event EventHandler<(Block block, HashDigest<SHA256> stateRootHash)> NextStateRootHashEvaluated- Above event will be triggered in the
BlockChain.Append(), afterIStateStore.PutNextStateRootHash()called
Context.IsValid(Block block) will be suspended until BlockChain.NextStateRootHashEvaluated triggered.
Redefine StateRootHash
- [x] Update
IStore - [x] Update
BlockChain.Append() - [x] Update
BlockChain.ValidateBlock() - [x] Update
BlockChain.Propose() - [x] Update tests for blockchain
- [ ] Update
Consensus.IsValid() - [ ] Update tests for consensus
- [ ] Update queries for
IWorldState