github.com/leovct/zkevm-bridge-service@v0.4.4/server/service.go (about) 1 package server 2 3 import ( 4 "context" 5 "encoding/hex" 6 "fmt" 7 8 "github.com/0xPolygonHermez/zkevm-bridge-service/bridgectrl" 9 "github.com/0xPolygonHermez/zkevm-bridge-service/bridgectrl/pb" 10 "github.com/0xPolygonHermez/zkevm-bridge-service/etherman" 11 "github.com/0xPolygonHermez/zkevm-bridge-service/log" 12 "github.com/0xPolygonHermez/zkevm-bridge-service/utils/gerror" 13 "github.com/ethereum/go-ethereum/common" 14 lru "github.com/hashicorp/golang-lru/v2" 15 "github.com/jackc/pgx/v4" 16 ) 17 18 type bridgeService struct { 19 rollupID uint 20 storage bridgeServiceStorage 21 networkIDs map[uint]uint8 22 height uint8 23 defaultPageLimit uint32 24 maxPageLimit uint32 25 version string 26 cache *lru.Cache[string, [][]byte] 27 pb.UnimplementedBridgeServiceServer 28 } 29 30 // NewBridgeService creates new bridge service. 31 func NewBridgeService(cfg Config, height uint8, networks []uint, storage interface{}, rollupID uint) *bridgeService { 32 var networkIDs = make(map[uint]uint8) 33 for i, network := range networks { 34 networkIDs[network] = uint8(i) 35 } 36 cache, err := lru.New[string, [][]byte](cfg.CacheSize) 37 if err != nil { 38 panic(err) 39 } 40 return &bridgeService{ 41 rollupID: rollupID, 42 storage: storage.(bridgeServiceStorage), 43 height: height, 44 networkIDs: networkIDs, 45 defaultPageLimit: cfg.DefaultPageLimit, 46 maxPageLimit: cfg.MaxPageLimit, 47 version: cfg.BridgeVersion, 48 cache: cache, 49 } 50 } 51 52 func (s *bridgeService) getNetworkID(networkID uint) (uint8, error) { 53 tID, found := s.networkIDs[networkID] 54 if !found { 55 return 0, gerror.ErrNetworkNotRegister 56 } 57 return tID, nil 58 } 59 60 // getNode returns the children hash pairs for a given parent hash. 61 func (s *bridgeService) getNode(ctx context.Context, parentHash [bridgectrl.KeyLen]byte, dbTx pgx.Tx) (left, right [bridgectrl.KeyLen]byte, err error) { 62 value, ok := s.cache.Get(string(parentHash[:])) 63 if !ok { 64 var err error 65 value, err = s.storage.Get(ctx, parentHash[:], dbTx) 66 if err != nil { 67 return left, right, fmt.Errorf("parentHash: %s, error: %v", common.BytesToHash(parentHash[:]).String(), err) 68 } 69 s.cache.Add(string(parentHash[:]), value) 70 } 71 copy(left[:], value[0]) 72 copy(right[:], value[1]) 73 return left, right, nil 74 } 75 76 // getProof returns the merkle proof for a given index and root. 77 func (s *bridgeService) getProof(index uint, root [bridgectrl.KeyLen]byte, dbTx pgx.Tx) ([][bridgectrl.KeyLen]byte, error) { 78 var siblings [][bridgectrl.KeyLen]byte 79 80 cur := root 81 ctx := context.Background() 82 // It starts in height-1 because 0 is the level of the leafs 83 for h := int(s.height - 1); h >= 0; h-- { 84 left, right, err := s.getNode(ctx, cur, dbTx) 85 if err != nil { 86 return nil, fmt.Errorf("height: %d, cur: %s, error: %v", h, common.BytesToHash(cur[:]).String(), err) 87 } 88 /* 89 * Root (level h=3 => height=4) 90 * / \ 91 * O5 O6 (level h=2) 92 * / \ / \ 93 * O1 O2 O3 O4 (level h=1) 94 * /\ /\ /\ /\ 95 * 0 1 2 3 4 5 6 7 Leafs (level h=0) 96 * Example 1: 97 * Choose index = 3 => 011 binary 98 * Assuming we are in level 1 => h=1; 1<<h = 010 binary 99 * Now, let's do AND operation => 011&010=010 which is higher than 0 so we need the left sibling (O1) 100 * Example 2: 101 * Choose index = 4 => 100 binary 102 * Assuming we are in level 1 => h=1; 1<<h = 010 binary 103 * Now, let's do AND operation => 100&010=000 which is not higher than 0 so we need the right sibling (O4) 104 * Example 3: 105 * Choose index = 4 => 100 binary 106 * Assuming we are in level 2 => h=2; 1<<h = 100 binary 107 * Now, let's do AND operation => 100&100=100 which is higher than 0 so we need the left sibling (O5) 108 */ 109 110 if index&(1<<h) > 0 { 111 siblings = append(siblings, left) 112 cur = right 113 } else { 114 siblings = append(siblings, right) 115 cur = left 116 } 117 } 118 119 // We need to invert the siblings to go from leafs to the top 120 for st, en := 0, len(siblings)-1; st < en; st, en = st+1, en-1 { 121 siblings[st], siblings[en] = siblings[en], siblings[st] 122 } 123 124 return siblings, nil 125 } 126 127 // getRollupExitProof returns the merkle proof for the zkevm leaf. 128 func (s *bridgeService) getRollupExitProof(rollupIndex uint, root common.Hash, dbTx pgx.Tx) ([][bridgectrl.KeyLen]byte, common.Hash, error) { 129 ctx := context.Background() 130 131 // Get leaves given the root 132 leaves, err := s.storage.GetRollupExitLeavesByRoot(ctx, root, dbTx) 133 if err != nil { 134 return nil, common.Hash{}, err 135 } 136 // Compute Siblings 137 var ls [][bridgectrl.KeyLen]byte 138 for _, l := range leaves { 139 var aux [bridgectrl.KeyLen]byte 140 copy(aux[:], l.Leaf.Bytes()) 141 ls = append(ls, aux) 142 } 143 siblings, r, err := bridgectrl.ComputeSiblings(rollupIndex, ls, s.height) 144 if err != nil { 145 return nil, common.Hash{}, err 146 } else if root != r { 147 return nil, common.Hash{}, fmt.Errorf("error checking calculated root: %s, %s", root.String(), r.String()) 148 } 149 return siblings, ls[rollupIndex], nil 150 } 151 152 // GetClaimProof returns the merkle proof to claim the given deposit. 153 func (s *bridgeService) GetClaimProof(depositCnt, networkID uint, dbTx pgx.Tx) (*etherman.GlobalExitRoot, [][bridgectrl.KeyLen]byte, [][bridgectrl.KeyLen]byte, error) { 154 ctx := context.Background() 155 156 if dbTx == nil { // if the call comes from the rest API 157 deposit, err := s.storage.GetDeposit(ctx, depositCnt, networkID, nil) 158 if err != nil { 159 return nil, nil, nil, err 160 } 161 162 if !deposit.ReadyForClaim { 163 return nil, nil, nil, gerror.ErrDepositNotSynced 164 } 165 } 166 167 tID, err := s.getNetworkID(networkID) 168 if err != nil { 169 return nil, nil, nil, err 170 } 171 172 globalExitRoot, err := s.storage.GetLatestExitRoot(ctx, tID != 0, dbTx) 173 if err != nil { 174 return nil, nil, nil, err 175 } 176 177 var ( 178 merkleProof [][bridgectrl.KeyLen]byte 179 rollupMerkleProof [][bridgectrl.KeyLen]byte 180 rollupLeaf common.Hash 181 ) 182 if networkID == 0 { // Mainnet 183 merkleProof, err = s.getProof(depositCnt, globalExitRoot.ExitRoots[tID], dbTx) 184 if err != nil { 185 log.Error("error getting merkleProof. Error: ", err) 186 return nil, nil, nil, fmt.Errorf("getting the proof failed, error: %v, network: %d", err, networkID) 187 } 188 rollupMerkleProof = emptyProof() 189 } else { // Rollup 190 rollupMerkleProof, rollupLeaf, err = s.getRollupExitProof(s.rollupID-1, globalExitRoot.ExitRoots[tID], dbTx) 191 if err != nil { 192 log.Error("error getting rollupProof. Error: ", err) 193 return nil, nil, nil, fmt.Errorf("getting the rollup proof failed, error: %v, network: %d", err, networkID) 194 } 195 merkleProof, err = s.getProof(depositCnt, rollupLeaf, dbTx) 196 if err != nil { 197 log.Error("error getting merkleProof. Error: ", err) 198 return nil, nil, nil, fmt.Errorf("getting the proof failed, error: %v, network: %d", err, networkID) 199 } 200 } 201 202 return globalExitRoot, merkleProof, rollupMerkleProof, nil 203 } 204 205 func emptyProof() [][bridgectrl.KeyLen]byte { 206 var proof [][bridgectrl.KeyLen]byte 207 for i := 0; i < 32; i++ { 208 proof = append(proof, common.Hash{}) 209 } 210 return proof 211 } 212 213 // GetDepositStatus returns deposit with ready_for_claim status. 214 func (s *bridgeService) GetDepositStatus(ctx context.Context, depositCount uint, destNetworkID uint) (string, error) { 215 var ( 216 claimTxHash string 217 ) 218 // Get the claim tx hash 219 claim, err := s.storage.GetClaim(ctx, depositCount, destNetworkID, nil) 220 if err != nil { 221 if err != gerror.ErrStorageNotFound { 222 return "", err 223 } 224 } else { 225 claimTxHash = claim.TxHash.String() 226 } 227 return claimTxHash, nil 228 } 229 230 // CheckAPI returns api version. 231 // Bridge rest API endpoint 232 func (s *bridgeService) CheckAPI(ctx context.Context, req *pb.CheckAPIRequest) (*pb.CheckAPIResponse, error) { 233 return &pb.CheckAPIResponse{ 234 Api: s.version, 235 }, nil 236 } 237 238 // GetBridges returns bridges for the destination address both in L1 and L2. 239 // Bridge rest API endpoint 240 func (s *bridgeService) GetBridges(ctx context.Context, req *pb.GetBridgesRequest) (*pb.GetBridgesResponse, error) { 241 limit := req.Limit 242 if limit == 0 { 243 limit = s.defaultPageLimit 244 } 245 if limit > s.maxPageLimit { 246 limit = s.maxPageLimit 247 } 248 totalCount, err := s.storage.GetDepositCount(ctx, req.DestAddr, nil) 249 if err != nil { 250 return nil, err 251 } 252 deposits, err := s.storage.GetDeposits(ctx, req.DestAddr, uint(limit), uint(req.Offset), nil) 253 if err != nil { 254 return nil, err 255 } 256 257 var pbDeposits []*pb.Deposit 258 for _, deposit := range deposits { 259 claimTxHash, err := s.GetDepositStatus(ctx, deposit.DepositCount, deposit.DestinationNetwork) 260 if err != nil { 261 return nil, err 262 } 263 mainnetFlag := deposit.NetworkID == 0 264 rollupIndex := s.rollupID - 1 265 localExitRootIndex := deposit.DepositCount 266 pbDeposits = append( 267 pbDeposits, &pb.Deposit{ 268 LeafType: uint32(deposit.LeafType), 269 OrigNet: uint32(deposit.OriginalNetwork), 270 OrigAddr: deposit.OriginalAddress.Hex(), 271 Amount: deposit.Amount.String(), 272 DestNet: uint32(deposit.DestinationNetwork), 273 DestAddr: deposit.DestinationAddress.Hex(), 274 BlockNum: deposit.BlockNumber, 275 DepositCnt: uint64(deposit.DepositCount), 276 NetworkId: uint32(deposit.NetworkID), 277 TxHash: deposit.TxHash.String(), 278 ClaimTxHash: claimTxHash, 279 Metadata: "0x" + hex.EncodeToString(deposit.Metadata), 280 ReadyForClaim: deposit.ReadyForClaim, 281 GlobalIndex: etherman.GenerateGlobalIndex(mainnetFlag, rollupIndex, localExitRootIndex).String(), 282 }, 283 ) 284 } 285 286 return &pb.GetBridgesResponse{ 287 Deposits: pbDeposits, 288 TotalCnt: totalCount, 289 }, nil 290 } 291 292 // GetClaims returns claims for the specific smart contract address both in L1 and L2. 293 // Bridge rest API endpoint 294 func (s *bridgeService) GetClaims(ctx context.Context, req *pb.GetClaimsRequest) (*pb.GetClaimsResponse, error) { 295 limit := req.Limit 296 if limit == 0 { 297 limit = s.defaultPageLimit 298 } 299 if limit > s.maxPageLimit { 300 limit = s.maxPageLimit 301 } 302 totalCount, err := s.storage.GetClaimCount(ctx, req.DestAddr, nil) 303 if err != nil { 304 return nil, err 305 } 306 claims, err := s.storage.GetClaims(ctx, req.DestAddr, uint(limit), uint(req.Offset), nil) //nolint:gomnd 307 if err != nil { 308 return nil, err 309 } 310 311 var pbClaims []*pb.Claim 312 for _, claim := range claims { 313 pbClaims = append(pbClaims, &pb.Claim{ 314 Index: uint64(claim.Index), 315 OrigNet: uint32(claim.OriginalNetwork), 316 OrigAddr: claim.OriginalAddress.Hex(), 317 Amount: claim.Amount.String(), 318 NetworkId: uint32(claim.NetworkID), 319 DestAddr: claim.DestinationAddress.Hex(), 320 BlockNum: claim.BlockNumber, 321 TxHash: claim.TxHash.String(), 322 RollupIndex: claim.RollupIndex, 323 MainnetFlag: claim.MainnetFlag, 324 }) 325 } 326 327 return &pb.GetClaimsResponse{ 328 Claims: pbClaims, 329 TotalCnt: totalCount, 330 }, nil 331 } 332 333 // GetProof returns the merkle proof for the given deposit. 334 // Bridge rest API endpoint 335 func (s *bridgeService) GetProof(ctx context.Context, req *pb.GetProofRequest) (*pb.GetProofResponse, error) { 336 globalExitRoot, merkleProof, rollupMerkleProof, err := s.GetClaimProof(uint(req.DepositCnt), uint(req.NetId), nil) 337 if err != nil { 338 return nil, err 339 } 340 var ( 341 proof []string 342 rollupProof []string 343 ) 344 if len(proof) != len(rollupProof) { 345 return nil, fmt.Errorf("proofs have different lengths. MerkleProof: %d. RollupMerkleProof: %d", len(merkleProof), len(rollupMerkleProof)) 346 } 347 for i := 0; i < len(merkleProof); i++ { 348 proof = append(proof, "0x"+hex.EncodeToString(merkleProof[i][:])) 349 rollupProof = append(rollupProof, "0x"+hex.EncodeToString(rollupMerkleProof[i][:])) 350 } 351 352 return &pb.GetProofResponse{ 353 Proof: &pb.Proof{ 354 RollupMerkleProof: rollupProof, 355 MerkleProof: proof, 356 MainExitRoot: globalExitRoot.ExitRoots[0].Hex(), 357 RollupExitRoot: globalExitRoot.ExitRoots[1].Hex(), 358 }, 359 }, nil 360 } 361 362 // GetBridge returns the bridge with status whether it is able to send a claim transaction or not. 363 // Bridge rest API endpoint 364 func (s *bridgeService) GetBridge(ctx context.Context, req *pb.GetBridgeRequest) (*pb.GetBridgeResponse, error) { 365 deposit, err := s.storage.GetDeposit(ctx, uint(req.DepositCnt), uint(req.NetId), nil) 366 if err != nil { 367 return nil, err 368 } 369 370 claimTxHash, err := s.GetDepositStatus(ctx, uint(req.DepositCnt), deposit.DestinationNetwork) 371 if err != nil { 372 return nil, err 373 } 374 375 return &pb.GetBridgeResponse{ 376 Deposit: &pb.Deposit{ 377 LeafType: uint32(deposit.LeafType), 378 OrigNet: uint32(deposit.OriginalNetwork), 379 OrigAddr: deposit.OriginalAddress.Hex(), 380 Amount: deposit.Amount.String(), 381 DestNet: uint32(deposit.DestinationNetwork), 382 DestAddr: deposit.DestinationAddress.Hex(), 383 BlockNum: deposit.BlockNumber, 384 DepositCnt: uint64(deposit.DepositCount), 385 NetworkId: uint32(deposit.NetworkID), 386 TxHash: deposit.TxHash.String(), 387 ClaimTxHash: claimTxHash, 388 Metadata: "0x" + hex.EncodeToString(deposit.Metadata), 389 ReadyForClaim: deposit.ReadyForClaim, 390 }, 391 }, nil 392 } 393 394 // GetTokenWrapped returns the token wrapped created for a specific network 395 // Bridge rest API endpoint 396 func (s *bridgeService) GetTokenWrapped(ctx context.Context, req *pb.GetTokenWrappedRequest) (*pb.GetTokenWrappedResponse, error) { 397 tokenWrapped, err := s.storage.GetTokenWrapped(ctx, uint(req.OrigNet), common.HexToAddress(req.OrigTokenAddr), nil) 398 if err != nil { 399 return nil, err 400 } 401 return &pb.GetTokenWrappedResponse{ 402 Tokenwrapped: &pb.TokenWrapped{ 403 OrigNet: uint32(tokenWrapped.OriginalNetwork), 404 OriginalTokenAddr: tokenWrapped.OriginalTokenAddress.Hex(), 405 WrappedTokenAddr: tokenWrapped.WrappedTokenAddress.Hex(), 406 NetworkId: uint32(tokenWrapped.NetworkID), 407 Name: tokenWrapped.Name, 408 Symbol: tokenWrapped.Symbol, 409 Decimals: uint32(tokenWrapped.Decimals), 410 }, 411 }, nil 412 }