github.com/MetalBlockchain/metalgo@v1.11.9/x/sync/g_db/db_client.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package gdb
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  
    10  	"google.golang.org/protobuf/types/known/emptypb"
    11  
    12  	"github.com/MetalBlockchain/metalgo/ids"
    13  	"github.com/MetalBlockchain/metalgo/utils/maybe"
    14  	"github.com/MetalBlockchain/metalgo/x/merkledb"
    15  	"github.com/MetalBlockchain/metalgo/x/sync"
    16  
    17  	pb "github.com/MetalBlockchain/metalgo/proto/pb/sync"
    18  )
    19  
    20  var _ sync.DB = (*DBClient)(nil)
    21  
    22  func NewDBClient(client pb.DBClient) *DBClient {
    23  	return &DBClient{
    24  		client: client,
    25  	}
    26  }
    27  
    28  type DBClient struct {
    29  	client pb.DBClient
    30  }
    31  
    32  func (c *DBClient) GetMerkleRoot(ctx context.Context) (ids.ID, error) {
    33  	resp, err := c.client.GetMerkleRoot(ctx, &emptypb.Empty{})
    34  	if err != nil {
    35  		return ids.Empty, err
    36  	}
    37  	return ids.ToID(resp.RootHash)
    38  }
    39  
    40  func (c *DBClient) GetChangeProof(
    41  	ctx context.Context,
    42  	startRootID ids.ID,
    43  	endRootID ids.ID,
    44  	startKey maybe.Maybe[[]byte],
    45  	endKey maybe.Maybe[[]byte],
    46  	keyLimit int,
    47  ) (*merkledb.ChangeProof, error) {
    48  	if endRootID == ids.Empty {
    49  		return nil, merkledb.ErrEmptyProof
    50  	}
    51  
    52  	resp, err := c.client.GetChangeProof(ctx, &pb.GetChangeProofRequest{
    53  		StartRootHash: startRootID[:],
    54  		EndRootHash:   endRootID[:],
    55  		StartKey: &pb.MaybeBytes{
    56  			IsNothing: startKey.IsNothing(),
    57  			Value:     startKey.Value(),
    58  		},
    59  		EndKey: &pb.MaybeBytes{
    60  			IsNothing: endKey.IsNothing(),
    61  			Value:     endKey.Value(),
    62  		},
    63  		KeyLimit: uint32(keyLimit),
    64  	})
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	// TODO handle merkledb.ErrInvalidMaxLength
    70  	// TODO disambiguate between the root not being present due to
    71  	// the end root not being present and the start root not being
    72  	// present before the end root. i.e. ErrNoEndRoot vs ErrInsufficientHistory.
    73  	if resp.GetRootNotPresent() {
    74  		return nil, merkledb.ErrInsufficientHistory
    75  	}
    76  
    77  	var proof merkledb.ChangeProof
    78  	if err := proof.UnmarshalProto(resp.GetChangeProof()); err != nil {
    79  		return nil, err
    80  	}
    81  	return &proof, nil
    82  }
    83  
    84  func (c *DBClient) VerifyChangeProof(
    85  	ctx context.Context,
    86  	proof *merkledb.ChangeProof,
    87  	startKey maybe.Maybe[[]byte],
    88  	endKey maybe.Maybe[[]byte],
    89  	expectedRootID ids.ID,
    90  ) error {
    91  	resp, err := c.client.VerifyChangeProof(ctx, &pb.VerifyChangeProofRequest{
    92  		Proof: proof.ToProto(),
    93  		StartKey: &pb.MaybeBytes{
    94  			Value:     startKey.Value(),
    95  			IsNothing: startKey.IsNothing(),
    96  		},
    97  		EndKey: &pb.MaybeBytes{
    98  			Value:     endKey.Value(),
    99  			IsNothing: endKey.IsNothing(),
   100  		},
   101  		ExpectedRootHash: expectedRootID[:],
   102  	})
   103  	if err != nil {
   104  		return err
   105  	}
   106  
   107  	// TODO there's probably a better way to do this.
   108  	if len(resp.Error) == 0 {
   109  		return nil
   110  	}
   111  	return errors.New(resp.Error)
   112  }
   113  
   114  func (c *DBClient) CommitChangeProof(ctx context.Context, proof *merkledb.ChangeProof) error {
   115  	_, err := c.client.CommitChangeProof(ctx, &pb.CommitChangeProofRequest{
   116  		Proof: proof.ToProto(),
   117  	})
   118  	return err
   119  }
   120  
   121  func (c *DBClient) GetProof(ctx context.Context, key []byte) (*merkledb.Proof, error) {
   122  	resp, err := c.client.GetProof(ctx, &pb.GetProofRequest{
   123  		Key: key,
   124  	})
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  
   129  	var proof merkledb.Proof
   130  	if err := proof.UnmarshalProto(resp.Proof); err != nil {
   131  		return nil, err
   132  	}
   133  	return &proof, nil
   134  }
   135  
   136  func (c *DBClient) GetRangeProofAtRoot(
   137  	ctx context.Context,
   138  	rootID ids.ID,
   139  	startKey maybe.Maybe[[]byte],
   140  	endKey maybe.Maybe[[]byte],
   141  	keyLimit int,
   142  ) (*merkledb.RangeProof, error) {
   143  	if rootID == ids.Empty {
   144  		return nil, merkledb.ErrEmptyProof
   145  	}
   146  
   147  	resp, err := c.client.GetRangeProof(ctx, &pb.GetRangeProofRequest{
   148  		RootHash: rootID[:],
   149  		StartKey: &pb.MaybeBytes{
   150  			IsNothing: startKey.IsNothing(),
   151  			Value:     startKey.Value(),
   152  		},
   153  		EndKey: &pb.MaybeBytes{
   154  			IsNothing: endKey.IsNothing(),
   155  			Value:     endKey.Value(),
   156  		},
   157  		KeyLimit: uint32(keyLimit),
   158  	})
   159  	if err != nil {
   160  		return nil, err
   161  	}
   162  
   163  	var proof merkledb.RangeProof
   164  	if err := proof.UnmarshalProto(resp.Proof); err != nil {
   165  		return nil, err
   166  	}
   167  	return &proof, nil
   168  }
   169  
   170  func (c *DBClient) CommitRangeProof(
   171  	ctx context.Context,
   172  	startKey maybe.Maybe[[]byte],
   173  	endKey maybe.Maybe[[]byte],
   174  	proof *merkledb.RangeProof,
   175  ) error {
   176  	_, err := c.client.CommitRangeProof(ctx, &pb.CommitRangeProofRequest{
   177  		StartKey: &pb.MaybeBytes{
   178  			IsNothing: startKey.IsNothing(),
   179  			Value:     startKey.Value(),
   180  		},
   181  		EndKey: &pb.MaybeBytes{
   182  			IsNothing: endKey.IsNothing(),
   183  			Value:     endKey.Value(),
   184  		},
   185  		RangeProof: proof.ToProto(),
   186  	})
   187  	return err
   188  }
   189  
   190  func (c *DBClient) Clear() error {
   191  	_, err := c.client.Clear(context.Background(), &emptypb.Empty{})
   192  	return err
   193  }