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  }