mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
ethclient/lightclient: addressed some TODOs
This commit is contained in:
parent
88a3179a8d
commit
cd41011cd4
2 changed files with 40 additions and 16 deletions
|
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue