code.vegaprotocol.io/vega@v0.79.0/datanode/sqlstore/oracle_data_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 "testing" 21 "time" 22 23 dstypes "code.vegaprotocol.io/vega/core/datasource/common" 24 "code.vegaprotocol.io/vega/datanode/entities" 25 "code.vegaprotocol.io/vega/datanode/sqlstore" 26 vegapb "code.vegaprotocol.io/vega/protos/vega" 27 datapb "code.vegaprotocol.io/vega/protos/vega/data/v1" 28 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/require" 31 ) 32 33 func TestOracleData(t *testing.T) { 34 t.Run("Add should insert oracle data", testAddOracleData) 35 t.Run("ListOracleData should return all data where matched spec ids contains the provided id", testGetOracleDataBySpecID) 36 t.Run("ListOracleData should return all data if the spec id is not provided", testGetOracleDataWithoutSpecID) 37 t.Run("GetByTxHash", testGetOracleDataByTxHash) 38 t.Run("Add should insert and retrieve oracle data with error", testAddAndRetrieveOracleDataWithError) 39 t.Run("Add should insert and retrieve oracle data with meta data", testAddAndRetrieveOracleDataWithMetaData) 40 } 41 42 func setupOracleDataTest(t *testing.T) (*sqlstore.Blocks, *sqlstore.OracleData, sqlstore.Connection) { 43 t.Helper() 44 bs := sqlstore.NewBlocks(connectionSource) 45 od := sqlstore.NewOracleData(connectionSource) 46 return bs, od, connectionSource 47 } 48 49 func testAddAndRetrieveOracleDataWithError(t *testing.T) { 50 ctx := tempTransaction(t) 51 52 bs, od, conn := setupOracleDataTest(t) 53 54 var rowCount int 55 assert.NoError(t, conn.QueryRow(ctx, "select count(*) from oracle_data").Scan(&rowCount)) 56 assert.Equal(t, 0, rowCount) 57 58 block := addTestBlock(t, ctx, bs) 59 dataProtos := getTestOracleData() 60 61 for i, proto := range dataProtos { 62 data, err := entities.OracleDataFromProto(proto, generateTxHash(), block.VegaTime, uint64(i)) 63 require.NoError(t, err) 64 assert.NoError(t, od.Add(ctx, data)) 65 } 66 67 dataForSpec, _, err := od.ListOracleData(ctx, "deadbeef01", entities.CursorPagination{}) 68 assert.NoError(t, err) 69 assert.Equal(t, len(dataForSpec), 1) 70 71 data := dataForSpec[0] 72 73 assert.Equal(t, dataProtos[0].ExternalData.Data.Error, data.ExternalData.Data.Error) 74 } 75 76 func testAddAndRetrieveOracleDataWithMetaData(t *testing.T) { 77 ctx := tempTransaction(t) 78 79 bs, od, conn := setupOracleDataTest(t) 80 81 var rowCount int 82 assert.NoError(t, conn.QueryRow(ctx, "select count(*) from oracle_data").Scan(&rowCount)) 83 assert.Equal(t, 0, rowCount) 84 85 block := addTestBlock(t, ctx, bs) 86 dataProtos := getTestOracleData() 87 88 for i, proto := range dataProtos { 89 data, err := entities.OracleDataFromProto(proto, generateTxHash(), block.VegaTime, uint64(i)) 90 require.NoError(t, err) 91 assert.NoError(t, od.Add(ctx, data)) 92 } 93 94 dataForSpec, _, err := od.ListOracleData(ctx, "deadbeef01", entities.CursorPagination{}) 95 assert.NoError(t, err) 96 assert.Equal(t, len(dataForSpec), 1) 97 98 data := dataForSpec[0] 99 100 assert.Equal(t, dataProtos[0].ExternalData.Data.MetaData[0].Value, data.ExternalData.Data.MetaData[0].Value) 101 } 102 103 func testAddOracleData(t *testing.T) { 104 ctx := tempTransaction(t) 105 106 bs, od, conn := setupOracleDataTest(t) 107 108 var rowCount int 109 assert.NoError(t, conn.QueryRow(ctx, "select count(*) from oracle_data").Scan(&rowCount)) 110 assert.Equal(t, 0, rowCount) 111 112 block := addTestBlock(t, ctx, bs) 113 dataProtos := getTestOracleData() 114 115 for i, proto := range dataProtos { 116 data, err := entities.OracleDataFromProto(proto, generateTxHash(), block.VegaTime, uint64(i)) 117 require.NoError(t, err) 118 assert.NoError(t, od.Add(ctx, data)) 119 } 120 121 assert.NoError(t, conn.QueryRow(ctx, "select count(*) from oracle_data").Scan(&rowCount)) 122 assert.Equal(t, len(dataProtos), rowCount) 123 } 124 125 func testGetOracleDataBySpecID(t *testing.T) { 126 ctx := tempTransaction(t) 127 128 bs, od, conn := setupOracleDataTest(t) 129 130 var rowCount int 131 err := conn.QueryRow(ctx, "select count(*) from oracle_data").Scan(&rowCount) 132 require.NoError(t, err) 133 assert.Equal(t, 0, rowCount) 134 135 testTime := time.Now() 136 dataProtos := getTestOracleData() 137 138 for i, proto := range dataProtos { 139 block := addTestBlockForTime(t, ctx, bs, testTime) 140 data, err := entities.OracleDataFromProto(proto, generateTxHash(), block.VegaTime, uint64(i)) 141 require.NoError(t, err) 142 err = od.Add(ctx, data) 143 require.NoError(t, err) 144 testTime = testTime.Add(time.Minute) 145 } 146 147 err = conn.QueryRow(ctx, "select count(*) from oracle_data").Scan(&rowCount) 148 require.NoError(t, err) 149 assert.Equal(t, len(dataProtos), rowCount) 150 151 got, _, err := od.ListOracleData(ctx, "deadbeef02", entities.CursorPagination{}) 152 require.NoError(t, err) 153 assert.Equal(t, 2, len(got)) 154 } 155 156 func testGetOracleDataWithoutSpecID(t *testing.T) { 157 ctx := tempTransaction(t) 158 159 bs, od, conn := setupOracleDataTest(t) 160 161 var rowCount int 162 err := conn.QueryRow(ctx, "select count(*) from oracle_data").Scan(&rowCount) 163 require.NoError(t, err) 164 assert.Equal(t, 0, rowCount) 165 166 testTime := time.Now() 167 dataProtos := getTestOracleData() 168 169 for i, proto := range dataProtos { 170 block := addTestBlockForTime(t, ctx, bs, testTime) 171 data, err := entities.OracleDataFromProto(proto, generateTxHash(), block.VegaTime, uint64(i)) 172 require.NoError(t, err) 173 err = od.Add(ctx, data) 174 require.NoError(t, err) 175 testTime = testTime.Add(time.Minute) 176 } 177 178 err = conn.QueryRow(ctx, "select count(*) from oracle_data").Scan(&rowCount) 179 require.NoError(t, err) 180 assert.Equal(t, len(dataProtos), rowCount) 181 182 got, _, err := od.ListOracleData(ctx, "", entities.CursorPagination{}) 183 require.NoError(t, err) 184 assert.Equal(t, len(dataProtos), len(got)) 185 } 186 187 func testGetOracleDataByTxHash(t *testing.T) { 188 ctx := tempTransaction(t) 189 190 bs, od, conn := setupOracleDataTest(t) 191 192 var rowCount int 193 err := conn.QueryRow(ctx, "select count(*) from oracle_data").Scan(&rowCount) 194 require.NoError(t, err) 195 assert.Equal(t, 0, rowCount) 196 197 testTime := time.Now() 198 dataProtos := getTestOracleData() 199 200 datas := make([]entities.OracleData, 0, len(dataProtos)) 201 for i, proto := range dataProtos { 202 block := addTestBlockForTime(t, ctx, bs, testTime) 203 data, err := entities.OracleDataFromProto(proto, generateTxHash(), block.VegaTime, uint64(i)) 204 require.NoError(t, err) 205 err = od.Add(ctx, data) 206 require.NoError(t, err) 207 testTime = testTime.Add(time.Minute) 208 209 datas = append(datas, *data) 210 } 211 212 err = conn.QueryRow(ctx, "select count(*) from oracle_data").Scan(&rowCount) 213 require.NoError(t, err) 214 assert.Equal(t, len(dataProtos), rowCount) 215 216 foundData, err := od.GetByTxHash(ctx, datas[0].ExternalData.Data.TxHash) 217 require.NoError(t, err) 218 assert.Equal(t, 1, len(foundData)) 219 assert.Equal(t, datas[0].ExternalData.Data, foundData[0].ExternalData.Data) 220 221 foundData2, err := od.GetByTxHash(ctx, datas[1].ExternalData.Data.TxHash) 222 require.NoError(t, err) 223 assert.Equal(t, 1, len(foundData2)) 224 assert.Equal(t, datas[1].ExternalData.Data, foundData2[0].ExternalData.Data) 225 } 226 227 func getTestOracleData() []*vegapb.OracleData { 228 pk1 := dstypes.CreateSignerFromString("b105f00d", dstypes.SignerTypePubKey) 229 pk2 := dstypes.CreateSignerFromString("baddcafe", dstypes.SignerTypePubKey) 230 testError := "testError" 231 232 return []*vegapb.OracleData{ 233 { // 0 234 ExternalData: &datapb.ExternalData{ 235 Data: &datapb.Data{ 236 Signers: []*datapb.Signer{pk1.IntoProto(), pk2.IntoProto()}, 237 MetaData: []*datapb.Property{ 238 { 239 Name: "metaKey", 240 Value: "metaValue", 241 }, 242 }, 243 MatchedSpecIds: []string{"deadbeef01"}, 244 BroadcastAt: 0, 245 Error: &testError, 246 }, 247 }, 248 }, 249 // }, 250 { // 1 251 ExternalData: &datapb.ExternalData{ 252 Data: &datapb.Data{ 253 Signers: []*datapb.Signer{pk1.IntoProto(), pk2.IntoProto()}, 254 Data: []*datapb.Property{ 255 { 256 Name: "Ticker", 257 Value: "USDETH", 258 }, 259 }, 260 MetaData: []*datapb.Property{}, 261 MatchedSpecIds: []string{"deadbeef02"}, 262 BroadcastAt: 0, 263 }, 264 }, 265 }, 266 { // 2 267 ExternalData: &datapb.ExternalData{ 268 Data: &datapb.Data{ 269 Signers: []*datapb.Signer{pk1.IntoProto(), pk2.IntoProto()}, 270 Data: []*datapb.Property{ 271 { 272 Name: "Ticker", 273 Value: "USDETH", 274 }, 275 }, 276 MetaData: []*datapb.Property{}, 277 MatchedSpecIds: []string{"deadbeef02"}, 278 BroadcastAt: 0, 279 }, 280 }, 281 }, 282 { // 3 283 ExternalData: &datapb.ExternalData{ 284 Data: &datapb.Data{ 285 Signers: []*datapb.Signer{pk1.IntoProto(), pk2.IntoProto()}, 286 Data: []*datapb.Property{ 287 { 288 Name: "Ticker", 289 Value: "USDSOL", 290 }, 291 }, 292 MetaData: []*datapb.Property{}, 293 MatchedSpecIds: []string{"deadbeef03"}, 294 BroadcastAt: 0, 295 }, 296 }, 297 }, 298 { // 4 299 ExternalData: &datapb.ExternalData{ 300 Data: &datapb.Data{ 301 Signers: []*datapb.Signer{pk1.IntoProto(), pk2.IntoProto()}, 302 Data: []*datapb.Property{ 303 { 304 Name: "AAAA", 305 Value: "AAAA", 306 }, 307 }, 308 MetaData: []*datapb.Property{}, 309 MatchedSpecIds: []string{"deadbeef04"}, 310 }, 311 }, 312 }, 313 { // 5 314 ExternalData: &datapb.ExternalData{ 315 Data: &datapb.Data{ 316 Signers: []*datapb.Signer{pk1.IntoProto(), pk2.IntoProto()}, 317 Data: []*datapb.Property{ 318 { 319 Name: "BBBB", 320 Value: "BBBB", 321 }, 322 }, 323 MetaData: []*datapb.Property{}, 324 MatchedSpecIds: []string{"deadbeef04"}, 325 }, 326 }, 327 }, 328 { // 6 329 ExternalData: &datapb.ExternalData{ 330 Data: &datapb.Data{ 331 Signers: []*datapb.Signer{pk1.IntoProto(), pk2.IntoProto()}, 332 Data: []*datapb.Property{ 333 { 334 Name: "CCCC", 335 Value: "CCCC", 336 }, 337 }, 338 MetaData: []*datapb.Property{}, 339 MatchedSpecIds: []string{"deadbeef04"}, 340 }, 341 }, 342 }, 343 { // 7 344 ExternalData: &datapb.ExternalData{ 345 Data: &datapb.Data{ 346 Signers: []*datapb.Signer{pk1.IntoProto(), pk2.IntoProto()}, 347 Data: []*datapb.Property{ 348 { 349 Name: "DDDD", 350 Value: "DDDD", 351 }, 352 }, 353 MetaData: []*datapb.Property{}, 354 MatchedSpecIds: []string{"deadbeef04"}, 355 }, 356 }, 357 }, 358 { // 8 359 ExternalData: &datapb.ExternalData{ 360 Data: &datapb.Data{ 361 Signers: []*datapb.Signer{pk1.IntoProto(), pk2.IntoProto()}, 362 Data: []*datapb.Property{ 363 { 364 Name: "EEEE", 365 Value: "EEEE", 366 }, 367 }, 368 MetaData: []*datapb.Property{}, 369 MatchedSpecIds: []string{"deadbeef04"}, 370 }, 371 }, 372 }, 373 { // 9 374 ExternalData: &datapb.ExternalData{ 375 Data: &datapb.Data{ 376 Signers: []*datapb.Signer{pk1.IntoProto(), pk2.IntoProto()}, 377 Data: []*datapb.Property{ 378 { 379 Name: "FFFF", 380 Value: "FFFF", 381 }, 382 }, 383 MetaData: []*datapb.Property{}, 384 MatchedSpecIds: []string{"deadbeef04"}, 385 }, 386 }, 387 }, 388 { // 10 389 ExternalData: &datapb.ExternalData{ 390 Data: &datapb.Data{ 391 Signers: []*datapb.Signer{pk1.IntoProto(), pk2.IntoProto()}, 392 Data: []*datapb.Property{ 393 { 394 Name: "GGGG", 395 Value: "GGGG", 396 }, 397 }, 398 MetaData: []*datapb.Property{}, 399 MatchedSpecIds: []string{"deadbeef04"}, 400 }, 401 }, 402 }, 403 } 404 } 405 406 func getTestPaginationOracleData(t *testing.T, ctx context.Context, bs *sqlstore.Blocks, ds *sqlstore.OracleData) []entities.OracleData { 407 t.Helper() 408 protoData := getTestOracleData() 409 data := make([]entities.OracleData, 0, len(protoData)) 410 411 blockTime := time.Now() 412 413 for i, item := range protoData { 414 block := addTestBlockForTime(t, ctx, bs, blockTime) 415 odEntity, err := entities.OracleDataFromProto(item, generateTxHash(), block.VegaTime, uint64(i)) 416 require.NoError(t, err) 417 418 err = ds.Add(ctx, odEntity) 419 require.NoError(t, err) 420 421 data = append(data, *odEntity) 422 blockTime = blockTime.Add(time.Minute) 423 } 424 425 return data 426 } 427 428 func TestOracleData_GetOracleDataBySpecIDCursorPagination(t *testing.T) { 429 t.Run("should return all data when no pagination is provided", testOracleDataGetBySpecNoPagination) 430 t.Run("should return first page when first is provided", testOracleDataGetBySpecFirst) 431 t.Run("should return last page when last is provided", testOracleDataGetBySpecLast) 432 t.Run("should return requested page when first and after is provided", testOracleDataGetBySpecFirstAfter) 433 t.Run("should return requested page when last and before is provided", testOracleDataGetBySpecLastBefore) 434 } 435 436 func testOracleDataGetBySpecNoPagination(t *testing.T) { 437 ctx := tempTransaction(t) 438 439 bs, ds, _ := setupOracleDataTest(t) 440 data := getTestPaginationOracleData(t, ctx, bs, ds) 441 442 pagination, err := entities.NewCursorPagination(nil, nil, nil, nil, false) 443 require.NoError(t, err) 444 445 got, pageInfo, err := ds.ListOracleData(ctx, "deadbeef04", pagination) 446 require.NoError(t, err) 447 assert.Equal(t, data[4:], got) 448 assert.Equal(t, entities.PageInfo{ 449 HasNextPage: false, 450 HasPreviousPage: false, 451 StartCursor: data[4].Cursor().Encode(), 452 EndCursor: data[10].Cursor().Encode(), 453 }, pageInfo) 454 } 455 456 func testOracleDataGetBySpecFirst(t *testing.T) { 457 ctx := tempTransaction(t) 458 459 bs, ds, _ := setupOracleDataTest(t) 460 data := getTestPaginationOracleData(t, ctx, bs, ds) 461 462 first := int32(3) 463 pagination, err := entities.NewCursorPagination(&first, nil, nil, nil, false) 464 require.NoError(t, err) 465 466 got, pageInfo, err := ds.ListOracleData(ctx, "deadbeef04", pagination) 467 require.NoError(t, err) 468 assert.Equal(t, data[4:7], got) 469 assert.Equal(t, entities.PageInfo{ 470 HasNextPage: true, 471 HasPreviousPage: false, 472 StartCursor: data[4].Cursor().Encode(), 473 EndCursor: data[6].Cursor().Encode(), 474 }, pageInfo) 475 } 476 477 func testOracleDataGetBySpecLast(t *testing.T) { 478 ctx := tempTransaction(t) 479 480 bs, ds, _ := setupOracleDataTest(t) 481 data := getTestPaginationOracleData(t, ctx, bs, ds) 482 483 last := int32(3) 484 pagination, err := entities.NewCursorPagination(nil, nil, &last, nil, false) 485 require.NoError(t, err) 486 487 got, pageInfo, err := ds.ListOracleData(ctx, "deadbeef04", pagination) 488 require.NoError(t, err) 489 assert.Equal(t, data[8:], got) 490 assert.Equal(t, entities.PageInfo{ 491 HasNextPage: false, 492 HasPreviousPage: true, 493 StartCursor: data[8].Cursor().Encode(), 494 EndCursor: data[10].Cursor().Encode(), 495 }, pageInfo) 496 } 497 498 func testOracleDataGetBySpecFirstAfter(t *testing.T) { 499 ctx := tempTransaction(t) 500 501 bs, ds, _ := setupOracleDataTest(t) 502 data := getTestPaginationOracleData(t, ctx, bs, ds) 503 504 first := int32(3) 505 after := data[6].Cursor().Encode() 506 pagination, err := entities.NewCursorPagination(&first, &after, nil, nil, false) 507 require.NoError(t, err) 508 509 got, pageInfo, err := ds.ListOracleData(ctx, "deadbeef04", pagination) 510 require.NoError(t, err) 511 assert.Equal(t, data[7:10], got) 512 assert.Equal(t, entities.PageInfo{ 513 HasNextPage: true, 514 HasPreviousPage: true, 515 StartCursor: data[7].Cursor().Encode(), 516 EndCursor: data[9].Cursor().Encode(), 517 }, pageInfo) 518 } 519 520 func testOracleDataGetBySpecLastBefore(t *testing.T) { 521 ctx := tempTransaction(t) 522 523 bs, ds, _ := setupOracleDataTest(t) 524 data := getTestPaginationOracleData(t, ctx, bs, ds) 525 526 last := int32(3) 527 before := data[8].Cursor().Encode() 528 pagination, err := entities.NewCursorPagination(nil, nil, &last, &before, false) 529 require.NoError(t, err) 530 531 got, pageInfo, err := ds.ListOracleData(ctx, "deadbeef04", pagination) 532 require.NoError(t, err) 533 assert.Equal(t, data[5:8], got) 534 assert.Equal(t, entities.PageInfo{ 535 HasNextPage: true, 536 HasPreviousPage: true, 537 StartCursor: data[5].Cursor().Encode(), 538 EndCursor: data[7].Cursor().Encode(), 539 }, pageInfo) 540 } 541 542 // check when its empty what happens