code.vegaprotocol.io/vega@v0.79.0/core/validators/erc20multisig/topology_test.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package erc20multisig_test 17 18 import ( 19 "context" 20 "testing" 21 "time" 22 23 bmocks "code.vegaprotocol.io/vega/core/broker/mocks" 24 "code.vegaprotocol.io/vega/core/types" 25 "code.vegaprotocol.io/vega/core/validators" 26 "code.vegaprotocol.io/vega/core/validators/erc20multisig" 27 "code.vegaprotocol.io/vega/core/validators/erc20multisig/mocks" 28 "code.vegaprotocol.io/vega/logging" 29 30 "github.com/golang/mock/gomock" 31 "github.com/stretchr/testify/assert" 32 ) 33 34 type testTopology struct { 35 *erc20multisig.Topology 36 37 ctrl *gomock.Controller 38 broker *bmocks.MockBroker 39 witness *mocks.MockWitness 40 ocv *mocks.MockMultiSigOnChainVerifier 41 ethEventSource *mocks.MockEthereumEventSource 42 } 43 44 func getTestTopology(t *testing.T) *testTopology { 45 t.Helper() 46 ctrl := gomock.NewController(t) 47 witness := mocks.NewMockWitness(ctrl) 48 ocv := mocks.NewMockMultiSigOnChainVerifier(ctrl) 49 broker := bmocks.NewMockBroker(ctrl) 50 ethEventSource := mocks.NewMockEthereumEventSource(ctrl) 51 52 top := &testTopology{ 53 Topology: erc20multisig.NewTopology( 54 erc20multisig.NewDefaultConfig(), 55 logging.NewTestLogger(), 56 witness, 57 ocv, 58 broker, 59 "primary", 60 ), 61 ctrl: ctrl, 62 broker: broker, 63 witness: witness, 64 ocv: ocv, 65 ethEventSource: ethEventSource, 66 } 67 68 top.SetEthereumEventSource(ethEventSource) 69 return top 70 } 71 72 func TestERC20Topology(t *testing.T) { 73 t.Run("valid threshold set event, threshold updated", testValidThresholdEvent) 74 t.Run("invalid threshold set event, threshold not updated", testInvalidThresholdEvent) 75 t.Run("valid signer event, signers set updated", testValidSignerEvents) 76 t.Run("invalid signer event, signers set not updated", testInvalidSignerEvents) 77 t.Run("error on duplicate signer event", testErrorOnDuplicteSignerEvent) 78 t.Run("error on duplicate threshold set event", testErrorOnDuplicteThesholdSetEvent) 79 } 80 81 func testValidThresholdEvent(t *testing.T) { 82 top := getTestTopology(t) 83 defer top.ctrl.Finish() 84 85 top.OnTick(context.Background(), time.Unix(10, 0)) 86 87 // first assert we have no signers 88 assert.Equal(t, top.GetThreshold(), uint32(0)) 89 90 event := types.SignerThresholdSetEvent{ 91 Threshold: 666, 92 BlockNumber: 10, 93 LogIndex: 11, 94 TxHash: "0xacbde", 95 ID: "someid", 96 Nonce: "123", 97 BlockTime: 123456789, 98 } 99 100 var cb func(interface{}, bool) 101 var res validators.Resource 102 top.witness.EXPECT().StartCheck(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).DoAndReturn(func(r validators.Resource, f func(interface{}, bool), _ time.Time) error { 103 cb = f 104 res = r 105 return nil 106 }) 107 108 assert.NoError(t, top.ProcessThresholdEvent(&event)) 109 110 // now we can call the callback 111 cb(res, true) 112 113 // now we can update the time 114 top.broker.EXPECT().Send(gomock.Any()).Times(1) 115 top.OnTick(context.Background(), time.Unix(11, 0)) 116 assert.Equal(t, top.GetThreshold(), uint32(666)) 117 118 // now update it again at a later time 119 event2 := types.SignerThresholdSetEvent{ 120 Threshold: 900, 121 BlockNumber: 11, 122 LogIndex: 7, 123 TxHash: "0xedcba", 124 ID: "someid2", 125 Nonce: "321", 126 BlockTime: 123456790, 127 } 128 129 top.witness.EXPECT().StartCheck(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).DoAndReturn(func(r validators.Resource, f func(interface{}, bool), _ time.Time) error { 130 cb = f 131 res = r 132 return nil 133 }) 134 135 assert.NoError(t, top.ProcessThresholdEvent(&event2)) 136 137 // now we can call the callback 138 cb(res, true) 139 140 // now we can update the time 141 top.broker.EXPECT().Send(gomock.Any()).Times(1) 142 top.OnTick(context.Background(), time.Unix(11, 0)) 143 assert.Equal(t, top.GetThreshold(), uint32(900)) 144 } 145 146 func testInvalidThresholdEvent(t *testing.T) { 147 top := getTestTopology(t) 148 defer top.ctrl.Finish() 149 150 top.OnTick(context.Background(), time.Unix(10, 0)) 151 152 // first assert we have no signers 153 assert.Equal(t, top.GetThreshold(), uint32(0)) 154 155 event := types.SignerThresholdSetEvent{ 156 Threshold: 666, 157 BlockNumber: 10, 158 LogIndex: 11, 159 TxHash: "0xacbde", 160 ID: "someid", 161 Nonce: "123", 162 BlockTime: 123456789, 163 } 164 165 var cb func(interface{}, bool) 166 var res validators.Resource 167 top.witness.EXPECT().StartCheck(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).DoAndReturn(func(r validators.Resource, f func(interface{}, bool), _ time.Time) error { 168 cb = f 169 res = r 170 return nil 171 }) 172 173 assert.NoError(t, top.ProcessThresholdEvent(&event)) 174 175 // now we can call the callback 176 cb(res, false) 177 178 // now we can update the time 179 top.OnTick(context.Background(), time.Unix(11, 0)) 180 assert.Equal(t, top.GetThreshold(), uint32(0)) 181 } 182 183 func testInvalidSignerEvents(t *testing.T) { 184 top := getTestTopology(t) 185 defer top.ctrl.Finish() 186 187 top.OnTick(context.Background(), time.Unix(10, 0)) 188 189 // first assert we have no signers 190 assert.Len(t, top.GetSigners(), 0) 191 192 event := types.SignerEvent{ 193 BlockNumber: 10, 194 LogIndex: 11, 195 TxHash: "0xacbde", 196 ID: "someid", 197 Address: "0x123456", 198 Nonce: "123", 199 BlockTime: 123456789, 200 Kind: types.SignerEventKindAdded, 201 } 202 203 var cb func(interface{}, bool) 204 var res validators.Resource 205 top.witness.EXPECT().StartCheck(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).DoAndReturn(func(r validators.Resource, f func(interface{}, bool), _ time.Time) error { 206 cb = f 207 res = r 208 return nil 209 }) 210 211 assert.NoError(t, top.ProcessSignerEvent(&event)) 212 213 // now we can call the callback 214 cb(res, false) 215 216 // now we can update the time 217 top.OnTick(context.Background(), time.Unix(11, 0)) 218 assert.Len(t, top.GetSigners(), 0) 219 } 220 221 func testValidSignerEvents(t *testing.T) { 222 top := getTestTopology(t) 223 defer top.ctrl.Finish() 224 225 top.ocv.EXPECT().GetMultiSigAddress().AnyTimes() 226 top.ethEventSource.EXPECT().UpdateContractBlock(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() 227 top.OnTick(context.Background(), time.Unix(10, 0)) 228 229 // first assert we have no signers 230 assert.Len(t, top.GetSigners(), 0) 231 232 event := types.SignerEvent{ 233 BlockNumber: 10, 234 LogIndex: 11, 235 TxHash: "0xacbde", 236 ID: "someid", 237 Address: "0x123456", 238 Nonce: "123", 239 BlockTime: 123456789, 240 Kind: types.SignerEventKindAdded, 241 } 242 243 var cb func(interface{}, bool) 244 var res validators.Resource 245 top.witness.EXPECT().StartCheck(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).DoAndReturn(func(r validators.Resource, f func(interface{}, bool), _ time.Time) error { 246 cb = f 247 res = r 248 return nil 249 }) 250 251 assert.NoError(t, top.ProcessSignerEvent(&event)) 252 253 // now we can call the callback 254 cb(res, true) 255 256 // now we can update the time 257 top.broker.EXPECT().Send(gomock.Any()).Times(1) 258 top.OnTick(context.Background(), time.Unix(11, 0)) 259 260 t.Run("ensure the signer list is updated", func(t *testing.T) { 261 signers := top.GetSigners() 262 assert.Len(t, signers, 1) 263 assert.Equal(t, "0x123456", signers[0]) 264 }) 265 266 t.Run("check if our party IsSigner", func(t *testing.T) { 267 assert.True(t, top.IsSigner("0x123456")) 268 }) 269 270 t.Run("check excess signers", func(t *testing.T) { 271 okAddresses := []string{"0x123456"} 272 koAddresses := []string{} 273 274 assert.True(t, top.ExcessSigners(koAddresses)) 275 assert.False(t, top.ExcessSigners(okAddresses)) 276 }) 277 278 // now we try to delete it yeay! 279 event2 := types.SignerEvent{ 280 BlockNumber: 11, 281 LogIndex: 4, 282 TxHash: "0xedcba", 283 ID: "someid2", 284 Address: "0x123456", 285 Nonce: "321", 286 BlockTime: 123456790, 287 Kind: types.SignerEventKindRemoved, 288 } 289 290 top.witness.EXPECT().StartCheck(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).DoAndReturn(func(r validators.Resource, f func(interface{}, bool), _ time.Time) error { 291 cb = f 292 res = r 293 return nil 294 }) 295 296 assert.NoError(t, top.ProcessSignerEvent(&event2)) 297 298 // now we can call the callback again! 299 cb(res, true) 300 301 // now we can update the time 302 top.broker.EXPECT().Send(gomock.Any()).Times(1) 303 top.OnTick(context.Background(), time.Unix(12, 0)) 304 305 t.Run("ensure all signers have been removed", func(t *testing.T) { 306 signers := top.GetSigners() 307 assert.Len(t, signers, 0) 308 }) 309 } 310 311 func testErrorOnDuplicteSignerEvent(t *testing.T) { 312 top := getTestTopology(t) 313 defer top.ctrl.Finish() 314 315 event := types.SignerEvent{ 316 BlockNumber: 10, 317 LogIndex: 11, 318 TxHash: "0xacbde", 319 ID: "someid", 320 Address: "0x123456", 321 Nonce: "123", 322 BlockTime: 123456789, 323 Kind: types.SignerEventKindAdded, 324 } 325 326 top.witness.EXPECT().StartCheck(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) 327 assert.NoError(t, top.ProcessSignerEvent(&event)) 328 329 assert.EqualError(t, 330 top.ProcessSignerEvent(&event), 331 erc20multisig.ErrDuplicatedSignerEvent.Error(), 332 ) 333 } 334 335 func testErrorOnDuplicteThesholdSetEvent(t *testing.T) { 336 top := getTestTopology(t) 337 defer top.ctrl.Finish() 338 339 event := types.SignerThresholdSetEvent{ 340 BlockNumber: 10, 341 LogIndex: 11, 342 TxHash: "0xacbde", 343 ID: "someid", 344 Threshold: 666, 345 Nonce: "123", 346 BlockTime: 123456789, 347 } 348 349 top.witness.EXPECT().StartCheck(gomock.Any(), gomock.Any(), gomock.Any()).Times(1).Return(nil) 350 assert.NoError(t, top.ProcessThresholdEvent(&event)) 351 352 assert.EqualError(t, 353 top.ProcessThresholdEvent(&event), 354 erc20multisig.ErrDuplicatedThresholdEvent.Error(), 355 ) 356 }