@@ -23,6 +23,7 @@ import (
23
23
"github.com/ethereum/go-ethereum/common"
24
24
"github.com/ethereum/go-ethereum/consensus"
25
25
"github.com/ethereum/go-ethereum/core/state"
26
+ "github.com/ethereum/go-ethereum/core/stateless"
26
27
"github.com/ethereum/go-ethereum/core/types"
27
28
"github.com/ethereum/go-ethereum/params"
28
29
"github.com/ethereum/go-ethereum/trie"
@@ -35,14 +36,12 @@ import (
35
36
type BlockValidator struct {
36
37
config * params.ChainConfig // Chain configuration options
37
38
bc * BlockChain // Canonical block chain
38
- engine consensus.Engine // Consensus engine used for validating
39
39
}
40
40
41
41
// NewBlockValidator returns a new block validator which is safe for re-use
42
- func NewBlockValidator (config * params.ChainConfig , blockchain * BlockChain , engine consensus. Engine ) * BlockValidator {
42
+ func NewBlockValidator (config * params.ChainConfig , blockchain * BlockChain ) * BlockValidator {
43
43
validator := & BlockValidator {
44
44
config : config ,
45
- engine : engine ,
46
45
bc : blockchain ,
47
46
}
48
47
return validator
@@ -60,7 +59,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
60
59
// Header validity is known at this point. Here we verify that uncles, transactions
61
60
// and withdrawals given in the block body match the header.
62
61
header := block .Header ()
63
- if err := v .engine .VerifyUncles (v .bc , block ); err != nil {
62
+ if err := v .bc . engine .VerifyUncles (v .bc , block ); err != nil {
64
63
return err
65
64
}
66
65
if hash := types .CalcUncleHash (block .Uncles ()); hash != header .UncleHash {
@@ -122,31 +121,55 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
122
121
123
122
// ValidateState validates the various changes that happen after a state transition,
124
123
// such as amount of used gas, the receipt roots and the state root itself.
125
- // If validateRemoteRoot is false, the provided block header's root is not asserted to be equal to the one computed from
126
- // execution.
127
- func (v * BlockValidator ) ValidateState (block * types.Block , statedb * state.StateDB , receipts types.Receipts , usedGas uint64 , checkRemoteRoot bool ) (root common.Hash , err error ) {
124
+ func (v * BlockValidator ) ValidateState (block * types.Block , statedb * state.StateDB , receipts types.Receipts , usedGas uint64 , stateless bool ) error {
128
125
header := block .Header ()
129
126
if block .GasUsed () != usedGas {
130
- return root , fmt .Errorf ("invalid gas used (remote: %d local: %d)" , block .GasUsed (), usedGas )
127
+ return fmt .Errorf ("invalid gas used (remote: %d local: %d)" , block .GasUsed (), usedGas )
131
128
}
132
129
// Validate the received block's bloom with the one derived from the generated receipts.
133
130
// For valid blocks this should always validate to true.
134
131
rbloom := types .CreateBloom (receipts )
135
132
if rbloom != header .Bloom {
136
- return root , fmt .Errorf ("invalid bloom (remote: %x local: %x)" , header .Bloom , rbloom )
133
+ return fmt .Errorf ("invalid bloom (remote: %x local: %x)" , header .Bloom , rbloom )
134
+ }
135
+ // In stateless mode, return early because the receipt and state root are not
136
+ // provided through the witness, rather the cross validator needs to return it.
137
+ if stateless {
138
+ return nil
137
139
}
138
140
// The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]]))
139
141
receiptSha := types .DeriveSha (receipts , trie .NewStackTrie (nil ))
140
142
if receiptSha != header .ReceiptHash {
141
- return root , fmt .Errorf ("invalid receipt root hash (remote: %x local: %x)" , header .ReceiptHash , receiptSha )
143
+ return fmt .Errorf ("invalid receipt root hash (remote: %x local: %x)" , header .ReceiptHash , receiptSha )
142
144
}
143
- // Compute the state root and if enabled, check it against the
144
- // received state root and throw an error if they don't match.
145
- root = statedb .IntermediateRoot (v .config .IsEIP158 (header .Number ))
146
- if checkRemoteRoot && header .Root != root {
147
- return root , fmt .Errorf ("invalid merkle root (remote: %x local: %x) dberr: %w" , header .Root , root , statedb .Error ())
145
+ // Validate the state root against the received state root and throw
146
+ // an error if they don't match.
147
+ if root := statedb .IntermediateRoot (v .config .IsEIP158 (header .Number )); header .Root != root {
148
+ return fmt .Errorf ("invalid merkle root (remote: %x local: %x) dberr: %w" , header .Root , root , statedb .Error ())
148
149
}
149
- return root , nil
150
+ return nil
151
+ }
152
+
153
+ // ValidateWitness cross validates a block execution with stateless remote clients.
154
+ //
155
+ // Normally we'd distribute the block witness to remote cross validators, wait
156
+ // for them to respond and then merge the results. For now, however, it's only
157
+ // Geth, so do an internal stateless run.
158
+ func (v * BlockValidator ) ValidateWitness (witness * stateless.Witness , receiptRoot common.Hash , stateRoot common.Hash ) error {
159
+ // Run the cross client stateless execution
160
+ // TODO(karalabe): Self-stateless for now, swap with other clients
161
+ crossReceiptRoot , crossStateRoot , err := ExecuteStateless (v .config , witness )
162
+ if err != nil {
163
+ return fmt .Errorf ("stateless execution failed: %v" , err )
164
+ }
165
+ // Stateless cross execution suceeeded, validate the withheld computed fields
166
+ if crossReceiptRoot != receiptRoot {
167
+ return fmt .Errorf ("cross validator receipt root mismatch (cross: %x local: %x)" , crossReceiptRoot , receiptRoot )
168
+ }
169
+ if crossStateRoot != stateRoot {
170
+ return fmt .Errorf ("cross validator state root mismatch (cross: %x local: %x)" , crossStateRoot , stateRoot )
171
+ }
172
+ return nil
150
173
}
151
174
152
175
// CalcGasLimit computes the gas limit of the next block after parent. It aims
0 commit comments