guardianset.go 3.5 KB

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