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 }