code.vegaprotocol.io/vega@v0.79.0/datanode/sqlstore/notary_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 sqlstore_test 17 18 import ( 19 "context" 20 "fmt" 21 "testing" 22 23 "code.vegaprotocol.io/vega/datanode/entities" 24 "code.vegaprotocol.io/vega/datanode/sqlstore" 25 v1 "code.vegaprotocol.io/vega/protos/vega/commands/v1" 26 27 "github.com/stretchr/testify/assert" 28 "github.com/stretchr/testify/require" 29 ) 30 31 func TestNotary(t *testing.T) { 32 t.Run("Adding a single signature", testAddSignatures) 33 t.Run("Adding multiple signatures for multiple resources", testAddMultipleSignatures) 34 t.Run("Getting a non-existing resource signatures", testNoResource) 35 t.Run("GetByTxHash", testSignatureGetByTx) 36 } 37 38 func setupNotaryStoreTests(t *testing.T) (*sqlstore.Notary, *sqlstore.Blocks, sqlstore.Connection) { 39 t.Helper() 40 ns := sqlstore.NewNotary(connectionSource) 41 bs := sqlstore.NewBlocks(connectionSource) 42 return ns, bs, connectionSource 43 } 44 45 func testAddSignatures(t *testing.T) { 46 ctx := tempTransaction(t) 47 48 ws, bs, conn := setupNotaryStoreTests(t) 49 50 var rowCount int 51 52 err := conn.QueryRow(ctx, `select count(*) from withdrawals`).Scan(&rowCount) 53 require.NoError(t, err) 54 assert.Equal(t, 0, rowCount) 55 56 ns := getTestNodeSignature(t, ctx, bs, "deadbeef", "iamsig") 57 err = ws.Add(ctx, ns) 58 require.NoError(t, err) 59 60 err = conn.QueryRow(ctx, `select count(*) from node_signatures`).Scan(&rowCount) 61 assert.NoError(t, err) 62 assert.Equal(t, 1, rowCount) 63 } 64 65 func testAddMultipleSignatures(t *testing.T) { 66 ctx := tempTransaction(t) 67 68 ws, bs, _ := setupNotaryStoreTests(t) 69 70 nodeSig1 := getTestNodeSignature(t, ctx, bs, "deadbeef", "iamsig") 71 nodeSig2 := getTestNodeSignature(t, ctx, bs, "deadbeef", "iamsig") // this will have a different sig 72 nodeSig3 := getTestNodeSignature(t, ctx, bs, "deadbeef", "iamsig") // this will be a dupe of ns2 73 nodeSig4 := getTestNodeSignature(t, ctx, bs, "deadbeefdeadbeef", "iamsig") // this will have a different sig and id 74 75 nodeSig2.Sig = []byte("iamdifferentsig") 76 nodeSig4.Sig = []byte("iamdifferentsigagain") 77 78 err := ws.Add(ctx, nodeSig1) 79 require.NoError(t, err) 80 81 err = ws.Add(ctx, nodeSig2) 82 require.NoError(t, err) 83 84 err = ws.Add(ctx, nodeSig3) 85 require.NoError(t, err) 86 87 err = ws.Add(ctx, nodeSig4) 88 require.NoError(t, err) 89 90 res, _, err := ws.GetByResourceID(ctx, "deadbeef", entities.CursorPagination{}) 91 require.NoError(t, err) 92 require.Len(t, res, 2) 93 94 res, _, err = ws.GetByResourceID(ctx, "deadbeefdeadbeef", entities.CursorPagination{}) 95 require.NoError(t, err) 96 require.Len(t, res, 1) 97 } 98 99 func getTestNodeSignature(t *testing.T, ctx context.Context, bs *sqlstore.Blocks, id string, sig string) *entities.NodeSignature { 100 t.Helper() 101 block := addTestBlock(t, ctx, bs) 102 ns, err := entities.NodeSignatureFromProto( 103 &v1.NodeSignature{ 104 Id: id, 105 Sig: []byte(sig), 106 Kind: v1.NodeSignatureKind_NODE_SIGNATURE_KIND_ASSET_WITHDRAWAL, 107 }, 108 generateTxHash(), 109 block.VegaTime, 110 ) 111 require.NoError(t, err) 112 return ns 113 } 114 115 func testNoResource(t *testing.T) { 116 ctx := tempTransaction(t) 117 118 ws, _, _ := setupNotaryStoreTests(t) 119 120 res, _, err := ws.GetByResourceID(ctx, "deadbeefdeadbeef", entities.CursorPagination{}) 121 require.NoError(t, err) 122 require.Len(t, res, 0) 123 } 124 125 func testSignatureGetByTx(t *testing.T) { 126 ctx := tempTransaction(t) 127 128 ns, bs, _ := setupNotaryStoreTests(t) 129 130 signature := getTestNodeSignature(t, ctx, bs, "deadbeef", "iamsig") 131 require.NoError(t, ns.Add(ctx, signature)) 132 133 signature2 := getTestNodeSignature(t, ctx, bs, "deadbaef", "iamsig") 134 require.NoError(t, ns.Add(ctx, signature2)) 135 136 signatures, err := ns.GetByTxHash(ctx, signature.TxHash) 137 require.NoError(t, err) 138 require.Len(t, signatures, 1) 139 require.Equal(t, *signature, signatures[0]) 140 141 signatures, err = ns.GetByTxHash(ctx, signature2.TxHash) 142 require.NoError(t, err) 143 require.Len(t, signatures, 1) 144 require.Equal(t, *signature2, signatures[0]) 145 } 146 147 func TestNodeSignaturePagination(t *testing.T) { 148 t.Run("should return all node signatures if no pagination is specified", testNodeSignaturePaginationNoPagination) 149 t.Run("should return first page of node signatures if first pagination is specified", testNodeSignaturePaginationFirst) 150 t.Run("should return last page of node signatures if last pagination is specified", testNodeSignaturePaginationLast) 151 t.Run("should return specified page of node signatures if first and after pagination is specified", testNodeSignaturePaginationFirstAfter) 152 t.Run("should return specified page of node signatures if last and before pagination is specified", testNodeSignaturePaginationLastBefore) 153 154 t.Run("should return all node signatures if no pagination is specified - newest first", testNodeSignaturePaginationNoPaginationNewestFirst) 155 t.Run("should return first page of node signatures if first pagination is specified - newest first", testNodeSignaturePaginationFirstNewestFirst) 156 t.Run("should return last page of node signatures if last pagination is specified - newest first", testNodeSignaturePaginationLastNewestFirst) 157 t.Run("should return specified page of node signatures if first and after pagination is specified - newest first", testNodeSignaturePaginationFirstAfterNewestFirst) 158 t.Run("should return specified page of node signatures if last and before pagination is specified - newest first", testNodeSignaturePaginationLastBeforeNewestFirst) 159 } 160 161 func testNodeSignaturePaginationNoPagination(t *testing.T) { 162 ctx := tempTransaction(t) 163 164 ns, sigs := setupNodeSignaturePaginationTest(t, ctx) 165 pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, false) 166 require.NoError(t, err) 167 168 got, pageInfo, err := ns.GetByResourceID(ctx, "deadbeef", pagination) 169 require.NoError(t, err) 170 want := sigs 171 assert.Equal(t, want, got) 172 assert.Equal(t, entities.PageInfo{ 173 HasNextPage: false, 174 HasPreviousPage: false, 175 StartCursor: want[0].Cursor().Encode(), 176 EndCursor: want[9].Cursor().Encode(), 177 }, pageInfo) 178 } 179 180 func testNodeSignaturePaginationFirst(t *testing.T) { 181 ctx := tempTransaction(t) 182 183 ns, sigs := setupNodeSignaturePaginationTest(t, ctx) 184 first := int32(3) 185 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, false) 186 require.NoError(t, err) 187 188 got, pageInfo, err := ns.GetByResourceID(ctx, "deadbeef", pagination) 189 require.NoError(t, err) 190 want := sigs[:3] 191 assert.Equal(t, want, got) 192 assert.Equal(t, entities.PageInfo{ 193 HasNextPage: true, 194 HasPreviousPage: false, 195 StartCursor: want[0].Cursor().Encode(), 196 EndCursor: want[2].Cursor().Encode(), 197 }, pageInfo) 198 } 199 200 func testNodeSignaturePaginationLast(t *testing.T) { 201 ctx := tempTransaction(t) 202 203 ns, sigs := setupNodeSignaturePaginationTest(t, ctx) 204 last := int32(3) 205 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, false) 206 require.NoError(t, err) 207 208 got, pageInfo, err := ns.GetByResourceID(ctx, "deadbeef", pagination) 209 require.NoError(t, err) 210 want := sigs[7:] 211 assert.Equal(t, want, got) 212 assert.Equal(t, entities.PageInfo{ 213 HasNextPage: false, 214 HasPreviousPage: true, 215 StartCursor: want[0].Cursor().Encode(), 216 EndCursor: want[2].Cursor().Encode(), 217 }, pageInfo) 218 } 219 220 func testNodeSignaturePaginationFirstAfter(t *testing.T) { 221 ctx := tempTransaction(t) 222 223 ns, sigs := setupNodeSignaturePaginationTest(t, ctx) 224 first := int32(3) 225 after := sigs[2].Cursor().Encode() 226 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, false) 227 require.NoError(t, err) 228 229 got, pageInfo, err := ns.GetByResourceID(ctx, "deadbeef", pagination) 230 require.NoError(t, err) 231 want := sigs[3:6] 232 assert.Equal(t, want, got) 233 assert.Equal(t, entities.PageInfo{ 234 HasNextPage: true, 235 HasPreviousPage: true, 236 StartCursor: want[0].Cursor().Encode(), 237 EndCursor: want[2].Cursor().Encode(), 238 }, pageInfo) 239 } 240 241 func testNodeSignaturePaginationLastBefore(t *testing.T) { 242 ctx := tempTransaction(t) 243 244 ns, sigs := setupNodeSignaturePaginationTest(t, ctx) 245 last := int32(3) 246 before := sigs[7].Cursor().Encode() 247 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, false) 248 require.NoError(t, err) 249 250 got, pageInfo, err := ns.GetByResourceID(ctx, "deadbeef", pagination) 251 require.NoError(t, err) 252 want := sigs[4:7] 253 assert.Equal(t, want, got) 254 assert.Equal(t, entities.PageInfo{ 255 HasNextPage: true, 256 HasPreviousPage: true, 257 StartCursor: want[0].Cursor().Encode(), 258 EndCursor: want[2].Cursor().Encode(), 259 }, pageInfo) 260 } 261 262 func testNodeSignaturePaginationNoPaginationNewestFirst(t *testing.T) { 263 ctx := tempTransaction(t) 264 265 ns, sigs := setupNodeSignaturePaginationTest(t, ctx) 266 pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, true) 267 require.NoError(t, err) 268 269 got, pageInfo, err := ns.GetByResourceID(ctx, "deadbeef", pagination) 270 require.NoError(t, err) 271 want := entities.ReverseSlice(sigs) 272 assert.Equal(t, want, got) 273 assert.Equal(t, entities.PageInfo{ 274 HasNextPage: false, 275 HasPreviousPage: false, 276 StartCursor: want[0].Cursor().Encode(), 277 EndCursor: want[9].Cursor().Encode(), 278 }, pageInfo) 279 } 280 281 func testNodeSignaturePaginationFirstNewestFirst(t *testing.T) { 282 ctx := tempTransaction(t) 283 284 ns, sigs := setupNodeSignaturePaginationTest(t, ctx) 285 first := int32(3) 286 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, true) 287 require.NoError(t, err) 288 289 got, pageInfo, err := ns.GetByResourceID(ctx, "deadbeef", pagination) 290 require.NoError(t, err) 291 want := entities.ReverseSlice(sigs)[:3] 292 assert.Equal(t, want, got) 293 assert.Equal(t, entities.PageInfo{ 294 HasNextPage: true, 295 HasPreviousPage: false, 296 StartCursor: want[0].Cursor().Encode(), 297 EndCursor: want[2].Cursor().Encode(), 298 }, pageInfo) 299 } 300 301 func testNodeSignaturePaginationLastNewestFirst(t *testing.T) { 302 ctx := tempTransaction(t) 303 304 ns, sigs := setupNodeSignaturePaginationTest(t, ctx) 305 last := int32(3) 306 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, true) 307 require.NoError(t, err) 308 309 got, pageInfo, err := ns.GetByResourceID(ctx, "deadbeef", pagination) 310 require.NoError(t, err) 311 want := entities.ReverseSlice(sigs)[7:] 312 assert.Equal(t, want, got) 313 assert.Equal(t, entities.PageInfo{ 314 HasNextPage: false, 315 HasPreviousPage: true, 316 StartCursor: want[0].Cursor().Encode(), 317 EndCursor: want[2].Cursor().Encode(), 318 }, pageInfo) 319 } 320 321 func testNodeSignaturePaginationFirstAfterNewestFirst(t *testing.T) { 322 ctx := tempTransaction(t) 323 324 ns, sigs := setupNodeSignaturePaginationTest(t, ctx) 325 first := int32(3) 326 after := sigs[7].Cursor().Encode() 327 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, true) 328 require.NoError(t, err) 329 330 got, pageInfo, err := ns.GetByResourceID(ctx, "deadbeef", pagination) 331 require.NoError(t, err) 332 want := entities.ReverseSlice(sigs)[3:6] 333 assert.Equal(t, want, got) 334 assert.Equal(t, entities.PageInfo{ 335 HasNextPage: true, 336 HasPreviousPage: true, 337 StartCursor: want[0].Cursor().Encode(), 338 EndCursor: want[2].Cursor().Encode(), 339 }, pageInfo) 340 } 341 342 func testNodeSignaturePaginationLastBeforeNewestFirst(t *testing.T) { 343 ctx := tempTransaction(t) 344 345 ns, sigs := setupNodeSignaturePaginationTest(t, ctx) 346 last := int32(3) 347 before := sigs[2].Cursor().Encode() 348 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, true) 349 require.NoError(t, err) 350 351 got, pageInfo, err := ns.GetByResourceID(ctx, "deadbeef", pagination) 352 require.NoError(t, err) 353 want := entities.ReverseSlice(sigs)[4:7] 354 assert.Equal(t, want, got) 355 assert.Equal(t, entities.PageInfo{ 356 HasNextPage: true, 357 HasPreviousPage: true, 358 StartCursor: want[0].Cursor().Encode(), 359 EndCursor: want[2].Cursor().Encode(), 360 }, pageInfo) 361 } 362 363 func setupNodeSignaturePaginationTest(t *testing.T, ctx context.Context) (*sqlstore.Notary, []entities.NodeSignature) { 364 t.Helper() 365 bs := sqlstore.NewBlocks(connectionSource) 366 ns := sqlstore.NewNotary(connectionSource) 367 signatures := make([]entities.NodeSignature, 10) 368 369 for i := 0; i < 10; i++ { 370 signature := getTestNodeSignature(t, ctx, bs, "deadbeef", fmt.Sprintf("sig%02d", i+1)) 371 signatures[i] = *signature 372 err := ns.Add(ctx, signature) 373 require.NoError(t, err) 374 } 375 376 return ns, signatures 377 } 378 379 func TestNodeSignatureKindEnum(t *testing.T) { 380 var nodeSignatureKind v1.NodeSignatureKind 381 sigKinds := getEnums(t, nodeSignatureKind) 382 assert.Len(t, sigKinds, 6) 383 for k, kind := range sigKinds { 384 t.Run(kind, func(t *testing.T) { 385 ctx := tempTransaction(t) 386 387 ws, bs, _ := setupNotaryStoreTests(t) 388 389 ns := getTestNodeSignature(t, ctx, bs, "deadbeef", "iamsig") 390 ns.Kind = entities.NodeSignatureKind(k) 391 require.NoError(t, ws.Add(ctx, ns)) 392 got, err := ws.GetByTxHash(ctx, ns.TxHash) 393 require.NoError(t, err) 394 assert.Len(t, got, 1) 395 assert.Equal(t, ns.Kind, got[0].Kind) 396 }) 397 } 398 }