status-im/status-go

View on GitHub
services/wallet/blockchainstate/blockchainstate.go

Summary

Maintainability
A
0 mins
Test Coverage
B
88%
package blockchainstate

import (
    "context"
    "sync"
    "time"

    "github.com/status-im/status-go/services/wallet/common"
)

type LatestBlockData struct {
    blockNumber   uint64
    timestamp     time.Time
    blockDuration time.Duration
}

type BlockChainState struct {
    blkMu              sync.RWMutex
    latestBlockNumbers map[uint64]LatestBlockData
    sinceFn            func(time.Time) time.Duration
}

func NewBlockChainState() *BlockChainState {
    return &BlockChainState{
        blkMu:              sync.RWMutex{},
        latestBlockNumbers: make(map[uint64]LatestBlockData),
        sinceFn:            time.Since,
    }
}

func (s *BlockChainState) GetEstimatedLatestBlockNumber(ctx context.Context, chainID uint64) (uint64, error) {
    blockNumber, _ := s.estimateLatestBlockNumber(chainID)
    return blockNumber, nil
}

func (s *BlockChainState) SetLastBlockNumber(chainID uint64, blockNumber uint64) {
    blockDuration, found := common.AverageBlockDurationForChain[common.ChainID(chainID)]
    if !found {
        blockDuration = common.AverageBlockDurationForChain[common.ChainID(common.UnknownChainID)]
    }
    s.setLatestBlockDataForChain(chainID, LatestBlockData{
        blockNumber:   blockNumber,
        timestamp:     time.Now(),
        blockDuration: blockDuration,
    })
}

func (s *BlockChainState) setLatestBlockDataForChain(chainID uint64, latestBlockData LatestBlockData) {
    s.blkMu.Lock()
    defer s.blkMu.Unlock()
    s.latestBlockNumbers[chainID] = latestBlockData
}

func (s *BlockChainState) estimateLatestBlockNumber(chainID uint64) (uint64, bool) {
    s.blkMu.RLock()
    defer s.blkMu.RUnlock()
    blockData, ok := s.latestBlockNumbers[chainID]
    if !ok {
        return 0, false
    }
    timeDiff := s.sinceFn(blockData.timestamp)
    return blockData.blockNumber + uint64((timeDiff / blockData.blockDuration)), true
}