guardianset.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. package common
  2. import (
  3. "fmt"
  4. gossipv1 "github.com/certusone/wormhole/node/pkg/proto/gossip/v1"
  5. "github.com/ethereum/go-ethereum/common"
  6. "github.com/libp2p/go-libp2p-core/peer"
  7. "sync"
  8. "time"
  9. )
  10. // MaxGuardianCount specifies the maximum number of guardians supported by on-chain contracts.
  11. //
  12. // Matching constants:
  13. // - MAX_LEN_GUARDIAN_KEYS in Solana contract (limited by transaction size - 19 is the maximum amount possible)
  14. //
  15. // The Eth and Terra contracts do not specify a maximum number and support more than that,
  16. // but presumably, chain-specific transaction size limits will apply at some point (untested).
  17. const MaxGuardianCount = 19
  18. // MaxNodesPerGuardian specifies the maximum amount of nodes per guardian key that we'll accept
  19. // whenever we maintain any per-guardian, per-node state.
  20. //
  21. // There currently isn't any state clean up, so the value is on the high side to prevent
  22. // accidentally reaching the limit due to operational mistakes.
  23. const MaxNodesPerGuardian = 15
  24. // MaxStateAge specified the maximum age of state entries in seconds. Expired entries are purged
  25. // from the state by Cleanup().
  26. const MaxStateAge = 1 * time.Minute
  27. type GuardianSet struct {
  28. // Guardian's public key hashes truncated by the ETH standard hashing mechanism (20 bytes).
  29. Keys []common.Address
  30. // On-chain set index
  31. Index uint32
  32. }
  33. func (g *GuardianSet) KeysAsHexStrings() []string {
  34. r := make([]string, len(g.Keys))
  35. for n, k := range g.Keys {
  36. r[n] = k.Hex()
  37. }
  38. return r
  39. }
  40. // KeyIndex returns a given address index from the guardian set. Returns (-1, false)
  41. // if the address wasn't found and (addr, true) otherwise.
  42. func (g *GuardianSet) KeyIndex(addr common.Address) (int, bool) {
  43. for n, k := range g.Keys {
  44. if k == addr {
  45. return n, true
  46. }
  47. }
  48. return -1, false
  49. }
  50. type GuardianSetState struct {
  51. mu sync.Mutex
  52. current *GuardianSet
  53. // Last heartbeat message received per guardian per p2p node. Maintained
  54. // across guardian set updates - these values don't change.
  55. lastHeartbeats map[common.Address]map[peer.ID]*gossipv1.Heartbeat
  56. }
  57. func NewGuardianSetState() *GuardianSetState {
  58. return &GuardianSetState{
  59. lastHeartbeats: map[common.Address]map[peer.ID]*gossipv1.Heartbeat{},
  60. }
  61. }
  62. func (st *GuardianSetState) Set(set *GuardianSet) {
  63. st.mu.Lock()
  64. defer st.mu.Unlock()
  65. st.current = set
  66. }
  67. func (st *GuardianSetState) Get() *GuardianSet {
  68. st.mu.Lock()
  69. defer st.mu.Unlock()
  70. return st.current
  71. }
  72. // LastHeartbeat returns the most recent heartbeat message received for
  73. // a given guardian node, or nil if none have been received.
  74. func (st *GuardianSetState) LastHeartbeat(addr common.Address) map[peer.ID]*gossipv1.Heartbeat {
  75. st.mu.Lock()
  76. defer st.mu.Unlock()
  77. ret := make(map[peer.ID]*gossipv1.Heartbeat)
  78. for k, v := range st.lastHeartbeats[addr] {
  79. ret[k] = v
  80. }
  81. return ret
  82. }
  83. // SetHeartbeat stores a verified heartbeat observed by a given guardian.
  84. func (st *GuardianSetState) SetHeartbeat(addr common.Address, peerId peer.ID, hb *gossipv1.Heartbeat) error {
  85. st.mu.Lock()
  86. defer st.mu.Unlock()
  87. v, ok := st.lastHeartbeats[addr]
  88. if !ok {
  89. v = make(map[peer.ID]*gossipv1.Heartbeat)
  90. st.lastHeartbeats[addr] = v
  91. } else {
  92. if len(v) >= MaxNodesPerGuardian {
  93. // TODO: age out old entries?
  94. return fmt.Errorf("too many nodes (%d) for guardian, cannot store entry", len(v))
  95. }
  96. }
  97. v[peerId] = hb
  98. return nil
  99. }
  100. // GetAll returns all stored heartbeats.
  101. func (st *GuardianSetState) GetAll() map[common.Address]map[peer.ID]*gossipv1.Heartbeat {
  102. st.mu.Lock()
  103. defer st.mu.Unlock()
  104. ret := make(map[common.Address]map[peer.ID]*gossipv1.Heartbeat)
  105. // Deep copy
  106. for addr, v := range st.lastHeartbeats {
  107. ret[addr] = make(map[peer.ID]*gossipv1.Heartbeat)
  108. for peerId, hb := range v {
  109. ret[addr][peerId] = hb
  110. }
  111. }
  112. return ret
  113. }
  114. // Cleanup removes expired entries from the state.
  115. func (st *GuardianSetState) Cleanup() {
  116. st.mu.Lock()
  117. defer st.mu.Unlock()
  118. for addr, v := range st.lastHeartbeats {
  119. for peerId, hb := range v {
  120. ts := time.Unix(hb.Timestamp, 0)
  121. if time.Since(ts) > MaxStateAge {
  122. delete(st.lastHeartbeats[addr], peerId)
  123. }
  124. }
  125. }
  126. }