ethclient/lightclient: addressed some TODOs

This commit is contained in:
Zsolt Felfoldi 2024-06-08 13:58:21 +02:00
parent 88a3179a8d
commit cd41011cd4
2 changed files with 40 additions and 16 deletions

View file

@ -67,7 +67,7 @@ func (c *Client) fetchProof(ctx context.Context, req proofRequest) (*gethclient.
request := c.proofRequests.request(req) request := c.proofRequests.request(req)
proof, err := request.getResult(ctx) proof, err := request.getResult(ctx)
if err == nil { if err == nil {
c.proofCache.Add(req, proof) //TODO cached before validation; remove and retry if invalid c.proofCache.Add(req, proof) // cached before validation; remove and retry if invalid
} }
request.release() request.release()
return proof, err return proof, err
@ -129,7 +129,7 @@ func (c *Client) fetchCode(ctx context.Context, req codeRequest) ([]byte, error)
request := c.codeRequests.request(req) request := c.codeRequests.request(req)
code, err := request.getResult(ctx) code, err := request.getResult(ctx)
if err == nil { if err == nil {
c.codeCache.Add(req, code) //TODO cached before validation; remove and retry if invalid c.codeCache.Add(req, code) // cached before validation; remove and retry if invalid
} }
request.release() request.release()
return code, err return code, err
@ -190,9 +190,17 @@ func stValueBytes(value *big.Int) ([]byte, error) {
} }
func (c *Client) getProof(ctx context.Context, blockNumber *big.Int, account common.Address, storageKeys []string, getCode bool) (*gethclient.AccountResult, []byte, error) { func (c *Client) getProof(ctx context.Context, blockNumber *big.Int, account common.Address, storageKeys []string, getCode bool) (*gethclient.AccountResult, []byte, error) {
proof, code, retry, err := c.getProofOnce(ctx, blockNumber, account, storageKeys, getCode)
if retry {
proof, code, _, err = c.getProofOnce(ctx, blockNumber, account, storageKeys, getCode)
}
return proof, code, err
}
func (c *Client) getProofOnce(ctx context.Context, blockNumber *big.Int, account common.Address, storageKeys []string, getCode bool) (*gethclient.AccountResult, []byte, bool, error) {
num, pheader, err := c.resolveBlockNumber(blockNumber) num, pheader, err := c.resolveBlockNumber(blockNumber)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, false, err
} }
var ( var (
stateRoot common.Hash stateRoot common.Hash
@ -227,34 +235,44 @@ func (c *Client) getProof(ctx context.Context, blockNumber *big.Int, account com
code []byte code []byte
codeErr error codeErr error
codeCh = make(chan struct{}) codeCh = make(chan struct{})
codeReq codeRequest
) )
if getCode { if getCode {
go func() { go func() {
code, codeErr = c.fetchCode(ctx, codeRequest{blockNumber: num, address: account}) codeReq = codeRequest{blockNumber: num, address: account}
code, codeErr = c.fetchCode(ctx, codeReq)
close(codeCh) close(codeCh)
}() }()
} }
proof, proofErr := c.fetchProof(ctx, proofRequest{blockNumber: num, address: account, storageKeys: strings.Join(storageKeys, ",")}) proofReq := proofRequest{blockNumber: num, address: account, storageKeys: strings.Join(storageKeys, ",")}
proof, proofErr := c.fetchProof(ctx, proofReq)
if proofErr != nil { if proofErr != nil {
return nil, nil, proofErr return nil, nil, false, proofErr
} }
<-stateRootCh <-stateRootCh
if stateRootErr != nil { if stateRootErr != nil {
return nil, nil, stateRootErr return nil, nil, false, stateRootErr
} }
if err := c.validateProof(proof, stateRoot, account, storageKeys); err != nil { if err := c.validateProof(proof, stateRoot, account, storageKeys); err != nil {
return nil, nil, err if getCode {
<-codeCh
c.codeCache.Remove(codeReq)
}
c.proofCache.Remove(proofReq)
return nil, nil, true, err
} }
if getCode { if getCode {
<-codeCh <-codeCh
if codeErr != nil { if codeErr != nil {
return nil, nil, codeErr return nil, nil, false, codeErr
} }
if crypto.Keccak256Hash(code) != proof.CodeHash { if crypto.Keccak256Hash(code) != proof.CodeHash {
return nil, nil, errors.New("code hash mismatch") c.codeCache.Remove(codeReq)
c.proofCache.Remove(proofReq)
return nil, nil, true, errors.New("code hash mismatch")
} }
} }
return proof, code, nil return proof, code, false, nil
} }
func (c *Client) validateProof(proof *gethclient.AccountResult, stateRoot common.Hash, account common.Address, storageKeys []string) error { func (c *Client) validateProof(proof *gethclient.AccountResult, stateRoot common.Hash, account common.Address, storageKeys []string) error {
@ -312,7 +330,7 @@ func (c *Client) validateProof(proof *gethclient.AccountResult, stateRoot common
if err != nil { if err != nil {
return err return err
} }
key = common.BytesToHash(key).Bytes() // TODO 32 byte padding needed??? key = common.BytesToHash(key).Bytes()
value, err := trie.VerifyProof(proof.StorageHash, crypto.Keccak256(key), proofReader) value, err := trie.VerifyProof(proof.StorageHash, crypto.Keccak256(key), proofReader)
if err != nil { if err != nil {
return err return err
@ -322,8 +340,7 @@ func (c *Client) validateProof(proof *gethclient.AccountResult, stateRoot common
return err return err
} }
enc, _ := rlp.EncodeToBytes(stv) enc, _ := rlp.EncodeToBytes(stv)
if !bytes.Equal(enc, value) { //TODO check for empty value if !bytes.Equal(enc, value) {
//log.Info("storage value mismatch", "value", enc, "proven", value)
return errors.New("storage value mismatch") return errors.New("storage value mismatch")
} }
} }

View file

@ -74,7 +74,11 @@ func (c *Client) getTxByHash(ctx context.Context, txHash common.Hash) (tx *types
if pos, ok := c.txPosCache.Get(txHash); ok { if pos, ok := c.txPosCache.Get(txHash); ok {
if hash, ok := c.getCachedHash(pos.blockNumber); ok && hash == pos.blockHash { if hash, ok := c.getCachedHash(pos.blockNumber); ok && hash == pos.blockHash {
if block, ok := c.blockCache.Get(pos.blockHash); ok { if block, ok := c.blockCache.Get(pos.blockHash); ok {
return block.Transactions()[pos.index], false, nil //TODO index range check transactions := block.Transactions()
if pos.index >= uint(len(transactions)) {
return nil, false, errors.New("transaction index out of range")
}
return transactions[pos.index], false, nil
} }
} }
} }
@ -107,7 +111,10 @@ func (c *Client) getReceiptByTxHash(ctx context.Context, txHash common.Hash) (*t
if pos, ok := c.txPosCache.Get(txHash); ok { if pos, ok := c.txPosCache.Get(txHash); ok {
if hash, ok := c.getCachedHash(pos.blockNumber); ok && hash == pos.blockHash { if hash, ok := c.getCachedHash(pos.blockNumber); ok && hash == pos.blockHash {
if receipts, ok := c.receiptsCache.Get(pos.blockHash); ok { if receipts, ok := c.receiptsCache.Get(pos.blockHash); ok {
return receipts[pos.index], nil //TODO index range check if pos.index >= uint(len(receipts)) {
return nil, errors.New("transaction index out of range")
}
return receipts[pos.index], nil
} }
} }
} }