github.com/MetalBlockchain/metalgo@v1.11.9/x/sync/g_db/db_server.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 _ pb.DBServer = (*DBServer)(nil)
    21  
    22  func NewDBServer(db sync.DB) *DBServer {
    23  	return &DBServer{
    24  		db: db,
    25  	}
    26  }
    27  
    28  type DBServer struct {
    29  	pb.UnsafeDBServer
    30  
    31  	db sync.DB
    32  }
    33  
    34  func (s *DBServer) GetMerkleRoot(
    35  	ctx context.Context,
    36  	_ *emptypb.Empty,
    37  ) (*pb.GetMerkleRootResponse, error) {
    38  	root, err := s.db.GetMerkleRoot(ctx)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	return &pb.GetMerkleRootResponse{
    43  		RootHash: root[:],
    44  	}, nil
    45  }
    46  
    47  func (s *DBServer) GetChangeProof(
    48  	ctx context.Context,
    49  	req *pb.GetChangeProofRequest,
    50  ) (*pb.GetChangeProofResponse, error) {
    51  	startRootID, err := ids.ToID(req.StartRootHash)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  	endRootID, err := ids.ToID(req.EndRootHash)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	start := maybe.Nothing[[]byte]()
    60  	if req.StartKey != nil && !req.StartKey.IsNothing {
    61  		start = maybe.Some(req.StartKey.Value)
    62  	}
    63  	end := maybe.Nothing[[]byte]()
    64  	if req.EndKey != nil && !req.EndKey.IsNothing {
    65  		end = maybe.Some(req.EndKey.Value)
    66  	}
    67  
    68  	changeProof, err := s.db.GetChangeProof(
    69  		ctx,
    70  		startRootID,
    71  		endRootID,
    72  		start,
    73  		end,
    74  		int(req.KeyLimit),
    75  	)
    76  	if err != nil {
    77  		if !errors.Is(err, merkledb.ErrInsufficientHistory) {
    78  			return nil, err
    79  		}
    80  		return &pb.GetChangeProofResponse{
    81  			Response: &pb.GetChangeProofResponse_RootNotPresent{
    82  				RootNotPresent: true,
    83  			},
    84  		}, nil
    85  	}
    86  
    87  	return &pb.GetChangeProofResponse{
    88  		Response: &pb.GetChangeProofResponse_ChangeProof{
    89  			ChangeProof: changeProof.ToProto(),
    90  		},
    91  	}, nil
    92  }
    93  
    94  func (s *DBServer) VerifyChangeProof(
    95  	ctx context.Context,
    96  	req *pb.VerifyChangeProofRequest,
    97  ) (*pb.VerifyChangeProofResponse, error) {
    98  	var proof merkledb.ChangeProof
    99  	if err := proof.UnmarshalProto(req.Proof); err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	rootID, err := ids.ToID(req.ExpectedRootHash)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	startKey := maybe.Nothing[[]byte]()
   108  	if req.StartKey != nil && !req.StartKey.IsNothing {
   109  		startKey = maybe.Some(req.StartKey.Value)
   110  	}
   111  	endKey := maybe.Nothing[[]byte]()
   112  	if req.EndKey != nil && !req.EndKey.IsNothing {
   113  		endKey = maybe.Some(req.EndKey.Value)
   114  	}
   115  
   116  	// TODO there's probably a better way to do this.
   117  	var errString string
   118  	if err := s.db.VerifyChangeProof(ctx, &proof, startKey, endKey, rootID); err != nil {
   119  		errString = err.Error()
   120  	}
   121  	return &pb.VerifyChangeProofResponse{
   122  		Error: errString,
   123  	}, nil
   124  }
   125  
   126  func (s *DBServer) CommitChangeProof(
   127  	ctx context.Context,
   128  	req *pb.CommitChangeProofRequest,
   129  ) (*emptypb.Empty, error) {
   130  	var proof merkledb.ChangeProof
   131  	if err := proof.UnmarshalProto(req.Proof); err != nil {
   132  		return nil, err
   133  	}
   134  
   135  	err := s.db.CommitChangeProof(ctx, &proof)
   136  	return &emptypb.Empty{}, err
   137  }
   138  
   139  func (s *DBServer) GetProof(
   140  	ctx context.Context,
   141  	req *pb.GetProofRequest,
   142  ) (*pb.GetProofResponse, error) {
   143  	proof, err := s.db.GetProof(ctx, req.Key)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  
   148  	return &pb.GetProofResponse{
   149  		Proof: proof.ToProto(),
   150  	}, nil
   151  }
   152  
   153  func (s *DBServer) GetRangeProof(
   154  	ctx context.Context,
   155  	req *pb.GetRangeProofRequest,
   156  ) (*pb.GetRangeProofResponse, error) {
   157  	rootID, err := ids.ToID(req.RootHash)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  	start := maybe.Nothing[[]byte]()
   162  	if req.StartKey != nil && !req.StartKey.IsNothing {
   163  		start = maybe.Some(req.StartKey.Value)
   164  	}
   165  	end := maybe.Nothing[[]byte]()
   166  	if req.EndKey != nil && !req.EndKey.IsNothing {
   167  		end = maybe.Some(req.EndKey.Value)
   168  	}
   169  	proof, err := s.db.GetRangeProofAtRoot(ctx, rootID, start, end, int(req.KeyLimit))
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  
   174  	protoProof := &pb.GetRangeProofResponse{
   175  		Proof: &pb.RangeProof{
   176  			StartProof: make([]*pb.ProofNode, len(proof.StartProof)),
   177  			EndProof:   make([]*pb.ProofNode, len(proof.EndProof)),
   178  			KeyValues:  make([]*pb.KeyValue, len(proof.KeyValues)),
   179  		},
   180  	}
   181  	for i, node := range proof.StartProof {
   182  		protoProof.Proof.StartProof[i] = node.ToProto()
   183  	}
   184  	for i, node := range proof.EndProof {
   185  		protoProof.Proof.EndProof[i] = node.ToProto()
   186  	}
   187  	for i, kv := range proof.KeyValues {
   188  		protoProof.Proof.KeyValues[i] = &pb.KeyValue{
   189  			Key:   kv.Key,
   190  			Value: kv.Value,
   191  		}
   192  	}
   193  
   194  	return protoProof, nil
   195  }
   196  
   197  func (s *DBServer) CommitRangeProof(
   198  	ctx context.Context,
   199  	req *pb.CommitRangeProofRequest,
   200  ) (*emptypb.Empty, error) {
   201  	var proof merkledb.RangeProof
   202  	if err := proof.UnmarshalProto(req.RangeProof); err != nil {
   203  		return nil, err
   204  	}
   205  
   206  	start := maybe.Nothing[[]byte]()
   207  	if req.StartKey != nil && !req.StartKey.IsNothing {
   208  		start = maybe.Some(req.StartKey.Value)
   209  	}
   210  
   211  	end := maybe.Nothing[[]byte]()
   212  	if req.EndKey != nil && !req.EndKey.IsNothing {
   213  		end = maybe.Some(req.EndKey.Value)
   214  	}
   215  
   216  	err := s.db.CommitRangeProof(ctx, start, end, &proof)
   217  	return &emptypb.Empty{}, err
   218  }
   219  
   220  func (s *DBServer) Clear(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
   221  	return &emptypb.Empty{}, s.db.Clear()
   222  }