feat(wallet) extract json blobs and add custom migration support

Extended the migration process with a generic way of applying custom
migration code on top of the SQL files. The implementation provides
a safer way to run GO code along with the SQL migrations and possibility
of rolling back the changes in case of failure to keep the database
consistent.
This custom GO migration is needed to extract the status from
the JSON blob receipt and store it in transfers table.

Other changes:
- Add NULL DB value tracking to JSONBlob helper
- Index status column on transfers table
- Remove unnecessary panic calls
- Move log_parser to wallet's common package and use to extract token
  identity from the logs

Notes:
- there is already an index on transfers table, sqlite creates one for
  each unique constraint therefore add only status to a new index
- the planned refactoring and improvements to the database have been
  postponed due to time constraints. Got the time to migrate the data
  though, extracting it can be done later for a more efficient
  implementation

Update status-desktop #10746
This commit is contained in:
Stefan 2023-05-19 18:31:45 +03:00 committed by Stefan Dunca
parent 9e0a12cb32
commit 5b6f7226bb
26 changed files with 1450 additions and 224 deletions

View File

@ -4,17 +4,27 @@ import (
"database/sql"
"encoding/json"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/appdatabase/migrations"
migrationsprevnodecfg "github.com/status-im/status-go/appdatabase/migrationsprevnodecfg"
"github.com/status-im/status-go/nodecfg"
"github.com/status-im/status-go/services/wallet/bigint"
w_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/sqlite"
)
const nodeCfgMigrationDate = 1640111208
var customSteps = []sqlite.PostStep{
{Version: 1674136690, CustomMigration: migrateEnsUsernames},
{Version: 1686048341, CustomMigration: migrateWalletJSONBlobs, RollBackVersion: 1686041510},
}
// InitializeDB creates db file at a given path and applies migrations.
func InitializeDB(path, password string, kdfIterationsNumber int) (*sql.DB, error) {
db, err := sqlite.OpenDB(path, password, kdfIterationsNumber)
@ -22,23 +32,11 @@ func InitializeDB(path, password string, kdfIterationsNumber int) (*sql.DB, erro
return nil, err
}
// Check if the migration table exists
row := db.QueryRow("SELECT exists(SELECT name FROM sqlite_master WHERE type='table' AND name='status_go_schema_migrations')")
migrationTableExists := false
err = row.Scan(&migrationTableExists)
if err != nil && err != sql.ErrNoRows {
lastMigration, migrationTableExists, err := sqlite.GetLastMigrationVersion(db)
if err != nil {
return nil, err
}
var lastMigration uint64 = 0
if migrationTableExists {
row = db.QueryRow("SELECT version FROM status_go_schema_migrations")
err = row.Scan(&lastMigration)
if err != nil && err != sql.ErrNoRows {
return nil, err
}
}
if !migrationTableExists || (lastMigration > 0 && lastMigration < nodeCfgMigrationDate) {
// If it's the first time migration's being run, or latest migration happened before migrating the nodecfg table
err = migrationsprevnodecfg.Migrate(db)
@ -53,13 +51,8 @@ func InitializeDB(path, password string, kdfIterationsNumber int) (*sql.DB, erro
}
}
err = migrations.Migrate(db)
if err != nil {
return nil, err
}
// Migrate `settings.usernames` here, because current SQL implementation doesn't support `json_each`
err = MigrateEnsUsernames(db)
// Run all the new migrations
err = migrations.Migrate(db, customSteps)
if err != nil {
return nil, err
}
@ -116,11 +109,11 @@ func GetDBFilename(db *sql.DB) (string, error) {
return "", errors.New("no main database found")
}
func MigrateEnsUsernames(db *sql.DB) error {
func migrateEnsUsernames(sqlTx *sql.Tx) error {
// 1. Check if ens_usernames table already exist
// row := db.QueryRow("SELECT exists(SELECT name FROM sqlite_master WHERE type='table' AND name='ens_usernames')")
// row := sqlTx.QueryRow("SELECT exists(SELECT name FROM sqlite_master WHERE type='table' AND name='ens_usernames')")
// tableExists := false
// err := row.Scan(&tableExists)
@ -134,7 +127,7 @@ func MigrateEnsUsernames(db *sql.DB) error {
// -- 1. Create new ens_usernames table
// _, err = db.Exec(`CREATE TABLE IF NOT EXISTS ens_usernames (
// _, err = sqlTx.Exec(`CREATE TABLE IF NOT EXISTS ens_usernames (
// "username" TEXT NOT NULL,
// "chain_id" UNSIGNED BIGINT DEFAULT 1);`)
@ -149,7 +142,7 @@ func MigrateEnsUsernames(db *sql.DB) error {
SELECT json_each.value FROM settings, json_each(usernames);
*/
rows, err := db.Query(`SELECT usernames FROM settings`)
rows, err := sqlTx.Query(`SELECT usernames FROM settings`)
if err != nil {
log.Error("Migrating ens usernames: failed to query 'settings.usernames'", "err", err.Error())
@ -187,7 +180,7 @@ func MigrateEnsUsernames(db *sql.DB) error {
var usernameAlreadyMigrated bool
row := db.QueryRow(`SELECT EXISTS(SELECT 1 FROM ens_usernames WHERE username=? AND chain_id=?)`, username, defaultChainID)
row := sqlTx.QueryRow(`SELECT EXISTS(SELECT 1 FROM ens_usernames WHERE username=? AND chain_id=?)`, username, defaultChainID)
err := row.Scan(&usernameAlreadyMigrated)
if err != nil {
@ -198,7 +191,7 @@ func MigrateEnsUsernames(db *sql.DB) error {
continue
}
_, err = db.Exec(`INSERT INTO ens_usernames (username, chain_id) VALUES (?, ?)`, username, defaultChainID)
_, err = sqlTx.Exec(`INSERT INTO ens_usernames (username, chain_id) VALUES (?, ?)`, username, defaultChainID)
if err != nil {
log.Error("Migrating ens usernames: failed to insert username into new database", "ensUsername", username, "err", err.Error())
}
@ -206,3 +199,173 @@ func MigrateEnsUsernames(db *sql.DB) error {
return nil
}
const (
batchSize = 1000
)
func migrateWalletJSONBlobs(sqlTx *sql.Tx) error {
var batchEntries [][]interface{}
// Extract useful information from the receipt blob and store it as sql interpretable
//
// Added tx_hash because the hash column in the transfers table is not (always) the transaction hash.
// Each entry in that table could either be: A native token (ETH) transfer or ERC20/ERC721 token transfer
// Added block_hash because the block_hash we have is generated by us and used as block entry ID
// Added receipt_type, the type we have only indicates if chain or token
// Added log_index that the log data represents
//
// Dropped storing postState because it was replaced by the status after EIP 658
// Dropped duplicating logs until we have a more structured way to store them.
// They can be extracted from the transfers.receipt still
// Dropped the bloom filter because in SQLite is not possible to use it in an
// efficient manner
//
// Extract useful information from the tx blob
//
// Added tx_type, which might be different than the receipt type
//
// Dropped access_list, need a separate table for it
// Already there chain_id
// Dropped v, r, s because I see no way to be useful as BLOBs
// Added BIGINT values as clamped 64 INT because we can't use 128 bits blobs/strings for int arithmetics
// _clamped64 prefix indicate clamped 64 bits INT values might be useful for queries (sorting, filtering ...)
// The amount is stored as a fixed length 128 bit hex string, in
// order to be able to sort and filter by it
newColumnsAndIndexSetup := `
ALTER TABLE transfers ADD COLUMN status INT;
ALTER TABLE transfers ADD COLUMN receipt_type INT;
ALTER TABLE transfers ADD COLUMN tx_hash BLOB;
ALTER TABLE transfers ADD COLUMN log_index INT;
ALTER TABLE transfers ADD COLUMN block_hash BLOB;
ALTER TABLE transfers ADD COLUMN cumulative_gas_used INT;
ALTER TABLE transfers ADD COLUMN contract_address TEXT;
ALTER TABLE transfers ADD COLUMN gas_used INT;
ALTER TABLE transfers ADD COLUMN tx_index INT;
ALTER TABLE transfers ADD COLUMN tx_type INT;
ALTER TABLE transfers ADD COLUMN protected BOOLEAN;
ALTER TABLE transfers ADD COLUMN gas_limit UNSIGNED INT;
ALTER TABLE transfers ADD COLUMN gas_price_clamped64 INT;
ALTER TABLE transfers ADD COLUMN gas_tip_cap_clamped64 INT;
ALTER TABLE transfers ADD COLUMN gas_fee_cap_clamped64 INT;
ALTER TABLE transfers ADD COLUMN amount_padded128hex CHAR(32);
ALTER TABLE transfers ADD COLUMN account_nonce INT;
ALTER TABLE transfers ADD COLUMN size INT;
ALTER TABLE transfers ADD COLUMN token_address BLOB;
ALTER TABLE transfers ADD COLUMN token_id BLOB;
CREATE INDEX idx_transfers_filter ON transfers (status, token_address, token_id);`
rowIndex := 0
mightHaveRows := true
_, err := sqlTx.Exec(newColumnsAndIndexSetup)
if err != nil {
return err
}
for mightHaveRows {
var chainID uint64
var hash common.Hash
var address common.Address
var entryType string
rows, err := sqlTx.Query(`SELECT hash, address, network_id, tx, receipt, log, type FROM transfers WHERE tx IS NOT NULL OR receipt IS NOT NULL LIMIT ? OFFSET ?`, batchSize, rowIndex)
if err != nil {
return err
}
curProcessed := 0
for rows.Next() {
tx := &types.Transaction{}
r := &types.Receipt{}
l := &types.Log{}
// Scan row data into the transaction and receipt objects
nullableTx := sqlite.JSONBlob{Data: tx}
nullableR := sqlite.JSONBlob{Data: r}
nullableL := sqlite.JSONBlob{Data: l}
err = rows.Scan(&hash, &address, &chainID, &nullableTx, &nullableR, &nullableL, &entryType)
if err != nil {
rows.Close()
return err
}
var logIndex *uint
if nullableL.Valid {
logIndex = new(uint)
*logIndex = l.Index
}
var currentRow []interface{}
// Check if the receipt is not null before transferring the receipt data
if nullableR.Valid {
currentRow = append(currentRow, r.Status, r.Type, r.TxHash, logIndex, r.BlockHash, r.CumulativeGasUsed, r.ContractAddress, r.GasUsed, r.TransactionIndex)
} else {
for i := 0; i < 9; i++ {
currentRow = append(currentRow, nil)
}
}
if nullableTx.Valid {
var tokenAddress *common.Address
var correctType w_common.Type
var tokenID, value *big.Int
if nullableL.Valid {
correctType, tokenAddress, tokenID, value = w_common.ExtractTokenIdentity(w_common.Type(entryType), l, tx)
} else {
correctType = w_common.Type(entryType)
value = new(big.Int).Set(tx.Value())
}
gasPrice := sqlite.BigIntToClampedInt64(tx.GasPrice())
gasTipCap := sqlite.BigIntToClampedInt64(tx.GasTipCap())
gasFeeCap := sqlite.BigIntToClampedInt64(tx.GasFeeCap())
valueStr := sqlite.BigIntToPadded128BitsStr(value)
currentRow = append(currentRow, tx.Type(), tx.Protected(), tx.Gas(), gasPrice, gasTipCap, gasFeeCap, valueStr, tx.Nonce(), int64(tx.Size()), &sqlite.JSONBlob{Data: tokenAddress}, (*bigint.SQLBigIntBytes)(tokenID), correctType)
} else {
for i := 0; i < 11; i++ {
currentRow = append(currentRow, nil)
}
currentRow = append(currentRow, w_common.EthTransfer)
}
currentRow = append(currentRow, hash, address, chainID)
batchEntries = append(batchEntries, currentRow)
curProcessed++
}
rowIndex += curProcessed
// Check if there was an error in the last rows.Next()
rows.Close()
if err = rows.Err(); err != nil {
return err
}
mightHaveRows = (curProcessed == batchSize)
// insert extracted data into the new columns
if len(batchEntries) > 0 {
var stmt *sql.Stmt
stmt, err = sqlTx.Prepare(`UPDATE transfers SET status = ?, receipt_type = ?, tx_hash = ?, log_index = ?, block_hash = ?, cumulative_gas_used = ?, contract_address = ?, gas_used = ?, tx_index = ?,
tx_type = ?, protected = ?, gas_limit = ?, gas_price_clamped64 = ?, gas_tip_cap_clamped64 = ?, gas_fee_cap_clamped64 = ?, amount_padded128hex = ?, account_nonce = ?, size = ?, token_address = ?, token_id = ?, type = ?
WHERE hash = ? AND address = ? AND network_id = ?`)
if err != nil {
return err
}
for _, dataEntry := range batchEntries {
_, err = stmt.Exec(dataEntry...)
if err != nil {
return err
}
}
// Reset placeHolders and batchEntries for the next batch
batchEntries = [][]interface{}{}
}
}
return nil
}

View File

@ -1,10 +1,24 @@
package appdatabase
import (
"database/sql"
"encoding/json"
"errors"
"fmt"
"math/big"
"strconv"
"testing"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/status-im/status-go/appdatabase/migrations"
migrationsprevnodecfg "github.com/status-im/status-go/appdatabase/migrationsprevnodecfg"
"github.com/status-im/status-go/nodecfg"
"github.com/status-im/status-go/services/wallet/bigint"
w_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/sqlite"
)
@ -31,3 +45,420 @@ func Test_GetDBFilename(t *testing.T) {
require.NoError(t, err)
require.Equal(t, "", fn)
}
const (
erc20ReceiptTestDataTemplate = `{"type":"0x2","root":"0x","status":"0x%d","cumulativeGasUsed":"0x10f8d2c","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000001008000000000000000000000000000000000000002000000000020000000000000000000800000000000000000000000010000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000800000000000000000000","logs":[{"address":"0x98339d8c260052b7ad81c28c16c0b98420f2b46a","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000e2d622c817878da5143bbe06866ca8e35273ba8a"],"data":"0x0000000000000000000000000000000000000000000000000000000000989680","blockNumber":"0x825527","transactionHash":"0xdcaa0fc7fe2e0d1f1343d1f36807344bb4fd26cda62ad8f9d8700e2c458cc79a","transactionIndex":"0x6c","blockHash":"0x69e0f829a557052c134cd7e21c220507d91bc35c316d3c47217e9bd362270274","logIndex":"0xcd","removed":false}],"transactionHash":"0xdcaa0fc7fe2e0d1f1343d1f36807344bb4fd26cda62ad8f9d8700e2c458cc79a","contractAddress":"0x0000000000000000000000000000000000000000","gasUsed":"0x8623","blockHash":"0x69e0f829a557052c134cd7e21c220507d91bc35c316d3c47217e9bd362270274","blockNumber":"0x825527","transactionIndex":"0x6c"}`
erc20TxTestData = `{"type":"0x2","nonce":"0x3d","gasPrice":"0x0","maxPriorityFeePerGas":"0x8c347c90","maxFeePerGas":"0x45964d43a4","gas":"0x8623","value":"0x0","input":"0x40c10f19000000000000000000000000e2d622c817878da5143bbe06866ca8e35273ba8a0000000000000000000000000000000000000000000000000000000000989680","v":"0x0","r":"0xbcac4bb290d48b467bb18ac67e98050b5f316d2c66b2f75dcc1d63a45c905d21","s":"0x10c15517ea9cabd7fe134b270daabf5d2e8335e935d3e021f54a4efaffb37cd2","to":"0x98339d8c260052b7ad81c28c16c0b98420f2b46a","chainId":"0x5","accessList":[],"hash":"0xdcaa0fc7fe2e0d1f1343d1f36807344bb4fd26cda62ad8f9d8700e2c458cc79a"}`
erc20LogTestData = `{"address":"0x98339d8c260052b7ad81c28c16c0b98420f2b46a","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000e2d622c817878da5143bbe06866ca8e35273ba8a"],"data":"0x0000000000000000000000000000000000000000000000000000000000989680","blockNumber":"0x825527","transactionHash":"0xdcaa0fc7fe2e0d1f1343d1f36807344bb4fd26cda62ad8f9d8700e2c458cc79a","transactionIndex":"0x6c","blockHash":"0x69e0f829a557052c134cd7e21c220507d91bc35c316d3c47217e9bd362270274","logIndex":"0xcd","removed":false}`
ethReceiptTestData = `{
"type": "0x2",
"root": "0x",
"status": "0x1",
"cumulativeGasUsed": "0x2b461",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"logs": [],
"transactionHash": "0x4ac700ee2a1702f82b3cfdc88fd4d91f767b87fea9b929bd6223c6471a5e05b4",
"contractAddress": "0x0000000000000000000000000000000000000000",
"gasUsed": "0x5208",
"blockHash": "0x25fe164361c1cb4ed1b46996f7b5236d3118144529b31fca037fcda1d8ee684d",
"blockNumber": "0x5e3294",
"transactionIndex": "0x3"
}`
ethTxTestData = `{
"type": "0x2",
"nonce": "0x1",
"gasPrice": "0x0",
"maxPriorityFeePerGas": "0x33",
"maxFeePerGas": "0x3b9aca00",
"gas": "0x55f0",
"value": "0x%s",
"input": "0x",
"v": "0x0",
"r": "0xacc277ce156382d6f333cc8d75a56250778b17f1c6d1676af63cf68d53713986",
"s": "0x32417261484e9796390abb8db13f993965d917836be5cd96df25b9b581de91ec",
"to": "0xbd54a96c0ae19a220c8e1234f54c940dfab34639",
"chainId": "0x1a4",
"accessList": [],
"hash": "0x4ac700ee2a1702f82b3cfdc88fd4d91f767b87fea9b929bd6223c6471a5e05b4"
}`
erc721TxTestData = `{"type":"0x2","nonce":"0x2f","gasPrice":"0x0","maxPriorityFeePerGas":"0x3b9aca00","maxFeePerGas":"0x2f691e609","gas":"0x1abc3","value":"0x0","input":"0x42842e0e000000000000000000000000165eeecc32dcb623f51fc6c1ddd9e2aea1575c630000000000000000000000001c9751e0fbf5081849b56b522d50fb7f163b8080000000000000000000000000000000000000000000000000000000003ba7b95e360c6ebe","v":"0x1","r":"0xead469c32ffda3aa933f9aed814df411fb07893153c775b50596660036bbb5da","s":"0x73edadd4e4a7f0895f686b68e16101d195c0bb1b5f248f16b21557800b95bdf8","to":"0x85f0e02cb992aa1f9f47112f815f519ef1a59e2d","chainId":"0x1","accessList":[],"hash":"0x1dd936499e35ece8747bc481e476ac43eb4555a3a82e8cb93b7e429219bdd371"}`
erc721ReceiptTestData = `{"type":"0x2","root":"0x","status":"0x1","cumulativeGasUsed":"0x54cadb","logsBloom":"0x00000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200200000000000000000000000000008000000000000080000000000000000000000002000200000020000000200000000000800000000000000000000000010000000000000000000000040000000000000000000000000000000000000000000000000020000000000000000000040010000000000000000000000000000000800000000000002020000000000000000000000000000000000000000000000000020000010000000000000000000004000000000000000000000000000000000000000","logs":[{"address":"0x85f0e02cb992aa1f9f47112f815f519ef1a59e2d","topics":["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0x000000000000000000000000165eeecc32dcb623f51fc6c1ddd9e2aea1575c63","0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000000000000000000000000000000000003ba7b95e"],"data":"0x","blockNumber":"0xf57974","transactionHash":"0x1dd936499e35ece8747bc481e476ac43eb4555a3a82e8cb93b7e429219bdd371","transactionIndex":"0x44","blockHash":"0x9228724ff5c19f9b1586e19b13102f94798d1ee32b5f14d5cbcdf74cc32eb732","logIndex":"0x86","removed":false},{"address":"0x85f0e02cb992aa1f9f47112f815f519ef1a59e2d","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000165eeecc32dcb623f51fc6c1ddd9e2aea1575c63","0x0000000000000000000000001c9751e0fbf5081849b56b522d50fb7f163b8080","0x000000000000000000000000000000000000000000000000000000003ba7b95e"],"data":"0x","blockNumber":"0xf57974","transactionHash":"0x1dd936499e35ece8747bc481e476ac43eb4555a3a82e8cb93b7e429219bdd371","transactionIndex":"0x44","blockHash":"0x9228724ff5c19f9b1586e19b13102f94798d1ee32b5f14d5cbcdf74cc32eb732","logIndex":"0x87","removed":false}],"transactionHash":"0x1dd936499e35ece8747bc481e476ac43eb4555a3a82e8cb93b7e429219bdd371","contractAddress":"0x0000000000000000000000000000000000000000","gasUsed":"0x18643","blockHash":"0x9228724ff5c19f9b1586e19b13102f94798d1ee32b5f14d5cbcdf74cc32eb732","blockNumber":"0xf57974","transactionIndex":"0x44"}`
erc721LogTestData = `{"address":"0x85f0e02cb992aa1f9f47112f815f519ef1a59e2d","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000165eeecc32dcb623f51fc6c1ddd9e2aea1575c63","0x0000000000000000000000001c9751e0fbf5081849b56b522d50fb7f163b8080","0x000000000000000000000000000000000000000000000000000000003ba7b95e"],"data":"0x","blockNumber":"0xf57974","transactionHash":"0x1dd936499e35ece8747bc481e476ac43eb4555a3a82e8cb93b7e429219bdd371","transactionIndex":"0x44","blockHash":"0x9228724ff5c19f9b1586e19b13102f94798d1ee32b5f14d5cbcdf74cc32eb732","logIndex":"0x87","removed":false}`
uniswapV2TxTestData = `{"type":"0x2","nonce":"0x42","gasPrice":"0x0","maxPriorityFeePerGas":"0x3b9aca00","maxFeePerGas":"0x13c6f691f2","gas":"0x2ed0d","value":"0xa688906bd8b0000","input":"0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000006440875700000000000000000000000000000000000000000000000000000000000000020b080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000a688906bd8b0000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000a688906bd8b000000000000000000000000000000000000000000001188be846e642b0ae4ae055e00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933","v":"0x1","r":"0xeb7b527c2bfd3d26ea8e21951f537f4603867a11532081ba77fde9465696c20a","s":"0x5c120e64973a3b83a80d8b045a2228b9d1421065c1d480d2c1e322dad3b76c0f","to":"0xef1c6e67703c7bd7107eed8303fbe6ec2554bf6b","chainId":"0x1","accessList":[],"hash":"0x6d70a0b14e2fe1ba28d6cb910ffc4aa787264dff6c273e20509136461ac587aa"}`
uniswapV2ReceiptTestData = `{"type":"0x2","root":"0x","status":"0x1","cumulativeGasUsed":"0x1ba15e","logsBloom":"0x00200000000000000000000080400000000000000000000000000000000000000000000000000000000000000000000002000000080000000000000200000000000000080000000000000008000000200000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000000000000008000000000000000040000000001000000080000004200000000000800000000000000000000008000000000000000000000000000000800000001000012000000000000000000000000400000000000001000000000000000000000200001000000020000000000000000000000000000400000000080000000","logs":[{"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","topics":["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c","0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"],"data":"0x0000000000000000000000000000000000000000000000000a688906bd8b0000","blockNumber":"0x104ae90","transactionHash":"0x6d70a0b14e2fe1ba28d6cb910ffc4aa787264dff6c273e20509136461ac587aa","transactionIndex":"0x4","blockHash":"0x49e3ef5a17eb5563b327fffdf315dd9269c5a5676eec1f5c15897c4ef61623df","logIndex":"0x2b","removed":false},{"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b","0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"],"data":"0x0000000000000000000000000000000000000000000000000a688906bd8b0000","blockNumber":"0x104ae90","transactionHash":"0x6d70a0b14e2fe1ba28d6cb910ffc4aa787264dff6c273e20509136461ac587aa","transactionIndex":"0x4","blockHash":"0x49e3ef5a17eb5563b327fffdf315dd9269c5a5676eec1f5c15897c4ef61623df","logIndex":"0x2c","removed":false},{"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b","0x000000000000000000000000a43fe16908251ee70ef74718545e4fe6c5ccec9f"],"data":"0x0000000000000000000000000000000000000000000000000a688906bd8b0000","blockNumber":"0x104ae90","transactionHash":"0x6d70a0b14e2fe1ba28d6cb910ffc4aa787264dff6c273e20509136461ac587aa","transactionIndex":"0x4","blockHash":"0x49e3ef5a17eb5563b327fffdf315dd9269c5a5676eec1f5c15897c4ef61623df","logIndex":"0x2d","removed":false},{"address":"0x6982508145454ce325ddbe47a25d4ec3d2311933","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000a43fe16908251ee70ef74718545e4fe6c5ccec9f","0x000000000000000000000000165eeecc32dcb623f51fc6c1ddd9e2aea1575c63"],"data":"0x000000000000000000000000000000000000000011b2e784030a3a65a3559087","blockNumber":"0x104ae90","transactionHash":"0x6d70a0b14e2fe1ba28d6cb910ffc4aa787264dff6c273e20509136461ac587aa","transactionIndex":"0x4","blockHash":"0x49e3ef5a17eb5563b327fffdf315dd9269c5a5676eec1f5c15897c4ef61623df","logIndex":"0x2e","removed":false},{"address":"0xa43fe16908251ee70ef74718545e4fe6c5ccec9f","topics":["0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1"],"data":"0x000000000000000000000000000000000000003bdd991fe0c766723fa956e323000000000000000000000000000000000000000000000023240d303bb8bbb575","blockNumber":"0x104ae90","transactionHash":"0x6d70a0b14e2fe1ba28d6cb910ffc4aa787264dff6c273e20509136461ac587aa","transactionIndex":"0x4","blockHash":"0x49e3ef5a17eb5563b327fffdf315dd9269c5a5676eec1f5c15897c4ef61623df","logIndex":"0x2f","removed":false},{"address":"0xa43fe16908251ee70ef74718545e4fe6c5ccec9f","topics":["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b","0x000000000000000000000000165eeecc32dcb623f51fc6c1ddd9e2aea1575c63"],"data":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a688906bd8b0000000000000000000000000000000000000000000011b2e784030a3a65a35590870000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x104ae90","transactionHash":"0x6d70a0b14e2fe1ba28d6cb910ffc4aa787264dff6c273e20509136461ac587aa","transactionIndex":"0x4","blockHash":"0x49e3ef5a17eb5563b327fffdf315dd9269c5a5676eec1f5c15897c4ef61623df","logIndex":"0x30","removed":false}],"transactionHash":"0x6d70a0b14e2fe1ba28d6cb910ffc4aa787264dff6c273e20509136461ac587aa","contractAddress":"0x0000000000000000000000000000000000000000","gasUsed":"0x1ec85","blockHash":"0x49e3ef5a17eb5563b327fffdf315dd9269c5a5676eec1f5c15897c4ef61623df","blockNumber":"0x104ae90","transactionIndex":"0x4"}`
uniswapV2LogTestData = `{"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","topics":["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c","0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"],"data":"0x0000000000000000000000000000000000000000000000000a688906bd8b0000","blockNumber":"0x104ae90","transactionHash":"0x6d70a0b14e2fe1ba28d6cb910ffc4aa787264dff6c273e20509136461ac587aa","transactionIndex":"0x4","blockHash":"0x49e3ef5a17eb5563b327fffdf315dd9269c5a5676eec1f5c15897c4ef61623df","logIndex":"0x2b","removed":false}`
uniswapV3TxTestData = `{"type":"0x2","nonce":"0x41","gasPrice":"0x0","maxPriorityFeePerGas":"0x3b9aca00","maxFeePerGas":"0x92abb2610","gas":"0x34389","value":"0x1f161421c8e0000","input":"0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000643e278300000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000001f161421c8e00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000001f161421c8e000000000000000000000000000000000000000000000002488dd50cfbb0a2a15abb00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc20027105026f006b85729a8b14553fae6af249ad16c9aab000000000000000000000000000000000000000000","v":"0x1","r":"0x4fca68a439e7f841bdbe6d108bebd3d4c405f739cae203e61422152c4a0a057c","s":"0x597bd6d3848d31357207df1f92df77580310b7ad31f178575f0dae7f36934b39","to":"0xef1c6e67703c7bd7107eed8303fbe6ec2554bf6b","chainId":"0x1","accessList":[],"hash":"0x5c5bca1291d1f09c07a9b66e56e78cc23da41b3e69e330dcd46a71ef6176df8b"}`
uniswapV3ReceiptTestData = `{"type":"0x2","root":"0x","status":"0x1","cumulativeGasUsed":"0x6c1b8a","logsBloom":"0x00000000000000000000000000400000000000000000000200000000000000000000000000000000000000000000000002000000080020000000000200000000000004000000000800000028000000000000000000000000240000008000000000000000000000800000000000000000000000000000000000000010000800000000000000000000000000080000000000000001000000000000000000000000000800000000000000000000000000000000000000000000000000000800002000000002000000000000000000000000400000000000000000000000000000000000200000000000000000000000000000000400000000400000000080000000","logs":[{"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","topics":["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c","0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"],"data":"0x00000000000000000000000000000000000000000000000001f161421c8e0000","blockNumber":"0x1047cc4","transactionHash":"0x5c5bca1291d1f09c07a9b66e56e78cc23da41b3e69e330dcd46a71ef6176df8b","transactionIndex":"0x4a","blockHash":"0x95c685d5165471e878aea2aaaa719bf4357cdbcd22722df4338e3e54f4e6c5d5","logIndex":"0xd8","removed":false},{"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b","0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"],"data":"0x00000000000000000000000000000000000000000000000001f161421c8e0000","blockNumber":"0x1047cc4","transactionHash":"0x5c5bca1291d1f09c07a9b66e56e78cc23da41b3e69e330dcd46a71ef6176df8b","transactionIndex":"0x4a","blockHash":"0x95c685d5165471e878aea2aaaa719bf4357cdbcd22722df4338e3e54f4e6c5d5","logIndex":"0xd9","removed":false},{"address":"0x5026f006b85729a8b14553fae6af249ad16c9aab","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000007316f8dd242974f0fd7b16dbcc68920b96bc4db1","0x000000000000000000000000165eeecc32dcb623f51fc6c1ddd9e2aea1575c63"],"data":"0x000000000000000000000000000000000000000000024cc783fc216d1e77f90d","blockNumber":"0x1047cc4","transactionHash":"0x5c5bca1291d1f09c07a9b66e56e78cc23da41b3e69e330dcd46a71ef6176df8b","transactionIndex":"0x4a","blockHash":"0x95c685d5165471e878aea2aaaa719bf4357cdbcd22722df4338e3e54f4e6c5d5","logIndex":"0xda","removed":false},{"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b","0x0000000000000000000000007316f8dd242974f0fd7b16dbcc68920b96bc4db1"],"data":"0x00000000000000000000000000000000000000000000000001f161421c8e0000","blockNumber":"0x1047cc4","transactionHash":"0x5c5bca1291d1f09c07a9b66e56e78cc23da41b3e69e330dcd46a71ef6176df8b","transactionIndex":"0x4a","blockHash":"0x95c685d5165471e878aea2aaaa719bf4357cdbcd22722df4338e3e54f4e6c5d5","logIndex":"0xdb","removed":false},{"address":"0x7316f8dd242974f0fd7b16dbcc68920b96bc4db1","topics":["0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67","0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b","0x000000000000000000000000165eeecc32dcb623f51fc6c1ddd9e2aea1575c63"],"data":"0xfffffffffffffffffffffffffffffffffffffffffffdb3387c03de92e18806f300000000000000000000000000000000000000000000000001f161421c8e00000000000000000000000000000000000000000000000ea9ed3658a1ccb7e6d1cc000000000000000000000000000000000000000000001e5ab304463cab4cd155fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6f54","blockNumber":"0x1047cc4","transactionHash":"0x5c5bca1291d1f09c07a9b66e56e78cc23da41b3e69e330dcd46a71ef6176df8b","transactionIndex":"0x4a","blockHash":"0x95c685d5165471e878aea2aaaa719bf4357cdbcd22722df4338e3e54f4e6c5d5","logIndex":"0xdc","removed":false}],"transactionHash":"0x5c5bca1291d1f09c07a9b66e56e78cc23da41b3e69e330dcd46a71ef6176df8b","contractAddress":"0x0000000000000000000000000000000000000000","gasUsed":"0x22478","blockHash":"0x95c685d5165471e878aea2aaaa719bf4357cdbcd22722df4338e3e54f4e6c5d5","blockNumber":"0x1047cc4","transactionIndex":"0x4a"}`
uniswapV3LogTestData = `{"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","topics":["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c","0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"],"data":"0x00000000000000000000000000000000000000000000000001f161421c8e0000","blockNumber":"0x1047cc4","transactionHash":"0x5c5bca1291d1f09c07a9b66e56e78cc23da41b3e69e330dcd46a71ef6176df8b","transactionIndex":"0x4a","blockHash":"0x95c685d5165471e878aea2aaaa719bf4357cdbcd22722df4338e3e54f4e6c5d5","logIndex":"0xd8","removed":false}`
)
func TestMigrateWalletJsonBlobs(t *testing.T) {
openDB := func() (*sql.DB, error) {
return sqlite.OpenDB(sqlite.InMemoryPath, "1234567890", sqlite.ReducedKDFIterationsNumber)
}
db, err := openDB()
require.NoError(t, err)
// Execute the old migrations
err = migrationsprevnodecfg.Migrate(db)
require.NoError(t, err)
err = nodecfg.MigrateNodeConfig(db)
require.NoError(t, err)
// Migrate until 1682393575_sync_ens_name.up
err = migrations.MigrateTo(db, customSteps, 1682393575)
require.NoError(t, err)
// Validate that transfers table has no status column
exists, err := ColumnExists(db, "transfers", "status")
require.NoError(t, err)
require.False(t, exists)
exists, err = ColumnExists(db, "transfers", "status")
require.NoError(t, err)
require.False(t, exists)
insertTestTransaction := func(index int, txBlob string, receiptBlob string, logBlob string, ethType bool) error {
indexStr := strconv.Itoa(index)
var txValue *string
if txBlob != "" {
txValue = &txBlob
}
var receiptValue *string
if receiptBlob != "" {
receiptValue = &receiptBlob
}
var logValue *string
if logBlob != "" {
logValue = &logBlob
}
entryType := "eth"
if !ethType {
entryType = "erc20"
}
_, err = db.Exec(`INSERT OR IGNORE INTO blocks(network_id, address, blk_number, blk_hash) VALUES (?, ?, ?, ?);
INSERT INTO transfers (hash, address, network_id, tx, receipt, log, blk_hash, type, blk_number, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
index, common.HexToAddress(indexStr), index, common.HexToHash(indexStr),
common.HexToHash(indexStr), common.HexToAddress(indexStr), index, txValue, receiptValue, logValue, common.HexToHash(indexStr), entryType, index, index)
return err
}
// Empty transaction, found the usecase in the test DB
err = insertTestTransaction(1, "", "", "", true)
require.NoError(t, err)
erc20FailReceiptJSON := fmt.Sprintf(erc20ReceiptTestDataTemplate, 0)
erc20SuccessReceiptJSON := fmt.Sprintf(erc20ReceiptTestDataTemplate, 1)
err = insertTestTransaction(2, erc20TxTestData, erc20FailReceiptJSON, erc20LogTestData, false)
require.NoError(t, err)
err = insertTestTransaction(3, erc20TxTestData, erc20SuccessReceiptJSON, erc20LogTestData, false)
require.NoError(t, err)
err = insertTestTransaction(4, erc721TxTestData, erc721ReceiptTestData, erc721LogTestData, false)
require.NoError(t, err)
ethZeroValueTxTestData := fmt.Sprintf(ethTxTestData, "0")
ethVeryBigValueTxTestData := fmt.Sprintf(ethTxTestData, "12345678901234567890")
ethOriginalTxTestData := fmt.Sprintf(ethTxTestData, "2386f26fc10000")
err = insertTestTransaction(5, ethZeroValueTxTestData, ethReceiptTestData, "", true)
require.NoError(t, err)
err = insertTestTransaction(6, ethVeryBigValueTxTestData, "", "", true)
require.NoError(t, err)
err = insertTestTransaction(7, ethOriginalTxTestData, ethReceiptTestData, "", true)
require.NoError(t, err)
err = insertTestTransaction(8, uniswapV2TxTestData, uniswapV2ReceiptTestData, uniswapV2LogTestData, false)
require.NoError(t, err)
err = insertTestTransaction(9, uniswapV3TxTestData, uniswapV3ReceiptTestData, uniswapV3LogTestData, false)
require.NoError(t, err)
failMigrationSteps := []sqlite.PostStep{
{
Version: customSteps[1].Version,
CustomMigration: func(sqlTx *sql.Tx) error {
return errors.New("failed to run custom migration")
},
RollBackVersion: customSteps[1].RollBackVersion,
},
}
// Attempt to run test migration 1686048341 and fail in custom step
err = migrations.MigrateTo(db, failMigrationSteps, customSteps[1].Version)
require.Error(t, err)
exists, err = ColumnExists(db, "transfers", "status")
require.NoError(t, err)
require.False(t, exists)
// Run test migration 1686048341_transfers_receipt_json_blob_out.<up/down>.sql
err = migrations.MigrateTo(db, customSteps, customSteps[1].Version)
require.NoError(t, err)
// Validate that the migration was run and transfers table has now status column
exists, err = ColumnExists(db, "transfers", "status")
require.NoError(t, err)
require.True(t, exists)
var (
status, receiptType, cumulativeGasUsed, gasUsed, txIndex sql.NullInt64
gasLimit, gasPriceClamped64, gasTipCapClamped64 sql.NullInt64
gasFeeCapClamped64, accountNonce, size, logIndex, txType sql.NullInt64
protected sql.NullBool
dbContractAddress, amount128Hex sql.NullString
contractAddress, tokenAddress common.Address
txHash, blockHash []byte
entryType string
isTokenIDNull bool
)
dbTokenAddress := sqlite.JSONBlob{Data: &tokenAddress}
tokenID := new(big.Int)
rows, err := db.Query(`SELECT status, receipt_type, tx_hash, log_index, block_hash, cumulative_gas_used, contract_address, gas_used, tx_index,
tx_type, protected, gas_limit, gas_price_clamped64, gas_tip_cap_clamped64, gas_fee_cap_clamped64, amount_padded128hex, account_nonce, size, token_address, token_id, type,
CASE
WHEN token_id IS NULL THEN 1
ELSE 0
END as token_id_status
FROM transfers ORDER BY timestamp ASC`)
require.NoError(t, err)
scanNextData := func() error {
rows.Next()
if rows.Err() != nil {
return rows.Err()
}
err := rows.Scan(&status, &receiptType, &txHash, &logIndex, &blockHash, &cumulativeGasUsed, &dbContractAddress, &gasUsed, &txIndex,
&txType, &protected, &gasLimit, &gasPriceClamped64, &gasTipCapClamped64, &gasFeeCapClamped64, &amount128Hex, &accountNonce, &size, &dbTokenAddress, (*bigint.SQLBigIntBytes)(tokenID), &entryType, &isTokenIDNull)
if err != nil {
return err
}
if dbContractAddress.Valid {
contractAddress = common.HexToAddress(dbContractAddress.String)
}
return nil
}
validateTransaction := func(tt *types.Transaction, expectedEntryType w_common.Type, tl *types.Log) {
if tt == nil {
require.False(t, txType.Valid)
require.False(t, protected.Valid)
require.False(t, gasLimit.Valid)
require.False(t, gasPriceClamped64.Valid)
require.False(t, gasTipCapClamped64.Valid)
require.False(t, gasFeeCapClamped64.Valid)
require.False(t, amount128Hex.Valid)
require.False(t, accountNonce.Valid)
require.False(t, size.Valid)
require.Equal(t, common.Address{}, tokenAddress)
require.True(t, isTokenIDNull)
require.Equal(t, string(w_common.EthTransfer), entryType)
} else {
require.True(t, txType.Valid)
require.Equal(t, tt.Type(), uint8(txType.Int64))
require.True(t, protected.Valid)
require.Equal(t, tt.Protected(), protected.Bool)
require.True(t, gasLimit.Valid)
require.Equal(t, tt.Gas(), uint64(gasLimit.Int64))
require.True(t, gasPriceClamped64.Valid)
require.Equal(t, *sqlite.BigIntToClampedInt64(tt.GasPrice()), gasPriceClamped64.Int64)
require.True(t, gasTipCapClamped64.Valid)
require.Equal(t, *sqlite.BigIntToClampedInt64(tt.GasTipCap()), gasTipCapClamped64.Int64)
require.True(t, gasFeeCapClamped64.Valid)
require.Equal(t, *sqlite.BigIntToClampedInt64(tt.GasFeeCap()), gasFeeCapClamped64.Int64)
require.True(t, accountNonce.Valid)
require.Equal(t, tt.Nonce(), uint64(accountNonce.Int64))
require.True(t, size.Valid)
require.Equal(t, int64(tt.Size()), size.Int64)
if expectedEntryType == w_common.EthTransfer {
require.True(t, amount128Hex.Valid)
require.Equal(t, *sqlite.BigIntToPadded128BitsStr(tt.Value()), amount128Hex.String)
require.False(t, dbTokenAddress.Valid)
require.True(t, isTokenIDNull)
} else {
actualEntryType, expectedTokenAddress, expectedTokenID, expectedValue := w_common.ExtractTokenIdentity(expectedEntryType, tl, tt)
if actualEntryType == w_common.Erc20Transfer {
require.True(t, amount128Hex.Valid)
require.Equal(t, *sqlite.BigIntToPadded128BitsStr(expectedValue), amount128Hex.String)
require.True(t, isTokenIDNull)
require.True(t, dbTokenAddress.Valid)
require.Equal(t, *expectedTokenAddress, tokenAddress)
} else if actualEntryType == w_common.Erc721Transfer {
require.False(t, amount128Hex.Valid)
require.False(t, isTokenIDNull)
require.Equal(t, expectedTokenID, expectedTokenID)
require.True(t, dbTokenAddress.Valid)
require.Equal(t, *expectedTokenAddress, tokenAddress)
} else {
require.False(t, amount128Hex.Valid)
require.True(t, isTokenIDNull)
require.False(t, dbTokenAddress.Valid)
}
require.Equal(t, expectedEntryType, actualEntryType)
}
}
}
validateReceipt := func(tr *types.Receipt, tl *types.Log) {
if tr == nil {
require.False(t, status.Valid)
require.False(t, receiptType.Valid)
require.Equal(t, []byte(nil), txHash)
require.Equal(t, []byte(nil), blockHash)
require.False(t, cumulativeGasUsed.Valid)
require.Equal(t, common.Address{}, contractAddress)
require.False(t, gasUsed.Valid)
require.False(t, txIndex.Valid)
} else {
require.True(t, status.Valid)
require.Equal(t, tr.Status, uint64(status.Int64))
require.True(t, receiptType.Valid)
require.Equal(t, int64(tr.Type), receiptType.Int64)
require.Equal(t, tr.TxHash, common.BytesToHash(txHash))
require.Equal(t, tr.BlockHash, common.BytesToHash(blockHash))
require.True(t, cumulativeGasUsed.Valid)
require.Equal(t, int64(tr.CumulativeGasUsed), cumulativeGasUsed.Int64)
require.Equal(t, tr.ContractAddress, contractAddress)
require.True(t, gasUsed.Valid)
require.Equal(t, int64(tr.GasUsed), gasUsed.Int64)
require.True(t, txIndex.Valid)
require.Equal(t, int64(tr.TransactionIndex), txIndex.Int64)
}
if tl == nil {
require.False(t, logIndex.Valid)
} else {
require.True(t, logIndex.Valid)
require.Equal(t, uint(logIndex.Int64), tl.Index)
}
}
err = scanNextData()
require.NoError(t, err)
validateTransaction(nil, w_common.EthTransfer, nil)
validateReceipt(nil, nil)
var successReceipt types.Receipt
err = json.Unmarshal([]byte(erc20SuccessReceiptJSON), &successReceipt)
require.NoError(t, err)
var failReceipt types.Receipt
err = json.Unmarshal([]byte(erc20FailReceiptJSON), &failReceipt)
require.NoError(t, err)
var erc20Log types.Log
err = json.Unmarshal([]byte(erc20LogTestData), &erc20Log)
require.NoError(t, err)
var erc20Tx types.Transaction
err = json.Unmarshal([]byte(erc20TxTestData), &erc20Tx)
require.NoError(t, err)
err = scanNextData()
require.NoError(t, err)
validateTransaction(&erc20Tx, w_common.Erc20Transfer, &erc20Log)
validateReceipt(&failReceipt, &erc20Log)
err = scanNextData()
require.NoError(t, err)
validateTransaction(&erc20Tx, w_common.Erc20Transfer, &erc20Log)
validateReceipt(&successReceipt, &erc20Log)
var erc721Receipt types.Receipt
err = json.Unmarshal([]byte(erc721ReceiptTestData), &erc721Receipt)
require.NoError(t, err)
var erc721Log types.Log
err = json.Unmarshal([]byte(erc721LogTestData), &erc721Log)
require.NoError(t, err)
var erc721Tx types.Transaction
err = json.Unmarshal([]byte(erc721TxTestData), &erc721Tx)
require.NoError(t, err)
err = scanNextData()
require.NoError(t, err)
validateTransaction(&erc721Tx, w_common.Erc721Transfer, &erc721Log)
validateReceipt(&erc721Receipt, &erc721Log)
var zeroTestTx types.Transaction
err = json.Unmarshal([]byte(ethZeroValueTxTestData), &zeroTestTx)
require.NoError(t, err)
var ethReceipt types.Receipt
err = json.Unmarshal([]byte(ethReceiptTestData), &ethReceipt)
require.NoError(t, err)
err = scanNextData()
require.NoError(t, err)
validateTransaction(&zeroTestTx, w_common.EthTransfer, nil)
validateReceipt(&ethReceipt, nil)
var bigTestTx types.Transaction
err = json.Unmarshal([]byte(ethVeryBigValueTxTestData), &bigTestTx)
require.NoError(t, err)
err = scanNextData()
require.NoError(t, err)
validateTransaction(&bigTestTx, w_common.EthTransfer, nil)
validateReceipt(nil, nil)
var ethOriginalTestTx types.Transaction
err = json.Unmarshal([]byte(ethOriginalTxTestData), &ethOriginalTestTx)
require.NoError(t, err)
err = scanNextData()
require.NoError(t, err)
validateTransaction(&ethOriginalTestTx, w_common.EthTransfer, nil)
validateReceipt(&ethReceipt, nil)
var uniswapV2Receipt types.Receipt
err = json.Unmarshal([]byte(uniswapV2ReceiptTestData), &uniswapV2Receipt)
require.NoError(t, err)
var uniswapV2Log types.Log
err = json.Unmarshal([]byte(uniswapV2LogTestData), &uniswapV2Log)
require.NoError(t, err)
var uniswapV2Tx types.Transaction
err = json.Unmarshal([]byte(uniswapV2TxTestData), &uniswapV2Tx)
require.NoError(t, err)
var uniswapV3Receipt types.Receipt
err = json.Unmarshal([]byte(uniswapV3ReceiptTestData), &uniswapV3Receipt)
require.NoError(t, err)
var uniswapV3Log types.Log
err = json.Unmarshal([]byte(uniswapV3LogTestData), &uniswapV3Log)
require.NoError(t, err)
var uniswapV3Tx types.Transaction
err = json.Unmarshal([]byte(uniswapV3TxTestData), &uniswapV3Tx)
require.NoError(t, err)
err = scanNextData()
require.NoError(t, err)
validateTransaction(&uniswapV2Tx, w_common.UniswapV2Swap, &uniswapV2Log)
validateReceipt(&uniswapV2Receipt, &uniswapV2Log)
err = scanNextData()
require.NoError(t, err)
validateTransaction(&uniswapV3Tx, w_common.UniswapV3Swap, &uniswapV3Log)
validateReceipt(&uniswapV3Receipt, &uniswapV3Log)
err = scanNextData()
// Validate that we processed all data (no more rows expected)
require.Error(t, err)
db.Close()
}

View File

@ -67,6 +67,8 @@
// 1685463947_add_to_asset_to_multitransaction.up.sql (61B)
// 1685880973_add_profile_links_settings_table.up.sql (1.656kB)
// 1686041510_add_idx_transfers_blkno_loaded.up.sql (71B)
// 1686048341_transfers_receipt_json_blob_out.up.sql.down.sql (104B)
// 1686048341_transfers_receipt_json_blob_out.up.sql.up.sql (1.5kB)
// doc.go (74B)
package migrations
@ -151,7 +153,7 @@ func _1640111208_dummyUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1640111208_dummy.up.sql", size: 258, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1640111208_dummy.up.sql", size: 258, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3e, 0xf0, 0xae, 0x20, 0x6e, 0x75, 0xd1, 0x36, 0x14, 0xf2, 0x40, 0xe5, 0xd6, 0x7a, 0xc4, 0xa5, 0x72, 0xaa, 0xb5, 0x4d, 0x71, 0x97, 0xb8, 0xe8, 0x95, 0x22, 0x95, 0xa2, 0xac, 0xaf, 0x48, 0x58}}
return a, nil
}
@ -171,7 +173,7 @@ func _1642666031_add_removed_clock_to_bookmarksUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1642666031_add_removed_clock_to_bookmarks.up.sql", size: 117, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1642666031_add_removed_clock_to_bookmarks.up.sql", size: 117, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x84, 0x4e, 0x38, 0x99, 0x7a, 0xc, 0x90, 0x13, 0xec, 0xfe, 0x2f, 0x55, 0xff, 0xb7, 0xb6, 0xaa, 0x96, 0xc6, 0x92, 0x79, 0xcc, 0xee, 0x4e, 0x99, 0x53, 0xfe, 0x1c, 0xbb, 0x32, 0x2, 0xa4, 0x27}}
return a, nil
}
@ -191,7 +193,7 @@ func _1643644541_gif_api_key_settingUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1643644541_gif_api_key_setting.up.sql", size: 108, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1643644541_gif_api_key_setting.up.sql", size: 108, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1b, 0x94, 0x28, 0xfb, 0x66, 0xd1, 0x7c, 0xb8, 0x89, 0xe2, 0xb4, 0x71, 0x65, 0x24, 0x57, 0x22, 0x95, 0x38, 0x97, 0x3, 0x9b, 0xc6, 0xa4, 0x41, 0x7b, 0xba, 0xf7, 0xdb, 0x70, 0xf7, 0x20, 0x3a}}
return a, nil
}
@ -211,7 +213,7 @@ func _1644188994_recent_stickersUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1644188994_recent_stickers.up.sql", size: 79, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1644188994_recent_stickers.up.sql", size: 79, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1e, 0xad, 0xaa, 0x30, 0xbf, 0x4, 0x7, 0xf8, 0xc3, 0x3, 0xb8, 0x97, 0x23, 0x2b, 0xbd, 0x1c, 0x60, 0x69, 0xb0, 0x42, 0x5e, 0x6b, 0xd, 0xa7, 0xa3, 0x6b, 0x2e, 0xdc, 0x70, 0x13, 0x72, 0x7}}
return a, nil
}
@ -231,7 +233,7 @@ func _1646659233_add_address_to_dapp_permisssionUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1646659233_add_address_to_dapp_permisssion.up.sql", size: 700, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1646659233_add_address_to_dapp_permisssion.up.sql", size: 700, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xed, 0xb0, 0x35, 0xcc, 0x2e, 0x16, 0xe6, 0x15, 0x86, 0x2c, 0x37, 0x80, 0xae, 0xa3, 0xc5, 0x31, 0x78, 0x5, 0x9d, 0xcd, 0x7b, 0xeb, 0x5f, 0xf2, 0xb3, 0x74, 0x72, 0xdf, 0xcf, 0x88, 0xb, 0x40}}
return a, nil
}
@ -251,7 +253,7 @@ func _1646841105_add_emoji_accountUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1646841105_add_emoji_account.up.sql", size: 96, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1646841105_add_emoji_account.up.sql", size: 96, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe6, 0x77, 0x29, 0x95, 0x18, 0x64, 0x82, 0x63, 0xe7, 0xaf, 0x6c, 0xa9, 0x15, 0x7d, 0x46, 0xa6, 0xbc, 0xdf, 0xa7, 0xd, 0x2b, 0xd2, 0x2d, 0x97, 0x4d, 0xa, 0x6b, 0xd, 0x6e, 0x90, 0x42, 0x5c}}
return a, nil
}
@ -271,7 +273,7 @@ func _1647278782_display_nameUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1647278782_display_name.up.sql", size: 110, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1647278782_display_name.up.sql", size: 110, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf4, 0xa1, 0x1f, 0x3e, 0x61, 0x65, 0x8d, 0xff, 0xee, 0xde, 0xc5, 0x91, 0xd9, 0x5c, 0xb5, 0xe2, 0xf0, 0xb7, 0xe7, 0x5c, 0x5c, 0x16, 0x25, 0x89, 0xee, 0x78, 0x12, 0xea, 0x3e, 0x48, 0x41, 0xa6}}
return a, nil
}
@ -291,7 +293,7 @@ func _1647862838_reset_last_backupUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1647862838_reset_last_backup.up.sql", size: 37, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1647862838_reset_last_backup.up.sql", size: 37, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x21, 0xe3, 0xd5, 0xf6, 0x5f, 0xfe, 0x65, 0xfa, 0x1d, 0x88, 0xf8, 0x5f, 0x24, 0x71, 0x34, 0x68, 0x96, 0x2a, 0x60, 0x87, 0x15, 0x82, 0x4d, 0x8a, 0x59, 0x3d, 0x1f, 0xd8, 0x56, 0xd4, 0xfb, 0xda}}
return a, nil
}
@ -311,7 +313,7 @@ func _1647871652_add_settings_sync_clock_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1647871652_add_settings_sync_clock_table.up.sql", size: 1044, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1647871652_add_settings_sync_clock_table.up.sql", size: 1044, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd8, 0x58, 0xec, 0x85, 0x90, 0xfa, 0x30, 0x98, 0x98, 0x9a, 0xa6, 0xa8, 0x96, 0x2b, 0x38, 0x93, 0xf3, 0xae, 0x46, 0x74, 0xa4, 0x41, 0x62, 0x9b, 0x2, 0x86, 0xbf, 0xe5, 0x2a, 0xce, 0xe2, 0xc0}}
return a, nil
}
@ -331,7 +333,7 @@ func _1647880168_add_torrent_configUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1647880168_add_torrent_config.up.sql", size: 211, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1647880168_add_torrent_config.up.sql", size: 211, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1, 0x92, 0x22, 0x37, 0x96, 0xf3, 0xb5, 0x5b, 0x27, 0xd0, 0x7d, 0x43, 0x5, 0x4e, 0x9d, 0xe2, 0x49, 0xbe, 0x86, 0x31, 0xa1, 0x89, 0xff, 0xd6, 0x51, 0xe0, 0x9c, 0xb, 0xda, 0xfc, 0xf2, 0x93}}
return a, nil
}
@ -351,7 +353,7 @@ func _1647882837_add_communities_settings_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1647882837_add_communities_settings_table.up.sql", size: 206, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1647882837_add_communities_settings_table.up.sql", size: 206, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xbd, 0x87, 0x78, 0x99, 0xd9, 0x5d, 0xbd, 0xf7, 0x57, 0x9c, 0xca, 0x97, 0xbd, 0xb3, 0xe9, 0xb5, 0x89, 0x31, 0x3f, 0xf6, 0x5c, 0x13, 0xb, 0xc3, 0x54, 0x93, 0x18, 0x40, 0x7, 0x82, 0xfe, 0x7e}}
return a, nil
}
@ -371,7 +373,7 @@ func _1647956635_add_waku_messages_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1647956635_add_waku_messages_table.up.sql", size: 266, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1647956635_add_waku_messages_table.up.sql", size: 266, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd1, 0xe, 0xe1, 0xdc, 0xda, 0x2e, 0x89, 0x8d, 0xdc, 0x2a, 0x1c, 0x13, 0xa1, 0xfc, 0xfe, 0xf, 0xb2, 0xb9, 0x85, 0xc8, 0x45, 0xd6, 0xd1, 0x7, 0x5c, 0xa3, 0x8, 0x47, 0x44, 0x6d, 0x96, 0xe0}}
return a, nil
}
@ -391,7 +393,7 @@ func _1648554928_network_testUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1648554928_network_test.up.sql", size: 132, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1648554928_network_test.up.sql", size: 132, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x9a, 0xc5, 0x7f, 0x87, 0xf3, 0x2c, 0xf7, 0xbb, 0xd3, 0x3a, 0x4e, 0x76, 0x88, 0xca, 0xaf, 0x73, 0xce, 0x8f, 0xa1, 0xf6, 0x3d, 0x4d, 0xed, 0x6f, 0x49, 0xf2, 0xfe, 0x56, 0x2a, 0x60, 0x68, 0xca}}
return a, nil
}
@ -411,7 +413,7 @@ func _1649174829_add_visitble_tokenUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1649174829_add_visitble_token.up.sql", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1649174829_add_visitble_token.up.sql", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa3, 0x22, 0xc0, 0x2b, 0x3f, 0x4f, 0x3d, 0x5e, 0x4c, 0x68, 0x7c, 0xd0, 0x15, 0x36, 0x9f, 0xec, 0xa1, 0x2a, 0x7b, 0xb4, 0xe3, 0xc6, 0xc9, 0xb4, 0x81, 0x50, 0x4a, 0x11, 0x3b, 0x35, 0x7, 0xcf}}
return a, nil
}
@ -431,7 +433,7 @@ func _1649882262_add_derived_from_accountsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1649882262_add_derived_from_accounts.up.sql", size: 110, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1649882262_add_derived_from_accounts.up.sql", size: 110, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x11, 0xb9, 0x44, 0x4d, 0x85, 0x8d, 0x7f, 0xb4, 0xae, 0x4f, 0x5c, 0x66, 0x64, 0xb6, 0xe2, 0xe, 0x3d, 0xad, 0x9d, 0x8, 0x4f, 0xab, 0x6e, 0xa8, 0x7d, 0x76, 0x3, 0xad, 0x96, 0x1, 0xee, 0x5c}}
return a, nil
}
@ -451,7 +453,7 @@ func _1650612625_add_community_message_archive_hashes_tableUpSql() (*asset, erro
return nil, err
}
info := bindataFileInfo{name: "1650612625_add_community_message_archive_hashes_table.up.sql", size: 130, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1650612625_add_community_message_archive_hashes_table.up.sql", size: 130, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x48, 0x31, 0xb3, 0x75, 0x23, 0xe2, 0x45, 0xe, 0x47, 0x1b, 0x35, 0xa5, 0x6e, 0x83, 0x4e, 0x64, 0x7d, 0xd7, 0xa2, 0xda, 0xe9, 0x53, 0xf1, 0x16, 0x86, 0x2c, 0x57, 0xad, 0xfa, 0xca, 0x39, 0xde}}
return a, nil
}
@ -471,7 +473,7 @@ func _1650616788_add_communities_archives_info_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1650616788_add_communities_archives_info_table.up.sql", size: 208, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1650616788_add_communities_archives_info_table.up.sql", size: 208, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd1, 0x4f, 0x80, 0x45, 0xb9, 0xd9, 0x15, 0xe2, 0x78, 0xd0, 0xcb, 0x71, 0xc1, 0x1b, 0xb7, 0x1b, 0x1b, 0x97, 0xfe, 0x47, 0x53, 0x3c, 0x62, 0xbc, 0xdd, 0x3a, 0x94, 0x1a, 0xc, 0x48, 0x76, 0xe}}
return a, nil
}
@ -491,7 +493,7 @@ func _1652715604_add_clock_accountsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1652715604_add_clock_accounts.up.sql", size: 62, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1652715604_add_clock_accounts.up.sql", size: 62, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb6, 0xd9, 0x8d, 0x73, 0xc9, 0xef, 0xfa, 0xb1, 0x4b, 0xa5, 0xf3, 0x5, 0x19, 0x26, 0x46, 0xf8, 0x47, 0x93, 0xdb, 0xac, 0x2, 0xef, 0xf9, 0x71, 0x56, 0x83, 0xe6, 0x2d, 0xb0, 0xd7, 0x83, 0x5c}}
return a, nil
}
@ -511,7 +513,7 @@ func _1653037334_add_notifications_settings_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1653037334_add_notifications_settings_table.up.sql", size: 1276, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1653037334_add_notifications_settings_table.up.sql", size: 1276, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4b, 0xc4, 0x65, 0xac, 0xa, 0xf2, 0xef, 0xb6, 0x39, 0x3c, 0xc5, 0xb1, 0xb2, 0x9c, 0x86, 0x58, 0xe0, 0x38, 0xcb, 0x57, 0x3c, 0x76, 0x73, 0x87, 0x79, 0x4e, 0xf6, 0xed, 0xb0, 0x8e, 0x9e, 0xa}}
return a, nil
}
@ -531,7 +533,7 @@ func _1654702119_add_mutual_contact_settingsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1654702119_add_mutual_contact_settings.up.sql", size: 78, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1654702119_add_mutual_contact_settings.up.sql", size: 78, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x26, 0x66, 0x67, 0x50, 0xfe, 0xd7, 0xe3, 0x29, 0x8b, 0xff, 0x9d, 0x5a, 0x87, 0xa7, 0x99, 0x6e, 0xd6, 0xcd, 0x2e, 0xbb, 0x17, 0xdf, 0x7f, 0xf7, 0xa3, 0xfa, 0x32, 0x7c, 0x2d, 0x92, 0xc8, 0x74}}
return a, nil
}
@ -551,7 +553,7 @@ func _1655375270_add_clock_field_to_communities_settings_tableUpSql() (*asset, e
return nil, err
}
info := bindataFileInfo{name: "1655375270_add_clock_field_to_communities_settings_table.up.sql", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1655375270_add_clock_field_to_communities_settings_table.up.sql", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x19, 0xc5, 0xc0, 0xf9, 0x84, 0x53, 0xdf, 0x83, 0xcf, 0xb6, 0x40, 0x6d, 0xf5, 0xdc, 0x77, 0x37, 0xb7, 0xe3, 0xa, 0x75, 0xe7, 0x6, 0x11, 0xca, 0x2b, 0x51, 0x92, 0xdd, 0x7d, 0xdb, 0xc3, 0xf5}}
return a, nil
}
@ -571,7 +573,7 @@ func _1655385721_drop_networks_configUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1655385721_drop_networks_config.up.sql", size: 27, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1655385721_drop_networks_config.up.sql", size: 27, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfc, 0xa7, 0x20, 0xbb, 0x67, 0x21, 0xe, 0xc6, 0xc8, 0x21, 0x74, 0xe0, 0xce, 0xc8, 0xe2, 0x2, 0xb4, 0xea, 0xf0, 0xe5, 0xc4, 0x4d, 0xdd, 0xd4, 0x52, 0x31, 0xa9, 0x3d, 0xcd, 0xd8, 0x9b, 0xab}}
return a, nil
}
@ -591,7 +593,7 @@ func _1655385724_networks_chaincolor_shortnameUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1655385724_networks_chainColor_shortName.up.sql", size: 220, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1655385724_networks_chainColor_shortName.up.sql", size: 220, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd9, 0xe7, 0x84, 0xbb, 0x5f, 0xd2, 0x2c, 0x42, 0x88, 0x62, 0x52, 0xb6, 0x58, 0x31, 0xac, 0xc, 0x96, 0x2b, 0x1b, 0xe5, 0x4e, 0x9a, 0x3a, 0xf6, 0xf6, 0xfc, 0xa9, 0x1a, 0x35, 0x62, 0x28, 0x88}}
return a, nil
}
@ -611,7 +613,7 @@ func _1655456688_add_deleted_at_field_to_bookmarks_tableUpSql() (*asset, error)
return nil, err
}
info := bindataFileInfo{name: "1655456688_add_deleted_at_field_to_bookmarks_table.up.sql", size: 69, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1655456688_add_deleted_at_field_to_bookmarks_table.up.sql", size: 69, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe7, 0x9a, 0xbd, 0x9a, 0xc9, 0xf, 0xdf, 0x90, 0x0, 0x5d, 0xea, 0x6e, 0x7d, 0x51, 0x95, 0xcd, 0x90, 0xd3, 0x1a, 0x36, 0x6c, 0xf4, 0xbd, 0xa7, 0x6b, 0xbf, 0xe5, 0xdb, 0xa3, 0x88, 0xe3, 0x50}}
return a, nil
}
@ -631,7 +633,7 @@ func _1655462032_create_bookmarks_deleted_at_indexUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1655462032_create_bookmarks_deleted_at_index.up.sql", size: 81, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1655462032_create_bookmarks_deleted_at_index.up.sql", size: 81, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf, 0x8e, 0x20, 0x6b, 0x14, 0x9e, 0xcd, 0x97, 0xd3, 0xfe, 0x62, 0x3, 0x26, 0x59, 0x1, 0x6c, 0x99, 0xef, 0x6d, 0x21, 0xd4, 0xb5, 0xa3, 0xf4, 0x39, 0x40, 0x54, 0x6, 0xd, 0x60, 0x13, 0x38}}
return a, nil
}
@ -651,7 +653,7 @@ func _1657617291_add_multi_transactions_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1657617291_add_multi_transactions_table.up.sql", size: 412, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1657617291_add_multi_transactions_table.up.sql", size: 412, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x86, 0xb0, 0x4e, 0x8c, 0x4, 0x82, 0xb4, 0x43, 0xaa, 0xd0, 0x16, 0xdd, 0xcb, 0x88, 0x81, 0xac, 0x4, 0x34, 0x1a, 0x8f, 0x2e, 0xc5, 0x69, 0xb, 0xf0, 0x17, 0xf7, 0xe3, 0x9, 0xe, 0x54, 0xe0}}
return a, nil
}
@ -671,7 +673,7 @@ func _1660134042_add_social_links_settings_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1660134042_add_social_links_settings_table.up.sql", size: 334, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1660134042_add_social_links_settings_table.up.sql", size: 334, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x84, 0x73, 0xb6, 0xe7, 0x3f, 0xaa, 0x39, 0x9a, 0x56, 0x56, 0x31, 0xf1, 0x8e, 0x26, 0x23, 0x1, 0xe4, 0xfa, 0x98, 0xfe, 0x78, 0x87, 0x20, 0xcb, 0x52, 0xf4, 0x38, 0x7f, 0xc4, 0x1c, 0x4, 0x22}}
return a, nil
}
@ -691,7 +693,7 @@ func _1660134060_settings_bioUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1660134060_settings_bio.up.sql", size: 91, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1660134060_settings_bio.up.sql", size: 91, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x46, 0x25, 0xa0, 0xa6, 0x47, 0xff, 0xbc, 0x2a, 0x0, 0xff, 0x59, 0x4b, 0xb0, 0xc9, 0x4e, 0x15, 0xe4, 0xd9, 0xda, 0xeb, 0xfe, 0x55, 0x98, 0xc3, 0x9d, 0x96, 0xe7, 0xf, 0xd1, 0x5c, 0x93, 0x73}}
return a, nil
}
@ -711,7 +713,7 @@ func _1660134070_add_wakuv2_storeUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1660134070_add_wakuv2_store.up.sql", size: 269, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1660134070_add_wakuv2_store.up.sql", size: 269, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1d, 0xe6, 0xc3, 0x9, 0xef, 0xdc, 0xae, 0x49, 0x30, 0x78, 0x54, 0xd6, 0xdb, 0xbf, 0xc0, 0x8e, 0x25, 0x8f, 0xfc, 0x67, 0x80, 0x39, 0x37, 0xd4, 0x86, 0xc1, 0x85, 0xc8, 0x99, 0xc4, 0x59, 0xd4}}
return a, nil
}
@ -731,7 +733,7 @@ func _1660134072_waku2_store_messagesUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1660134072_waku2_store_messages.up.sql", size: 497, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1660134072_waku2_store_messages.up.sql", size: 497, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3e, 0xeb, 0xb4, 0xa0, 0xa1, 0x2b, 0xcb, 0x4c, 0x3c, 0xc6, 0xd0, 0xe8, 0x96, 0xe3, 0x96, 0xf1, 0x4f, 0x1f, 0xe0, 0xe7, 0x1f, 0x85, 0xa3, 0xe, 0xf7, 0x52, 0x56, 0x63, 0x2b, 0xb0, 0x87, 0x7b}}
return a, nil
}
@ -751,7 +753,7 @@ func _1662365868_add_key_uid_accountsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1662365868_add_key_uid_accounts.up.sql", size: 68, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1662365868_add_key_uid_accounts.up.sql", size: 68, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc6, 0xd8, 0x2f, 0x2f, 0x3b, 0xa8, 0xbd, 0x6d, 0xf6, 0x87, 0x7e, 0xd2, 0xf1, 0xa2, 0xf7, 0x81, 0x6a, 0x23, 0x10, 0xbc, 0xbf, 0x5b, 0xe7, 0x2b, 0x9c, 0xa9, 0x8a, 0x18, 0xbb, 0xd0, 0x86, 0x91}}
return a, nil
}
@ -771,7 +773,7 @@ func _1662447680_add_keypairs_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1662447680_add_keypairs_table.up.sql", size: 218, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1662447680_add_keypairs_table.up.sql", size: 218, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xdc, 0x25, 0xa9, 0xc7, 0x63, 0x27, 0x97, 0x35, 0x5f, 0x6b, 0xab, 0x26, 0xcb, 0xf9, 0xbd, 0x5e, 0xac, 0x3, 0xa0, 0x5e, 0xb9, 0x71, 0xa3, 0x1f, 0xb3, 0x4f, 0x7f, 0x79, 0x28, 0x48, 0xbe, 0xc}}
return a, nil
}
@ -791,7 +793,7 @@ func _1662460056_move_favourites_to_saved_addressesUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1662460056_move_favourites_to_saved_addresses.up.sql", size: 233, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1662460056_move_favourites_to_saved_addresses.up.sql", size: 233, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x10, 0xa2, 0x8c, 0xa3, 0xec, 0xad, 0xdf, 0xc3, 0x48, 0x5, 0x9b, 0x50, 0x25, 0x59, 0xae, 0x7d, 0xee, 0x58, 0xd2, 0x41, 0x27, 0xf2, 0x22, 0x2e, 0x9a, 0xb9, 0x4a, 0xcc, 0x38, 0x6e, 0x3a, 0xb2}}
return a, nil
}
@ -811,7 +813,7 @@ func _1662738097_add_base_fee_transactionUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1662738097_add_base_fee_transaction.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1662738097_add_base_fee_transaction.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6b, 0xfb, 0x10, 0xae, 0xfc, 0x77, 0x70, 0x98, 0x6f, 0xec, 0xaa, 0xcd, 0x7, 0xc7, 0x74, 0x23, 0xc, 0xd5, 0x1e, 0x82, 0xdd, 0xfe, 0xff, 0x3b, 0xd2, 0x49, 0x10, 0x5b, 0x30, 0xc, 0x2d, 0xb0}}
return a, nil
}
@ -831,7 +833,7 @@ func _1662972194_add_keypairs_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1662972194_add_keypairs_table.up.sql", size: 345, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1662972194_add_keypairs_table.up.sql", size: 345, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xab, 0x76, 0xf2, 0x86, 0xe1, 0x7e, 0xe9, 0x47, 0x32, 0x48, 0xd5, 0x6b, 0xe5, 0xd, 0xab, 0xb7, 0xf1, 0xd4, 0xf1, 0xad, 0x38, 0xa6, 0x11, 0xe7, 0xce, 0x5c, 0x11, 0x11, 0xf, 0x47, 0xb2, 0x4}}
return a, nil
}
@ -851,7 +853,7 @@ func _1664392661_add_third_party_id_to_waku_messagesUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1664392661_add_third_party_id_to_waku_messages.up.sql", size: 70, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1664392661_add_third_party_id_to_waku_messages.up.sql", size: 70, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfd, 0x67, 0x66, 0x9e, 0x66, 0x74, 0xce, 0x1c, 0xb, 0x1b, 0x9d, 0xd5, 0xfc, 0x65, 0xe, 0x83, 0x90, 0x4c, 0x61, 0x4e, 0x6b, 0xe7, 0x86, 0xbe, 0x36, 0x4f, 0x91, 0x36, 0x4, 0x47, 0x7b, 0x82}}
return a, nil
}
@ -871,7 +873,7 @@ func _1664783660_add_sync_info_to_saved_addressesUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1664783660_add_sync_info_to_saved_addresses.up.sql", size: 388, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1664783660_add_sync_info_to_saved_addresses.up.sql", size: 388, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x67, 0x7c, 0x3a, 0x95, 0x4e, 0x55, 0xb2, 0xbd, 0xb4, 0x18, 0x93, 0xc1, 0xcf, 0x9f, 0x12, 0xbb, 0x49, 0x8a, 0x2a, 0x6a, 0x2a, 0x7f, 0xad, 0x44, 0xc3, 0xf, 0x3a, 0x79, 0x18, 0xb9, 0x4c, 0x64}}
return a, nil
}
@ -891,7 +893,7 @@ func _1668109917_wakunodesUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1668109917_wakunodes.up.sql", size: 99, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1668109917_wakunodes.up.sql", size: 99, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x29, 0xaa, 0x9e, 0x2, 0x66, 0x85, 0x69, 0xa8, 0xd9, 0xe2, 0x4b, 0x8d, 0x2a, 0x9c, 0xdf, 0xd2, 0xef, 0x64, 0x58, 0xe3, 0xa6, 0xe7, 0xc1, 0xd1, 0xc8, 0x9c, 0xc0, 0x2c, 0x1, 0xa8, 0x7b, 0x81}}
return a, nil
}
@ -911,7 +913,7 @@ func _1670249678_display_name_to_settings_sync_clock_tableUpSql() (*asset, error
return nil, err
}
info := bindataFileInfo{name: "1670249678_display_name_to_settings_sync_clock_table.up.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1670249678_display_name_to_settings_sync_clock_table.up.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x39, 0x18, 0xdc, 0xc4, 0x1f, 0x79, 0x22, 0x16, 0x4d, 0xdf, 0x6c, 0x66, 0xd5, 0xa4, 0x88, 0x5d, 0x5, 0x37, 0xa7, 0x41, 0x5, 0x50, 0xae, 0x12, 0xfa, 0x7e, 0x89, 0x24, 0x5c, 0xae, 0x30, 0xfc}}
return a, nil
}
@ -931,7 +933,7 @@ func _1670836810_add_imported_flag_to_community_archive_hashesUpSql() (*asset, e
return nil, err
}
info := bindataFileInfo{name: "1670836810_add_imported_flag_to_community_archive_hashes.up.sql", size: 144, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1670836810_add_imported_flag_to_community_archive_hashes.up.sql", size: 144, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6f, 0xf, 0xf0, 0xbd, 0xfe, 0x63, 0x25, 0x8f, 0x5e, 0x46, 0x4b, 0x45, 0x31, 0x8b, 0x3e, 0xd8, 0x6b, 0x5d, 0x9d, 0x6d, 0x10, 0x9a, 0x87, 0x4b, 0x18, 0xc6, 0x39, 0x81, 0x6e, 0xe4, 0x75, 0xfb}}
return a, nil
}
@ -951,7 +953,7 @@ func _1671438731_add_magnetlink_uri_to_communities_archive_infoUpSql() (*asset,
return nil, err
}
info := bindataFileInfo{name: "1671438731_add_magnetlink_uri_to_communities_archive_info.up.sql", size: 86, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1671438731_add_magnetlink_uri_to_communities_archive_info.up.sql", size: 86, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xda, 0x8b, 0x4b, 0xd6, 0xd8, 0xe2, 0x3d, 0xf7, 0x6b, 0xcd, 0x1e, 0x70, 0x9, 0x2e, 0x35, 0x4, 0x61, 0xc3, 0xb5, 0x9d, 0xc5, 0x27, 0x21, 0xa, 0x5a, 0xd6, 0x3e, 0xa6, 0x24, 0xa2, 0x12, 0xdf}}
return a, nil
}
@ -971,7 +973,7 @@ func _1672933930_switcher_cardUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1672933930_switcher_card.up.sql", size: 162, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1672933930_switcher_card.up.sql", size: 162, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x39, 0xba, 0xdc, 0xbb, 0x40, 0x4, 0xf2, 0x10, 0xdf, 0xb4, 0xd2, 0x80, 0x8a, 0x74, 0x4d, 0xf6, 0xbc, 0x50, 0x7, 0xd, 0x22, 0x7f, 0xc4, 0xaf, 0xaa, 0xde, 0xdc, 0x71, 0xe9, 0x42, 0x98, 0x36}}
return a, nil
}
@ -991,7 +993,7 @@ func _1674056187_add_price_cacheUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1674056187_add_price_cache.up.sql", size: 255, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1674056187_add_price_cache.up.sql", size: 255, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb7, 0x79, 0x6a, 0x9b, 0x28, 0xd1, 0x22, 0xf0, 0x84, 0x76, 0x40, 0x39, 0x49, 0x15, 0x5d, 0xaa, 0xfd, 0x11, 0xff, 0x13, 0x27, 0x42, 0x12, 0xfa, 0x82, 0xe6, 0x7a, 0xf0, 0x5e, 0x1f, 0xe3, 0xba}}
return a, nil
}
@ -1011,7 +1013,7 @@ func _1674136690_ens_usernamesUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1674136690_ens_usernames.up.sql", size: 98, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1674136690_ens_usernames.up.sql", size: 98, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x81, 0x7a, 0xf3, 0xa8, 0x88, 0x99, 0xd6, 0x9c, 0x69, 0x48, 0x3c, 0x10, 0xda, 0x72, 0xdc, 0x14, 0xd, 0x6e, 0x8c, 0x82, 0x92, 0x2d, 0x2c, 0xee, 0x4c, 0x70, 0xa4, 0xdc, 0x5c, 0x5, 0x2, 0xc3}}
return a, nil
}
@ -1031,7 +1033,7 @@ func _1674232431_add_balance_historyUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1674232431_add_balance_history.up.sql", size: 698, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1674232431_add_balance_history.up.sql", size: 698, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf7, 0xb5, 0x18, 0xca, 0x4a, 0x93, 0xbb, 0x6f, 0xa4, 0xee, 0xe4, 0x3e, 0xff, 0x6a, 0x4b, 0xe2, 0xe1, 0x61, 0x28, 0xee, 0xc5, 0x26, 0x57, 0x61, 0x5e, 0x6d, 0x44, 0x1e, 0x85, 0x43, 0x70, 0xa2}}
return a, nil
}
@ -1051,7 +1053,7 @@ func _1676368933_keypairs_to_keycardsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1676368933_keypairs_to_keycards.up.sql", size: 639, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1676368933_keypairs_to_keycards.up.sql", size: 639, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x81, 0x93, 0x27, 0x2, 0xf0, 0x37, 0x81, 0x65, 0xa4, 0xb3, 0x5b, 0x60, 0x36, 0x95, 0xfc, 0x81, 0xf0, 0x3b, 0x7c, 0xc3, 0x2c, 0x85, 0xbd, 0x38, 0x46, 0xa4, 0x95, 0x4a, 0x6, 0x3e, 0x74, 0xd5}}
return a, nil
}
@ -1071,7 +1073,7 @@ func _1676951398_add_currency_format_cacheUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1676951398_add_currency_format_cache.up.sql", size: 291, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1676951398_add_currency_format_cache.up.sql", size: 291, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf9, 0xa3, 0x76, 0x35, 0xca, 0xf, 0xe8, 0xdf, 0xd9, 0x61, 0xf9, 0xed, 0xfc, 0x6d, 0xf5, 0xe, 0x11, 0x88, 0xbd, 0x14, 0x92, 0xc6, 0x57, 0x53, 0xe, 0xcd, 0x52, 0xf4, 0xa9, 0xb1, 0xdd, 0xfd}}
return a, nil
}
@ -1091,7 +1093,7 @@ func _1676968196_keycards_add_clock_columnUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1676968196_keycards_add_clock_column.up.sql", size: 73, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1676968196_keycards_add_clock_column.up.sql", size: 73, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4c, 0xf, 0x1c, 0x28, 0x41, 0x57, 0x57, 0x6c, 0xe, 0x75, 0x6b, 0x75, 0x12, 0x0, 0x18, 0x1e, 0x88, 0x1e, 0x45, 0xe0, 0x32, 0xb9, 0xd4, 0xd9, 0x2e, 0xc8, 0xb, 0x80, 0x6, 0x51, 0x3d, 0x28}}
return a, nil
}
@ -1111,7 +1113,7 @@ func _1676968197_add_fallback_rpc_to_networksUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1676968197_add_fallback_rpc_to_networks.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1676968197_add_fallback_rpc_to_networks.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x77, 0x6a, 0xc6, 0x45, 0xfa, 0x62, 0x84, 0x74, 0x6d, 0x7c, 0xd7, 0x1d, 0x79, 0xb6, 0x38, 0x43, 0xa8, 0x8, 0x6b, 0x75, 0x3d, 0x9, 0x2, 0xc5, 0x9f, 0xbb, 0x45, 0x56, 0x4c, 0x4e, 0x17, 0x89}}
return a, nil
}
@ -1131,7 +1133,7 @@ func _1677674090_add_chains_ens_istest_to_saved_addressesUpSql() (*asset, error)
return nil, err
}
info := bindataFileInfo{name: "1677674090_add_chains_ens_istest_to_saved_addresses.up.sql", size: 638, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1677674090_add_chains_ens_istest_to_saved_addresses.up.sql", size: 638, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa8, 0x2d, 0xa4, 0x1b, 0xf6, 0x6a, 0x13, 0x7b, 0xe, 0x59, 0xcd, 0xe2, 0x4e, 0x81, 0x99, 0xc4, 0x33, 0x84, 0xde, 0x66, 0xca, 0xac, 0x2f, 0x5, 0x90, 0xac, 0xfd, 0x4e, 0xfc, 0x55, 0x44, 0xe5}}
return a, nil
}
@ -1151,7 +1153,7 @@ func _1677681143_accounts_table_type_column_updateUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1677681143_accounts_table_type_column_update.up.sql", size: 135, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1677681143_accounts_table_type_column_update.up.sql", size: 135, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd2, 0xc4, 0x6, 0x42, 0x50, 0x1d, 0xf4, 0x48, 0x55, 0xbc, 0xa2, 0x19, 0xdd, 0xad, 0xc8, 0xc, 0xa7, 0x30, 0xb6, 0xaf, 0xe, 0x2b, 0xaa, 0x2a, 0xa4, 0xe1, 0xb9, 0x41, 0x23, 0x66, 0xd3, 0x3}}
return a, nil
}
@ -1171,7 +1173,7 @@ func _1678264207_accounts_table_new_columns_addedUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1678264207_accounts_table_new_columns_added.up.sql", size: 130, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1678264207_accounts_table_new_columns_added.up.sql", size: 130, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf4, 0xd4, 0xf3, 0x35, 0xef, 0x5c, 0x19, 0x3c, 0x15, 0x90, 0x60, 0xbd, 0x1f, 0x81, 0xf0, 0x86, 0x73, 0x89, 0xa0, 0x70, 0xf2, 0x46, 0xae, 0xea, 0xd0, 0xc6, 0x9e, 0x55, 0x4a, 0x54, 0x62, 0xbb}}
return a, nil
}
@ -1191,7 +1193,7 @@ func _1680770368_add_bio_to_settings_sync_clock_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1680770368_add_bio_to_settings_sync_clock_table.up.sql", size: 75, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1680770368_add_bio_to_settings_sync_clock_table.up.sql", size: 75, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4a, 0x52, 0xf6, 0x3f, 0xaa, 0xd, 0xa0, 0xee, 0xe8, 0xe6, 0x16, 0x21, 0x80, 0x61, 0xe4, 0x7a, 0x4e, 0x37, 0x8d, 0x30, 0x51, 0x20, 0x4d, 0x15, 0x47, 0xfb, 0x6, 0xa1, 0xce, 0xc8, 0x27, 0x5a}}
return a, nil
}
@ -1211,7 +1213,7 @@ func _1681110436_add_mnemonic_to_settings_sync_clock_tableUpSql() (*asset, error
return nil, err
}
info := bindataFileInfo{name: "1681110436_add_mnemonic_to_settings_sync_clock_table.up.sql", size: 311, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1681110436_add_mnemonic_to_settings_sync_clock_table.up.sql", size: 311, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3d, 0x74, 0x81, 0x7d, 0x9e, 0x77, 0xb6, 0xfe, 0xe3, 0xcb, 0x48, 0xe5, 0x5f, 0x39, 0x23, 0xa1, 0x7d, 0x53, 0x22, 0xe8, 0x96, 0x15, 0x8a, 0x1e, 0x8e, 0xbc, 0xe2, 0x1d, 0xc4, 0xc2, 0x56, 0x34}}
return a, nil
}
@ -1231,7 +1233,7 @@ func _1681392602_9d_sync_periodUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1681392602_9d_sync_period.up.sql", size: 60, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1681392602_9d_sync_period.up.sql", size: 60, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc9, 0xa, 0x90, 0x29, 0x7f, 0x76, 0x98, 0xa7, 0x71, 0x80, 0x5a, 0x2f, 0xbe, 0x23, 0x9a, 0xd4, 0xf4, 0x39, 0x19, 0xd3, 0xa5, 0x34, 0x6e, 0x67, 0x6a, 0xbe, 0x8a, 0xad, 0x21, 0xc7, 0xba, 0x88}}
return a, nil
}
@ -1251,7 +1253,7 @@ func _1681762078_default_sync_period_9dUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1681762078_default_sync_period_9d.up.sql", size: 3002, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1681762078_default_sync_period_9d.up.sql", size: 3002, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3e, 0xd9, 0x26, 0xfc, 0xa9, 0x45, 0xc1, 0x81, 0xa8, 0xe2, 0x2c, 0xe9, 0x3c, 0xea, 0x1d, 0x37, 0x11, 0x45, 0x8c, 0x6c, 0xbc, 0xc2, 0x6, 0x69, 0x2, 0x75, 0x29, 0x40, 0x9f, 0xc5, 0xbb, 0x36}}
return a, nil
}
@ -1271,7 +1273,7 @@ func _1681780680_add_clock_to_social_links_settingsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1681780680_add_clock_to_social_links_settings.up.sql", size: 137, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1681780680_add_clock_to_social_links_settings.up.sql", size: 137, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x63, 0x11, 0xf5, 0x41, 0xe5, 0x5a, 0xf4, 0xe3, 0xf3, 0x14, 0x87, 0x28, 0xd8, 0xf0, 0x52, 0x31, 0x8, 0xd5, 0xbb, 0xf4, 0xff, 0x55, 0x5f, 0x42, 0x90, 0xcb, 0xf7, 0x46, 0x2, 0x6, 0xbe, 0x42}}
return a, nil
}
@ -1291,7 +1293,7 @@ func _1682073779_settings_table_remove_latest_derived_path_columnUpSql() (*asset
return nil, err
}
info := bindataFileInfo{name: "1682073779_settings_table_remove_latest_derived_path_column.up.sql", size: 4470, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1682073779_settings_table_remove_latest_derived_path_column.up.sql", size: 4470, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7a, 0x36, 0x2, 0x41, 0xd, 0x5c, 0xd1, 0x92, 0x85, 0x6d, 0x84, 0xff, 0x67, 0xa7, 0x4c, 0x67, 0xa4, 0xef, 0x52, 0x69, 0x1f, 0x22, 0x25, 0x92, 0xc, 0xb3, 0x89, 0x50, 0x91, 0xc, 0x49, 0xf9}}
return a, nil
}
@ -1311,7 +1313,7 @@ func _1682146075_add_created_at_to_saved_addressesUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1682146075_add_created_at_to_saved_addresses.up.sql", size: 107, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1682146075_add_created_at_to_saved_addresses.up.sql", size: 107, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x88, 0xfe, 0x35, 0x9c, 0x6b, 0xdf, 0x67, 0x18, 0x16, 0xe4, 0xc9, 0xd4, 0x77, 0x7c, 0x4, 0xe2, 0x6c, 0x41, 0xd9, 0x53, 0x97, 0xfe, 0x5, 0xa3, 0x23, 0xce, 0x82, 0xad, 0x92, 0x5e, 0xd7, 0x7d}}
return a, nil
}
@ -1331,7 +1333,7 @@ func _1682393575_sync_ens_nameUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1682393575_sync_ens_name.up.sql", size: 713, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1682393575_sync_ens_name.up.sql", size: 713, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfb, 0xea, 0xcb, 0x4d, 0x71, 0x5a, 0x49, 0x19, 0x8b, 0xef, 0x66, 0x27, 0x33, 0x89, 0xb0, 0xe, 0x37, 0x1b, 0x41, 0x8, 0x12, 0xcc, 0x56, 0xd8, 0x1b, 0xf, 0xf8, 0x50, 0x4b, 0x93, 0xf1, 0x29}}
return a, nil
}
@ -1351,7 +1353,7 @@ func _1683457503_add_blocks_ranges_sequential_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1683457503_add_blocks_ranges_sequential_table.up.sql", size: 263, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1683457503_add_blocks_ranges_sequential_table.up.sql", size: 263, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfe, 0x57, 0x2e, 0x0, 0x6a, 0x6e, 0xd7, 0xeb, 0xe6, 0x66, 0x79, 0x32, 0x22, 0x82, 0x92, 0xf4, 0xc9, 0xf1, 0x58, 0x1a, 0x45, 0x60, 0x77, 0x50, 0xe7, 0x54, 0x4a, 0xc0, 0x42, 0x3a, 0x4f, 0x35}}
return a, nil
}
@ -1371,7 +1373,7 @@ func _1683627613_accounts_and_keycards_improvementsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1683627613_accounts_and_keycards_improvements.up.sql", size: 3640, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1683627613_accounts_and_keycards_improvements.up.sql", size: 3640, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8e, 0xbe, 0x62, 0xf5, 0x9, 0x42, 0x8c, 0x8f, 0xa8, 0x45, 0xe7, 0x36, 0xc9, 0xde, 0xf4, 0xe2, 0xfd, 0xc4, 0x8, 0xd0, 0xa3, 0x8, 0x64, 0xe2, 0x56, 0xcc, 0xa7, 0x6d, 0xc5, 0xcc, 0x82, 0x2c}}
return a, nil
}
@ -1391,7 +1393,7 @@ func _1685041348_settings_table_add_latest_derived_path_columnUpSql() (*asset, e
return nil, err
}
info := bindataFileInfo{name: "1685041348_settings_table_add_latest_derived_path_column.up.sql", size: 115, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "1685041348_settings_table_add_latest_derived_path_column.up.sql", size: 115, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x21, 0xd4, 0x1b, 0xbf, 0x8, 0xf9, 0xd4, 0xb0, 0xa0, 0x6, 0x5b, 0xfb, 0x7e, 0xff, 0xfa, 0xbf, 0xcc, 0x64, 0x47, 0x81, 0x8b, 0x5e, 0x17, 0x6a, 0xa7, 0xa4, 0x35, 0x8f, 0x30, 0x4f, 0xd9, 0xd}}
return a, nil
}
@ -1411,7 +1413,7 @@ func _1685440989_update_color_id_accountsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1685440989_update_color_id_accounts.up.sql", size: 918, mode: os.FileMode(0644), modTime: time.Unix(1686041617, 0)}
info := bindataFileInfo{name: "1685440989_update_color_id_accounts.up.sql", size: 918, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x10, 0x2e, 0x51, 0x1d, 0x2d, 0x16, 0x84, 0xd6, 0xe8, 0xbc, 0x20, 0x53, 0x47, 0xb8, 0x40, 0x21, 0x52, 0x5c, 0xd9, 0xbb, 0xea, 0xe2, 0xa5, 0x77, 0xc8, 0x35, 0x4c, 0xe0, 0x9d, 0x42, 0x44, 0x50}}
return a, nil
}
@ -1431,7 +1433,7 @@ func _1685463947_add_to_asset_to_multitransactionUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1685463947_add_to_asset_to_multitransaction.up.sql", size: 61, mode: os.FileMode(0644), modTime: time.Unix(1686041617, 0)}
info := bindataFileInfo{name: "1685463947_add_to_asset_to_multitransaction.up.sql", size: 61, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd3, 0x66, 0x15, 0x10, 0xfa, 0x66, 0x81, 0x68, 0xd9, 0xb4, 0x93, 0x9e, 0x11, 0xed, 0x1d, 0x16, 0x9d, 0x5a, 0xf8, 0xd7, 0x8, 0xea, 0x7a, 0xaf, 0xe4, 0xb3, 0x22, 0x19, 0xca, 0xff, 0x75, 0x7c}}
return a, nil
}
@ -1451,7 +1453,7 @@ func _1685880973_add_profile_links_settings_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1685880973_add_profile_links_settings_table.up.sql", size: 1656, mode: os.FileMode(0644), modTime: time.Unix(1686041617, 0)}
info := bindataFileInfo{name: "1685880973_add_profile_links_settings_table.up.sql", size: 1656, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x13, 0x23, 0x7b, 0x1e, 0x82, 0x61, 0xcc, 0x76, 0xd6, 0xc7, 0x42, 0x6e, 0x69, 0x21, 0x1b, 0xfd, 0x7d, 0xda, 0xd7, 0xb7, 0xc7, 0xd3, 0x22, 0x63, 0xfe, 0xc6, 0xd3, 0xdf, 0xc8, 0x5f, 0x50, 0xcc}}
return a, nil
}
@ -1471,11 +1473,51 @@ func _1686041510_add_idx_transfers_blkno_loadedUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1686041510_add_idx_transfers_blkno_loaded.up.sql", size: 71, mode: os.FileMode(0644), modTime: time.Unix(1686041617, 0)}
info := bindataFileInfo{name: "1686041510_add_idx_transfers_blkno_loaded.up.sql", size: 71, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe2, 0x5d, 0x7e, 0x43, 0x14, 0x3c, 0x50, 0x44, 0x25, 0xd0, 0xe1, 0x75, 0xba, 0x61, 0x7b, 0x68, 0x2e, 0x43, 0x74, 0x1d, 0x10, 0x61, 0x8e, 0x45, 0xe6, 0x25, 0x78, 0x81, 0x68, 0x6, 0x24, 0x5b}}
return a, nil
}
var __1686048341_transfers_receipt_json_blob_outUpSqlDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x44\xcb\xc1\x0d\xc2\x30\x0c\x46\xe1\x55\xfe\x05\xc2\x1a\x88\x13\x17\x16\x30\xc1\x21\x16\xc1\xae\x6c\x37\x52\xb7\xaf\x72\xea\xed\x49\x4f\x5f\x29\x78\x75\x09\xfc\xe5\xeb\x94\x62\x0a\x09\x88\xe2\xfe\x44\xb5\x0f\xdf\xf0\x68\xab\xaf\xdd\x48\x46\x20\x97\x61\x4d\x3f\x10\xec\x93\x03\x14\x70\x1b\xe3\x4d\xf5\x87\x34\x64\x67\x6c\xce\x53\x6c\x0f\x98\xf2\x19\x00\x00\xff\xff\x4e\x62\x72\x83\x68\x00\x00\x00")
func _1686048341_transfers_receipt_json_blob_outUpSqlDownSqlBytes() ([]byte, error) {
return bindataRead(
__1686048341_transfers_receipt_json_blob_outUpSqlDownSql,
"1686048341_transfers_receipt_json_blob_out.up.sql.down.sql",
)
}
func _1686048341_transfers_receipt_json_blob_outUpSqlDownSql() (*asset, error) {
bytes, err := _1686048341_transfers_receipt_json_blob_outUpSqlDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1686048341_transfers_receipt_json_blob_out.up.sql.down.sql", size: 104, mode: os.FileMode(0644), modTime: time.Unix(1686147405, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x9f, 0x6c, 0xd9, 0x76, 0x83, 0x64, 0xf0, 0xf2, 0x74, 0x97, 0xca, 0xd7, 0xaa, 0x4, 0x74, 0x7c, 0x34, 0x56, 0x88, 0x10, 0xa9, 0x4d, 0x1d, 0x8e, 0x85, 0xc3, 0x66, 0x1, 0x2b, 0x30, 0x90, 0xf4}}
return a, nil
}
var __1686048341_transfers_receipt_json_blob_outUpSqlUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x94\x41\x6f\x9b\x4e\x10\xc5\xef\xf9\x14\x73\x4c\xa4\x24\x7f\xfd\xd3\xaa\xaa\x9a\x13\x8e\x51\xea\xca\x05\xc9\x25\x6a\x6e\x74\xbc\x3b\x98\xad\x97\x1d\xb4\x33\x24\xa4\x9f\xbe\x32\xb6\x53\xb7\x27\xc8\x0d\x2d\xf3\x7b\x6f\x61\xf7\xbd\xab\x2b\x28\x6a\x27\xd0\xb8\x4d\x44\x75\x1c\xc0\x09\x58\x0e\x04\x2e\xc0\x7d\x0e\x86\x2d\x01\x0a\x20\x98\x4e\x94\x1b\x10\xa5\xf6\xfa\xec\x88\x55\xce\x13\x08\xc5\x27\x92\x61\x2a\x00\x06\x53\x73\x84\x8a\x23\x68\x4d\x27\xba\xf2\x22\x4a\xcd\x8e\xbc\xab\xc9\x6c\x0f\x6f\xe8\x3b\x7a\x4f\xfa\x45\x38\xcc\x3c\xaf\x05\xaa\xc8\x0d\x60\xdb\x5a\x54\x5c\xa3\xd0\x7f\xc7\x87\xeb\x0d\x9f\xed\x7d\x09\x2a\xf6\x9e\x9f\x5d\xd8\x0c\xdb\x11\xc0\x48\xff\x6e\xfa\xd3\x30\x9c\x2c\x8b\x74\x05\x45\x32\x5b\xa6\xa0\x11\x83\x54\x14\x05\x92\xf9\x1c\xee\xf2\xe5\xc3\xd7\x0c\x44\x51\x3b\x81\x45\x56\xdc\x8e\x9a\x8f\x64\xc8\xb5\x5a\xea\x4b\x4b\xe3\x29\xed\xcb\x1a\xa5\x86\xd9\x32\x9f\x8d\x23\x3c\x6f\x4a\x17\x2c\xf5\xe3\x4d\xd6\x9e\xcd\x76\xaa\x8f\xe9\x9a\xce\xa3\xba\x27\x2a\x37\x28\x65\x27\x64\xc7\x3b\x1a\x0e\x1a\xd1\x68\x89\xd6\x46\x12\x81\x22\x7d\x1c\x89\x4e\x37\xd3\xfe\xf4\x87\x8c\x45\xa6\x9d\x53\x1b\x59\xc9\x28\x59\x98\xe5\xf9\x32\x4d\xb2\xf1\x1f\xe3\x5d\xe3\x14\x1e\xb2\x6f\x8b\xfb\x2c\x9d\x8f\xb7\xdc\xb1\x6d\x74\x86\x4a\xe3\xb1\x69\xc9\x7e\x78\x3f\x0d\x56\xd7\x96\x06\xdb\xb7\xe2\x15\xd1\x5b\x71\x6c\xb8\x0b\x5a\xb6\x68\x2d\xd9\xff\x6f\x3e\xd6\xd4\xc3\xdd\xe7\x64\x75\xfe\xee\xe6\x62\xa4\x82\x31\x83\x44\xe0\x60\x26\x1c\x93\xb8\x5f\x53\xc2\xc7\x5b\x0a\xaf\x57\x74\x7c\x34\xf6\x9c\xb3\x07\x64\x68\xae\x55\x9a\x14\x29\x2c\xb2\x79\xfa\xf8\x07\x2a\x2b\xe7\x95\x22\xe4\xd9\x89\xd0\xf9\xbe\x59\x2e\xff\xb6\xbf\x7c\x55\xbd\xb8\xfd\x31\x48\xa6\xfd\x10\x21\xd0\x1e\x30\xd8\x63\xbf\xc0\xae\xf5\xf6\x5d\xb8\x6b\xd1\x9f\xc2\x61\x97\xef\xf5\x30\x83\xd6\x0e\xab\x2e\x54\x1c\x9b\x43\x6b\x07\xe5\x61\x31\xd0\x33\x18\xf6\x5d\x13\xe4\x77\x00\x00\x00\xff\xff\x39\x7c\x13\x6d\xdc\x05\x00\x00")
func _1686048341_transfers_receipt_json_blob_outUpSqlUpSqlBytes() ([]byte, error) {
return bindataRead(
__1686048341_transfers_receipt_json_blob_outUpSqlUpSql,
"1686048341_transfers_receipt_json_blob_out.up.sql.up.sql",
)
}
func _1686048341_transfers_receipt_json_blob_outUpSqlUpSql() (*asset, error) {
bytes, err := _1686048341_transfers_receipt_json_blob_outUpSqlUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1686048341_transfers_receipt_json_blob_out.up.sql.up.sql", size: 1500, mode: os.FileMode(0644), modTime: time.Unix(1686147405, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x49, 0xcd, 0xe3, 0xa6, 0x8c, 0x53, 0x51, 0xe6, 0x3c, 0x64, 0xcb, 0x3, 0x3, 0xb, 0x4d, 0x52, 0xa5, 0x1c, 0xcc, 0xe1, 0x23, 0x94, 0x14, 0x79, 0xd7, 0x56, 0x58, 0xef, 0xcc, 0x1a, 0x6, 0xa4}}
return a, nil
}
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xc9\xb1\x0d\xc4\x20\x0c\x05\xd0\x9e\x29\xfe\x02\xd8\xfd\x6d\xe3\x4b\xac\x2f\x44\x82\x09\x78\x7f\xa5\x49\xfd\xa6\x1d\xdd\xe8\xd8\xcf\x55\x8a\x2a\xe3\x47\x1f\xbe\x2c\x1d\x8c\xfa\x6f\xe3\xb4\x34\xd4\xd9\x89\xbb\x71\x59\xb6\x18\x1b\x35\x20\xa2\x9f\x0a\x03\xa2\xe5\x0d\x00\x00\xff\xff\x60\xcd\x06\xbe\x4a\x00\x00\x00")
func docGoBytes() ([]byte, error) {
@ -1491,7 +1533,7 @@ func docGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1685543739, 0)}
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1686145633, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xde, 0x7c, 0x28, 0xcd, 0x47, 0xf2, 0xfa, 0x7c, 0x51, 0x2d, 0xd8, 0x38, 0xb, 0xb0, 0x34, 0x9d, 0x4c, 0x62, 0xa, 0x9e, 0x28, 0xc3, 0x31, 0x23, 0xd9, 0xbb, 0x89, 0x9f, 0xa0, 0x89, 0x1f, 0xe8}}
return a, nil
}
@ -1721,6 +1763,10 @@ var _bindata = map[string]func() (*asset, error){
"1686041510_add_idx_transfers_blkno_loaded.up.sql": _1686041510_add_idx_transfers_blkno_loadedUpSql,
"1686048341_transfers_receipt_json_blob_out.up.sql.down.sql": _1686048341_transfers_receipt_json_blob_outUpSqlDownSql,
"1686048341_transfers_receipt_json_blob_out.up.sql.up.sql": _1686048341_transfers_receipt_json_blob_outUpSqlUpSql,
"doc.go": docGo,
}
@ -1832,6 +1878,8 @@ var _bintree = &bintree{nil, map[string]*bintree{
"1685463947_add_to_asset_to_multitransaction.up.sql": &bintree{_1685463947_add_to_asset_to_multitransactionUpSql, map[string]*bintree{}},
"1685880973_add_profile_links_settings_table.up.sql": &bintree{_1685880973_add_profile_links_settings_tableUpSql, map[string]*bintree{}},
"1686041510_add_idx_transfers_blkno_loaded.up.sql": &bintree{_1686041510_add_idx_transfers_blkno_loadedUpSql, map[string]*bintree{}},
"1686048341_transfers_receipt_json_blob_out.up.sql.down.sql": &bintree{_1686048341_transfers_receipt_json_blob_outUpSqlDownSql, map[string]*bintree{}},
"1686048341_transfers_receipt_json_blob_out.up.sql.up.sql": &bintree{_1686048341_transfers_receipt_json_blob_outUpSqlUpSql, map[string]*bintree{}},
"doc.go": &bintree{docGo, map[string]*bintree{}},
}}

View File

@ -9,11 +9,22 @@ import (
)
// Migrate applies migrations.
func Migrate(db *sql.DB) error {
// see Migrate in vendor/status-go/sqlite/migrate.go
func Migrate(db *sql.DB, customSteps []sqlite.PostStep) error {
return sqlite.Migrate(db, bindata.Resource(
AssetNames(),
func(name string) ([]byte, error) {
return Asset(name)
},
))
), customSteps, nil)
}
// MigrateTo is used for testing purposes
func MigrateTo(db *sql.DB, customSteps []sqlite.PostStep, untilVersion uint) error {
return sqlite.Migrate(db, bindata.Resource(
AssetNames(),
func(name string) ([]byte, error) {
return Asset(name)
},
), customSteps, &untilVersion)
}

View File

@ -0,0 +1 @@
-- This migration is in GO code. If GO migration fails this entry serves as rollback to the previous one

View File

@ -0,0 +1,31 @@
-- This migration is done in GO code as a custom step.
-- This file serves as an anchor for the migration system
-- Check migrateWalletJsonBlobs from appdatabase/database.go
-- The following steps are done in GO code:
-- ALTER TABLE transfers ADD COLUMN status INT;
-- ALTER TABLE transfers ADD COLUMN receipt_type INT;
-- ALTER TABLE transfers ADD COLUMN tx_hash BLOB;
-- ALTER TABLE transfers ADD COLUMN log_index INT;
-- ALTER TABLE transfers ADD COLUMN block_hash BLOB;
-- ALTER TABLE transfers ADD COLUMN cumulative_gas_used INT;
-- ALTER TABLE transfers ADD COLUMN contract_address TEXT;
-- ALTER TABLE transfers ADD COLUMN gas_used INT;
-- ALTER TABLE transfers ADD COLUMN tx_index INT;
-- ALTER TABLE transfers ADD COLUMN tx_type INT;
-- ALTER TABLE transfers ADD COLUMN protected BOOLEAN;
-- ALTER TABLE transfers ADD COLUMN gas_limit UNSIGNED INT;
-- ALTER TABLE transfers ADD COLUMN gas_price_clamped64 INT;
-- ALTER TABLE transfers ADD COLUMN gas_tip_cap_clamped64 INT;
-- ALTER TABLE transfers ADD COLUMN gas_fee_cap_clamped64 INT;
-- ALTER TABLE transfers ADD COLUMN amount_padded128hex CHAR(32);
-- ALTER TABLE transfers ADD COLUMN account_nonce INT;
-- ALTER TABLE transfers ADD COLUMN size INT;
-- ALTER TABLE transfers ADD COLUMN token_address BLOB;
-- ALTER TABLE transfers ADD COLUMN token_id BLOB;
-- CREATE INDEX transfers_filter ON transfers (status, token_address, token_id);`
-- Extract tx and receipt data from the json blob and add the information into the new columns

View File

@ -15,5 +15,5 @@ func Migrate(db *sql.DB) error {
func(name string) ([]byte, error) {
return Asset(name)
},
))
), nil, nil)
}

View File

@ -38,3 +38,34 @@ func SetupTestMemorySQLDB(prefix string) (*sql.DB, error) {
return db, nil
}
func ColumnExists(db *sql.DB, tableName string, columnName string) (bool, error) {
rows, err := db.Query("PRAGMA table_info(" + tableName + ")")
if err != nil {
return false, err
}
defer rows.Close()
var cid int
var name string
var dataType string
var notNull bool
var dFLTValue sql.NullString
var pk int
for rows.Next() {
err := rows.Scan(&cid, &name, &dataType, &notNull, &dFLTValue, &pk)
if err != nil {
return false, err
}
if name == columnName {
return true, nil
}
}
if rows.Err() != nil {
return false, rows.Err()
}
return false, nil
}

View File

@ -102,7 +102,7 @@ func InitializeDB(path string) (*Database, error) {
if err != nil {
return nil, err
}
err = migrations.Migrate(db)
err = migrations.Migrate(db, nil)
if err != nil {
return nil, err
}

View File

@ -9,11 +9,12 @@ import (
)
// Migrate applies migrations.
func Migrate(db *sql.DB) error {
// see Migrate in vendor/status-go/sqlite/migrate.go
func Migrate(db *sql.DB, customSteps []sqlite.PostStep) error {
return sqlite.Migrate(db, bindata.Resource(
AssetNames(),
func(name string) ([]byte, error) {
return Asset(name)
},
))
), customSteps, nil)
}

View File

@ -152,7 +152,7 @@ func WithDatabase(db *sql.DB) Option {
func WithToplevelDatabaseMigrations() Option {
return func(c *config) error {
c.afterDbCreatedHooks = append(c.afterDbCreatedHooks, func(c *config) error {
return migrations.Migrate(c.db)
return migrations.Migrate(c.db, nil)
})
return nil
}

View File

@ -48,8 +48,8 @@ import (
localnotifications "github.com/status-im/status-go/services/local-notifications"
mailserversDB "github.com/status-im/status-go/services/mailservers"
"github.com/status-im/status-go/services/wallet"
w_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/services/wallet/transfer"
)
// EnvelopeEventsHandler used for two different event types.
@ -296,7 +296,7 @@ func (c *verifyTransactionClient) TransactionByHash(ctx context.Context, hash ty
// Token transfer, check the logs
if len(coremessage.Data()) != 0 {
if transfer.IsTokenTransfer(receipt.Logs) {
if w_common.IsTokenTransfer(receipt.Logs) {
return coremessage, coretypes.TransactionStatus(receipt.Status), nil
}
return coremessage, coretypes.TransactionStatusFailed, nil

View File

@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/require"
w_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/transfer"
"github.com/status-im/status-go/services/wallet/walletevent"
"github.com/status-im/status-go/signal"
@ -99,7 +100,7 @@ func TestTransactionNotification(t *testing.T) {
transfers := []transfer.Transfer{
{
ID: common.Hash{1},
Type: transfer.Type("eth"),
Type: w_common.Type("eth"),
BlockHash: header.Hash,
BlockNumber: header.Number,
Transaction: tx,

View File

@ -0,0 +1,157 @@
# DB extension and refactoring for activity
## Work in progress
| | Buy | Swap | Bridge | Send/Receive |
| ------------- | -------------- | -------------- | ------------- | ------------- |
| Activity data | ~~API~~ ~~DB~~ | ~~API~~ ~~DB~~ | _API_ _DB_ | _API_ _DB_ |
| Raw data | ~~API~~ ~~DB~~ | ~~API~~ ~~DB~~ | _API_ _DB_ | _API_ _DB_ |
| Pending data | ~~API~~ ~~DB~~ | ~~API~~ ~~DB~~ | _API_ _DB_ | _API_ _DB_ |
Legend:
- ~~API~~ - not much or at all provided
- _API_ - partially provided
- API - complete
### Summary
Improve on the identified limitations
- [ ] Missing filtering data
- [x] Missing cached (not extracted as a column)
- Extracting the data from the raw data is expensive but might be negligible given that usually we should not expect more than 20 entries per second in the worst case scenario.
- [x] Table extensions
- ~~Activity specific info in activity data store (multi_transaction table)~~
- Activity specific info in in the transactions data store (transfers table)
### Missing data
Filter requirements
- [ ] Activity operation status
- [ ] `pending`: have to aggregate for `Buy`, `Swap`, `Bridge`
- already there for `Send`, `Receive`
- [ ] `complete`: only extract and check for `status` in the `receipt` for `Send`, `Receive`
- For complex operations aggregate the `complete` status `Buy`, `Swap`, `Bridge`
- [ ] `finalized`: similar to `complete` for `Send`, `Receive`
- all sub-transactions are `complete` for `Buy`, `Swap`, `Bridge`
- [ ] `failed`: extract from `status` for all sub-transactions
- [ ] `chainID`: aggregate data for activity entries `Bridge`, `Buy`, `Swap`
- [ ] `tokenCode` for activity entries `Send`, `Receive`
- For `Bridge` its already there and `Buy`, `Swap` is coming soon
- [ ] `collectibles`: require adding collectible attributes to activity data (probably `token_address` and `tokenId`)
UX requirements
- [ ] `status`: for status icon and label
- [ ] `chainIDs`: for chain icons
- Missing for `Bridge`, `Buy`, `Swap`
- [ ] `amount`s: add to the activity.Entry
- already in DB
- [ ] `tokenCode`s: add to the activity.Entry
- already in DB
- [ ] `to`/`from`/`owner`: add to the activity.Entry
- already in DB, coming soon
- [ ] `tokenIdentity`: collectible is missing (`chainId`, `address`, `tokenId`)
- `tokenCode` should be covering fungible operations
- [x] `identity`: for all the sources
- [x] `type`: for the main icon and label
- [x] `time`: timestamp
### Refactoring
## Current state
### Transfers Table
The `transfers` transactions raw data
- Transaction identity: `network_id`, `hash`, `address`
- Implementation by `sqlite_autoindex_transfers_1` unique index
- `multi_transaction_id`: `multi_transaction` entries to `transfers` entries mapping (one to many)
- Raw data:
- `tx` transaction
- `receipt`: transfer receipt
### Multi-Transaction Table
Represented by `multi_transaction`
Responsibilities
- UX metadata for transactions originating from our APP.
- `from_address`, `to_address`
- `from_asset`, `to_asset`
- `from_amount`, `to_amount` (token codes)
- `type` identifies the type (initially only Send and Bridge)
- `timestamp` the timestamp of the execution
- Multi-transaction to sub-transaction mapping
- The `multi_transaction_id` in the `transfers` and `pending_transaction` table corresponds to the `ROWID` in the `multi_transactions`.
### Pending Transactions Table
The `pending_transactions` table represents transactions initiated from the app
- Transaction identity
- `network_id`, `hash`
- implemented by the `sqlite_autoindex_pending_transactions_1` index
- Note how this is different from the `transfers` table, where the `address` is also part of the identity.
- `timestamp`: The timestamp of the pending transaction.
- `multi_transaction_id`: `multi_transaction` entries to `pending_transactions` entries mapping (one to many)
### Schema
Relationships between the tables
```mermaid
erDiagram
multi_transaction ||--o{ transfers : has
multi_transaction ||--o{ pending_transactions : has
transfers {
network_id BIGINT
hash VARCHAR
timestamp BIGINT
multi_transaction_id INT
tx BLOB
receipt BLOB
log BLOB
}
multi_transaction {
ROWID INT
type VARCHAR
}
pending_transactions {
network_id BIGINT
hash VARCHAR
timestamp INT
multi_transaction_id INT
}
```
### Dropped tasks
Dropped the DB refactoring and improvements after further discussion and concerns
- [x] Terminology proposal
- [x] using `transactions` instead of `transfers` for the raw data
- [x] using `activity` instead of `multi-transaction` to better match the new requirements
- [x] Convert JSON blobs into structured data
Dropped benchmark performance and move on using theoretical knowledge by adding indexes for what we know only
Will leave the performance concerns for the next milestone
- [ ] Joining DBs
- [ ] One activity DB for all require metadata
- Pros:
- Faster to query (don't know the numbers)
- Simpler query will decrease maintenance
- Cons:
- have to migrate all data, extract and fill the activity on every download of updates for all activities
- [ ] Keep only filter specific metadata in the Activity DB
- Pros:
- Less changes to migrate existing data. Still have to maintain activity filtering specific data
- Cons:
- Slower to query (don't know how much yet)
- Complex query increases maintenance

View File

@ -19,9 +19,7 @@ import (
type PayloadType = int
// Beware if adding/removing please check if affected and update the functions below
// - NewActivityEntryWithTransaction
// - multiTransactionTypeToActivityType
// Beware: pleas update multiTransactionTypeToActivityType if changing this enum
const (
MultiTransactionPT PayloadType = iota + 1
SimpleTransactionPT
@ -75,9 +73,18 @@ func (e *Entry) UnmarshalJSON(data []byte) error {
return nil
}
func NewActivityEntryWithTransaction(payloadType PayloadType, transaction *transfer.TransactionIdentity, timestamp int64, activityType Type, activityStatus Status) Entry {
if payloadType != SimpleTransactionPT && payloadType != PendingTransactionPT {
panic("invalid transaction type")
func newActivityEntryWithPendingTransaction(transaction *transfer.TransactionIdentity, timestamp int64, activityType Type, activityStatus Status) Entry {
return newActivityEntryWithTransaction(true, transaction, timestamp, activityType, activityStatus)
}
func newActivityEntryWithSimpleTransaction(transaction *transfer.TransactionIdentity, timestamp int64, activityType Type, activityStatus Status) Entry {
return newActivityEntryWithTransaction(false, transaction, timestamp, activityType, activityStatus)
}
func newActivityEntryWithTransaction(pending bool, transaction *transfer.TransactionIdentity, timestamp int64, activityType Type, activityStatus Status) Entry {
payloadType := SimpleTransactionPT
if pending {
payloadType = PendingTransactionPT
}
return Entry{
@ -442,14 +449,13 @@ func GetActivityEntries(db *sql.DB, addresses []eth.Address, chainIDs []common.C
// TODO: extend DB with status in order to filter by status. The status has to be extracted from the receipt upon downloading
activityStatus := FinalizedAS
activityType, filteredAddress := getActivityType(dbTrType)
entry = NewActivityEntryWithTransaction(SimpleTransactionPT,
entry = newActivityEntryWithSimpleTransaction(
&transfer.TransactionIdentity{ChainID: common.ChainID(chainID.Int64), Hash: eth.BytesToHash(transferHash), Address: filteredAddress},
timestamp, activityType, activityStatus)
} else if pendingHash != nil && chainID.Valid {
activityStatus := PendingAS
activityType, _ := getActivityType(dbTrType)
entry = NewActivityEntryWithTransaction(PendingTransactionPT,
&transfer.TransactionIdentity{ChainID: common.ChainID(chainID.Int64), Hash: eth.BytesToHash(pendingHash)},
entry = newActivityEntryWithPendingTransaction(&transfer.TransactionIdentity{ChainID: common.ChainID(chainID.Int64), Hash: eth.BytesToHash(pendingHash)},
timestamp, activityType, activityStatus)
} else if multiTxID.Valid {
activityType := multiTransactionTypeToActivityType(transfer.MultiTransactionType(dbMtType.Byte))

View File

@ -1,4 +1,6 @@
package transfer
// Moved here because transactions package depends on accounts package which
// depends on appdatabase where this functionality is needed
package common
import (
"fmt"
@ -6,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
)
@ -17,21 +20,21 @@ type EventType string
const (
// Transaction types
ethTransfer Type = "eth"
erc20Transfer Type = "erc20"
erc721Transfer Type = "erc721"
uniswapV2Swap Type = "uniswapV2Swap"
uniswapV3Swap Type = "uniswapV3Swap"
EthTransfer Type = "eth"
Erc20Transfer Type = "erc20"
Erc721Transfer Type = "erc721"
UniswapV2Swap Type = "uniswapV2Swap"
UniswapV3Swap Type = "uniswapV3Swap"
unknownTransaction Type = "unknown"
// Event types
erc20TransferEventType EventType = "erc20Event"
erc721TransferEventType EventType = "erc721Event"
uniswapV2SwapEventType EventType = "uniswapV2SwapEvent"
uniswapV3SwapEventType EventType = "uniswapV3SwapEvent"
unknownEventType EventType = "unknownEvent"
Erc20TransferEventType EventType = "erc20Event"
Erc721TransferEventType EventType = "erc721Event"
UniswapV2SwapEventType EventType = "uniswapV2SwapEvent"
UniswapV3SwapEventType EventType = "uniswapV3SwapEvent"
UnknownEventType EventType = "unknownEvent"
erc20_721TransferEventSignature = "Transfer(address,address,uint256)"
Erc20_721TransferEventSignature = "Transfer(address,address,uint256)"
erc20TransferEventIndexedParameters = 3 // signature, from, to
erc721TransferEventIndexedParameters = 4 // signature, from, to, tokenId
@ -47,39 +50,39 @@ var (
// Detect event type for a cetain item from the Events Log
func GetEventType(log *types.Log) EventType {
erc20_721TransferEventSignatureHash := getEventSignatureHash(erc20_721TransferEventSignature)
uniswapV2SwapEventSignatureHash := getEventSignatureHash(uniswapV2SwapEventSignature)
uniswapV3SwapEventSignatureHash := getEventSignatureHash(uniswapV3SwapEventSignature)
erc20_721TransferEventSignatureHash := GetEventSignatureHash(Erc20_721TransferEventSignature)
uniswapV2SwapEventSignatureHash := GetEventSignatureHash(uniswapV2SwapEventSignature)
uniswapV3SwapEventSignatureHash := GetEventSignatureHash(uniswapV3SwapEventSignature)
if len(log.Topics) > 0 {
switch log.Topics[0] {
case erc20_721TransferEventSignatureHash:
switch len(log.Topics) {
case erc20TransferEventIndexedParameters:
return erc20TransferEventType
return Erc20TransferEventType
case erc721TransferEventIndexedParameters:
return erc721TransferEventType
return Erc721TransferEventType
}
case uniswapV2SwapEventSignatureHash:
return uniswapV2SwapEventType
return UniswapV2SwapEventType
case uniswapV3SwapEventSignatureHash:
return uniswapV3SwapEventType
return UniswapV3SwapEventType
}
}
return unknownEventType
return UnknownEventType
}
func EventTypeToSubtransactionType(eventType EventType) Type {
switch eventType {
case erc20TransferEventType:
return erc20Transfer
case erc721TransferEventType:
return erc721Transfer
case uniswapV2SwapEventType:
return uniswapV2Swap
case uniswapV3SwapEventType:
return uniswapV3Swap
case Erc20TransferEventType:
return Erc20Transfer
case Erc721TransferEventType:
return Erc721Transfer
case UniswapV2SwapEventType:
return UniswapV2Swap
case UniswapV3SwapEventType:
return UniswapV3Swap
}
return unknownTransaction
@ -88,20 +91,20 @@ func EventTypeToSubtransactionType(eventType EventType) Type {
func GetFirstEvent(logs []*types.Log) (EventType, *types.Log) {
for _, log := range logs {
eventType := GetEventType(log)
if eventType != unknownEventType {
if eventType != UnknownEventType {
return eventType, log
}
}
return unknownEventType, nil
return UnknownEventType, nil
}
func IsTokenTransfer(logs []*types.Log) bool {
eventType, _ := GetFirstEvent(logs)
return eventType == erc20TransferEventType
return eventType == Erc20TransferEventType
}
func parseErc20TransferLog(ethlog *types.Log) (from, to common.Address, amount *big.Int) {
func ParseErc20TransferLog(ethlog *types.Log) (from, to common.Address, amount *big.Int) {
amount = new(big.Int)
if len(ethlog.Topics) < 3 {
log.Warn("not enough topics for erc20 transfer", "topics", ethlog.Topics)
@ -126,7 +129,7 @@ func parseErc20TransferLog(ethlog *types.Log) (from, to common.Address, amount *
return
}
func parseErc721TransferLog(ethlog *types.Log) (from, to common.Address, tokenID *big.Int) {
func ParseErc721TransferLog(ethlog *types.Log) (from, to common.Address, tokenID *big.Int) {
tokenID = new(big.Int)
if len(ethlog.Topics) < 4 {
log.Warn("not enough topics for erc721 transfer", "topics", ethlog.Topics)
@ -151,7 +154,7 @@ func parseErc721TransferLog(ethlog *types.Log) (from, to common.Address, tokenID
return
}
func parseUniswapV2Log(ethlog *types.Log) (pairAddress common.Address, from common.Address, to common.Address, amount0In *big.Int, amount1In *big.Int, amount0Out *big.Int, amount1Out *big.Int, err error) {
func ParseUniswapV2Log(ethlog *types.Log) (pairAddress common.Address, from common.Address, to common.Address, amount0In *big.Int, amount1In *big.Int, amount0Out *big.Int, amount1Out *big.Int, err error) {
amount0In = new(big.Int)
amount1In = new(big.Int)
amount0Out = new(big.Int)
@ -199,7 +202,7 @@ func readInt256(b []byte) *big.Int {
return ret
}
func parseUniswapV3Log(ethlog *types.Log) (poolAddress common.Address, sender common.Address, recipient common.Address, amount0 *big.Int, amount1 *big.Int, err error) {
func ParseUniswapV3Log(ethlog *types.Log) (poolAddress common.Address, sender common.Address, recipient common.Address, amount0 *big.Int, amount1 *big.Int, err error) {
amount0 = new(big.Int)
amount1 = new(big.Int)
@ -229,3 +232,35 @@ func parseUniswapV3Log(ethlog *types.Log) (poolAddress common.Address, sender co
return
}
func GetEventSignatureHash(signature string) common.Hash {
return crypto.Keccak256Hash([]byte(signature))
}
func ExtractTokenIdentity(dbEntryType Type, log *types.Log, tx *types.Transaction) (correctType Type, tokenAddress *common.Address, tokenID *big.Int, value *big.Int) {
// erc721 transfers share signature with erc20 ones, so they both used to be categorized as erc20
// by the Downloader. We fix this here since they might be mis-categorized in the db.
if dbEntryType == Erc20Transfer {
eventType := GetEventType(log)
correctType = EventTypeToSubtransactionType(eventType)
} else {
correctType = dbEntryType
}
switch correctType {
case EthTransfer:
if tx != nil {
value = new(big.Int).Set(tx.Value())
}
case Erc20Transfer:
tokenAddress = new(common.Address)
*tokenAddress = log.Address
_, _, value = ParseErc20TransferLog(log)
case Erc721Transfer:
tokenAddress = new(common.Address)
*tokenAddress = log.Address
_, _, tokenID = ParseErc721TransferLog(log)
}
return
}

View File

@ -11,8 +11,10 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/rpc/chain"
"github.com/status-im/status-go/services/wallet/async"
w_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/token"
"github.com/status-im/status-go/services/wallet/walletevent"
)
@ -450,7 +452,7 @@ func (c *transfersCommand) checkAndProcessPendingMultiTx(subTx *Transfer) (Multi
func (c *transfersCommand) checkAndProcessSwapMultiTx(ctx context.Context, subTx *Transfer) (MultiTransactionIDType, error) {
switch subTx.Type {
// If the Tx contains any uniswapV2Swap/uniswapV3Swap subTx, generate a Swap multiTx
case uniswapV2Swap, uniswapV3Swap:
case w_common.UniswapV2Swap, w_common.UniswapV3Swap:
multiTransaction, err := buildUniswapSwapMultitransaction(ctx, c.chainClient, c.tokenManager, subTx)
if err != nil {
return NoMultiTransactionID, err

View File

@ -12,7 +12,10 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/services/wallet/bigint"
w_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/sqlite"
)
// DBHeader fields from header that are stored in database.
@ -25,7 +28,7 @@ type DBHeader struct {
Address common.Address
// Head is true if the block was a head at the time it was pulled from chain.
Head bool
// Loaded is true if trasfers from this block has been already fetched
// Loaded is true if transfers from this block have been already fetched
Loaded bool
}
@ -364,15 +367,15 @@ func insertBlocksWithTransactions(chainID uint64, creator statementCreator, acco
return err
}
updateTx, err := creator.Prepare(`UPDATE transfers
SET log = ?
SET log = ?, log_index = ?
WHERE network_id = ? AND address = ? AND hash = ?`)
if err != nil {
return err
}
insertTx, err := creator.Prepare(`INSERT OR IGNORE
INTO transfers (network_id, address, sender, hash, blk_number, blk_hash, type, timestamp, log, loaded)
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, 0)`)
INTO transfers (network_id, address, sender, hash, blk_number, blk_hash, type, timestamp, log, loaded, log_index)
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, 0, ?)`)
if err != nil {
return err
}
@ -383,7 +386,12 @@ func insertBlocksWithTransactions(chainID uint64, creator statementCreator, acco
return err
}
for _, transaction := range header.PreloadedTransactions {
res, err := updateTx.Exec(&JSONBlob{transaction.Log}, chainID, account, transaction.ID)
var logIndex *uint
if transaction.Log != nil {
logIndex = new(uint)
*logIndex = transaction.Log.Index
}
res, err := updateTx.Exec(&JSONBlob{transaction.Log}, logIndex, chainID, account, transaction.ID)
if err != nil {
return err
}
@ -395,9 +403,9 @@ func insertBlocksWithTransactions(chainID uint64, creator statementCreator, acco
continue
}
_, err = insertTx.Exec(chainID, account, account, transaction.ID, (*bigint.SQLBigInt)(header.Number), header.Hash, erc20Transfer, &JSONBlob{transaction.Log})
_, err = insertTx.Exec(chainID, account, account, transaction.ID, (*bigint.SQLBigInt)(header.Number), header.Hash, w_common.Erc20Transfer, &JSONBlob{transaction.Log}, logIndex)
if err != nil {
log.Error("error saving erc20transfer", "err", err)
log.Error("error saving Erc20transfer", "err", err)
return err
}
}
@ -407,14 +415,70 @@ func insertBlocksWithTransactions(chainID uint64, creator statementCreator, acco
func updateOrInsertTransfers(chainID uint64, creator statementCreator, transfers []Transfer) error {
insert, err := creator.Prepare(`INSERT OR REPLACE INTO transfers
(network_id, hash, blk_hash, blk_number, timestamp, address, tx, sender, receipt, log, type, loaded, base_gas_fee, multi_transaction_id)
(network_id, hash, blk_hash, blk_number, timestamp, address, tx, sender, receipt, log, type, loaded, base_gas_fee, multi_transaction_id,
status, receipt_type, tx_hash, log_index, block_hash, cumulative_gas_used, contract_address, gas_used, tx_index,
tx_type, protected, gas_limit, gas_price_clamped64, gas_tip_cap_clamped64, gas_fee_cap_clamped64, amount_padded128hex, account_nonce, size, token_address, token_id)
VALUES
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)`)
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
if err != nil {
return err
}
for _, t := range transfers {
_, err = insert.Exec(chainID, t.ID, t.BlockHash, (*bigint.SQLBigInt)(t.BlockNumber), t.Timestamp, t.Address, &JSONBlob{t.Transaction}, t.From, &JSONBlob{t.Receipt}, &JSONBlob{t.Log}, t.Type, t.BaseGasFees, t.MultiTransactionID)
var receiptType *uint8
var txHash, blockHash *common.Hash
var receiptStatus, cumulativeGasUsed, gasUsed *uint64
var contractAddress *common.Address
var transactionIndex, logIndex *uint
if t.Receipt != nil {
receiptType = &t.Receipt.Type
receiptStatus = &t.Receipt.Status
txHash = &t.Receipt.TxHash
if t.Log != nil {
logIndex = new(uint)
*logIndex = t.Log.Index
}
blockHash = &t.Receipt.BlockHash
cumulativeGasUsed = &t.Receipt.CumulativeGasUsed
contractAddress = &t.Receipt.ContractAddress
gasUsed = &t.Receipt.GasUsed
transactionIndex = &t.Receipt.TransactionIndex
}
var txProtected *bool
var txGas, txNonce, txSize *uint64
var txGasPrice, txGasTipCap, txGasFeeCap *int64
var txType *uint8
var txValue *string
var tokenAddress *common.Address
var tokenID *big.Int
if t.Transaction != nil {
var value *big.Int
if t.Log != nil {
_, tokenAddress, tokenID, value = w_common.ExtractTokenIdentity(t.Type, t.Log, t.Transaction)
} else {
value = new(big.Int).Set(t.Transaction.Value())
}
txType = new(uint8)
*txType = t.Transaction.Type()
txProtected = new(bool)
*txProtected = t.Transaction.Protected()
txGas = new(uint64)
*txGas = t.Transaction.Gas()
txGasPrice = sqlite.BigIntToClampedInt64(t.Transaction.GasPrice())
txGasTipCap = sqlite.BigIntToClampedInt64(t.Transaction.GasTipCap())
txGasFeeCap = sqlite.BigIntToClampedInt64(t.Transaction.GasFeeCap())
txValue = sqlite.BigIntToPadded128BitsStr(value)
txNonce = new(uint64)
*txNonce = t.Transaction.Nonce()
txSize = new(uint64)
*txSize = uint64(t.Transaction.Size())
}
_, err = insert.Exec(chainID, t.ID, t.BlockHash, (*bigint.SQLBigInt)(t.BlockNumber), t.Timestamp, t.Address, &JSONBlob{t.Transaction}, t.From, &JSONBlob{t.Receipt}, &JSONBlob{t.Log}, t.Type, t.BaseGasFees, t.MultiTransactionID,
receiptStatus, receiptType, txHash, logIndex, blockHash, cumulativeGasUsed, contractAddress, gasUsed, transactionIndex,
txType, txProtected, txGas, txGasPrice, txGasTipCap, txGasFeeCap, txValue, txNonce, txSize, &sqlite.JSONBlob{Data: tokenAddress}, (*bigint.SQLBigIntBytes)(tokenID))
if err != nil {
log.Error("can't save transfer", "b-hash", t.BlockHash, "b-n", t.BlockNumber, "a", t.Address, "h", t.ID)
return err

View File

@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/status-im/status-go/appdatabase"
w_common "github.com/status-im/status-go/services/wallet/common"
)
func setupTestDB(t *testing.T) (*Database, *BlockDAO, func()) {
@ -28,11 +29,11 @@ func TestDBProcessBlocks(t *testing.T) {
from := big.NewInt(0)
to := big.NewInt(10)
blocks := []*DBHeader{
&DBHeader{
{
Number: big.NewInt(1),
Hash: common.Hash{1},
},
&DBHeader{
{
Number: big.NewInt(2),
Hash: common.Hash{2},
}}
@ -48,7 +49,7 @@ func TestDBProcessBlocks(t *testing.T) {
transfers := []Transfer{
{
ID: common.Hash{1},
Type: ethTransfer,
Type: w_common.EthTransfer,
BlockHash: common.Hash{2},
BlockNumber: big.NewInt(1),
Address: common.Address{1},
@ -71,7 +72,7 @@ func TestDBProcessTransfer(t *testing.T) {
transfers := []Transfer{
{
ID: common.Hash{1},
Type: ethTransfer,
Type: w_common.EthTransfer,
BlockHash: header.Hash,
BlockNumber: header.Number,
Transaction: tx,
@ -115,7 +116,7 @@ func TestDBReorgTransfers(t *testing.T) {
}
require.NoError(t, db.ProcessBlocks(777, original.Address, original.Number, lastBlock, []*DBHeader{original}))
require.NoError(t, db.ProcessTransfers(777, []Transfer{
{ethTransfer, common.Hash{1}, *originalTX.To(), original.Number, original.Hash, 100, originalTX, true, 1777, common.Address{1}, rcpt, nil, "2100", NoMultiTransactionID},
{w_common.EthTransfer, common.Hash{1}, *originalTX.To(), original.Number, original.Hash, 100, originalTX, true, 1777, common.Address{1}, rcpt, nil, "2100", NoMultiTransactionID},
}, []*DBHeader{}))
nonce = int64(0)
lastBlock = &Block{
@ -125,7 +126,7 @@ func TestDBReorgTransfers(t *testing.T) {
}
require.NoError(t, db.ProcessBlocks(777, replaced.Address, replaced.Number, lastBlock, []*DBHeader{replaced}))
require.NoError(t, db.ProcessTransfers(777, []Transfer{
{ethTransfer, common.Hash{2}, *replacedTX.To(), replaced.Number, replaced.Hash, 100, replacedTX, true, 1777, common.Address{1}, rcpt, nil, "2100", NoMultiTransactionID},
{w_common.EthTransfer, common.Hash{2}, *replacedTX.To(), replaced.Number, replaced.Hash, 100, replacedTX, true, 1777, common.Address{1}, rcpt, nil, "2100", NoMultiTransactionID},
}, []*DBHeader{original}))
all, err := db.GetTransfers(777, big.NewInt(0), nil)
@ -151,7 +152,7 @@ func TestDBGetTransfersFromBlock(t *testing.T) {
receipt.Logs = []*types.Log{}
transfer := Transfer{
ID: tx.Hash(),
Type: ethTransfer,
Type: w_common.EthTransfer,
BlockNumber: header.Number,
BlockHash: header.Hash,
Transaction: tx,

View File

@ -13,7 +13,9 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/rpc/chain"
w_common "github.com/status-im/status-go/services/wallet/common"
)
type MultiTransactionIDType int64
@ -22,10 +24,6 @@ const (
NoMultiTransactionID = MultiTransactionIDType(0)
)
func getEventSignatureHash(signature string) common.Hash {
return crypto.Keccak256Hash([]byte(signature))
}
func getLogSubTxID(log types.Log) common.Hash {
// Get unique ID by using TxHash and log index
index := [4]byte{}
@ -45,7 +43,7 @@ var (
// To be converted into one or many Transfer objects post-indexing.
type PreloadedTransaction struct {
NetworkID uint64
Type Type `json:"type"`
Type w_common.Type `json:"type"`
ID common.Hash `json:"-"`
Address common.Address `json:"address"`
BlockNumber *big.Int `json:"blockNumber"`
@ -61,7 +59,7 @@ type PreloadedTransaction struct {
// Transfer stores information about transfer.
// A Transfer represents a plain ETH transfer or some token activity inside a Transaction
type Transfer struct {
Type Type `json:"type"`
Type w_common.Type `json:"type"`
ID common.Hash `json:"-"`
Address common.Address `json:"address"`
BlockNumber *big.Int `json:"blockNumber"`
@ -114,8 +112,8 @@ func getTransferByHash(ctx context.Context, client *chain.ClientWithFallback, si
return nil, err
}
eventType, transactionLog := GetFirstEvent(receipt.Logs)
transactionType := EventTypeToSubtransactionType(eventType)
eventType, transactionLog := w_common.GetFirstEvent(receipt.Logs)
transactionType := w_common.EventTypeToSubtransactionType(eventType)
from, err := types.Sender(signer, transaction)
@ -184,7 +182,7 @@ func (d *ETHDownloader) getTransfersInBlock(ctx context.Context, blk *types.Bloc
return nil, err
}
eventType, _ := GetFirstEvent(receipt.Logs)
eventType, _ := w_common.GetFirstEvent(receipt.Logs)
baseGasFee, err := d.chainClient.GetBaseFeeFromBlock(blk.Number())
if err != nil {
@ -193,9 +191,9 @@ func (d *ETHDownloader) getTransfersInBlock(ctx context.Context, blk *types.Bloc
// If the transaction is not already some known transfer type, add it
// to the list as a plain eth transfer
if eventType == unknownEventType {
if eventType == w_common.UnknownEventType {
rst = append(rst, Transfer{
Type: ethTransfer,
Type: w_common.EthTransfer,
ID: tx.Hash(),
Address: address,
BlockNumber: blk.Number(),
@ -218,7 +216,7 @@ func (d *ETHDownloader) getTransfersInBlock(ctx context.Context, blk *types.Bloc
// NewERC20TransfersDownloader returns new instance.
func NewERC20TransfersDownloader(client *chain.ClientWithFallback, accounts []common.Address, signer types.Signer) *ERC20TransfersDownloader {
signature := getEventSignatureHash(erc20_721TransferEventSignature)
signature := w_common.GetEventSignatureHash(w_common.Erc20_721TransferEventSignature)
return &ERC20TransfersDownloader{
client: client,
@ -230,7 +228,7 @@ func NewERC20TransfersDownloader(client *chain.ClientWithFallback, accounts []co
// ERC20TransfersDownloader is a downloader for erc20 and erc721 tokens transfers.
// Since both transaction types share the same signature, both will be assigned
// type erc20Transfer. Until the downloader gets refactored and a migration of the
// type Erc20Transfer. Until the downloader gets refactored and a migration of the
// database gets implemented, differentiation between erc20 and erc721 will handled
// in the controller.
type ERC20TransfersDownloader struct {
@ -291,28 +289,28 @@ func (d *ETHDownloader) subTransactionsFromTransactionHash(parent context.Contex
rst := make([]Transfer, 0, len(receipt.Logs))
for _, log := range receipt.Logs {
eventType := GetEventType(log)
eventType := w_common.GetEventType(log)
// Only add ERC20/ERC721 transfers from/to the given account
// Other types of events get always added
mustAppend := false
switch eventType {
case erc20TransferEventType:
from, to, _ := parseErc20TransferLog(log)
case w_common.Erc20TransferEventType:
from, to, _ := w_common.ParseErc20TransferLog(log)
if from == address || to == address {
mustAppend = true
}
case erc721TransferEventType:
from, to, _ := parseErc721TransferLog(log)
case w_common.Erc721TransferEventType:
from, to, _ := w_common.ParseErc721TransferLog(log)
if from == address || to == address {
mustAppend = true
}
case uniswapV2SwapEventType, uniswapV3SwapEventType:
case w_common.UniswapV2SwapEventType, w_common.UniswapV3SwapEventType:
mustAppend = true
}
if mustAppend {
transfer := Transfer{
Type: EventTypeToSubtransactionType(eventType),
Type: w_common.EventTypeToSubtransactionType(eventType),
ID: getLogSubTxID(*log),
Address: address,
BlockNumber: new(big.Int).SetUint64(log.BlockNumber),
@ -359,7 +357,7 @@ func (d *ERC20TransfersDownloader) blocksFromLogs(parent context.Context, logs [
ID: id,
From: address,
Loaded: false,
Type: erc20Transfer,
Type: w_common.Erc20Transfer,
Log: &l,
BaseGasFees: baseGasFee,
}},

View File

@ -53,7 +53,7 @@ func (q *transfersQuery) addWhereSeparator(separator SeparatorType) {
type SeparatorType int
// Beware if changing this enum please update addWhereSeparator as well
// Beware: please update addWhereSeparator if changing this enum
const (
NoSeparator SeparatorType = iota + 1
OrSeparator

View File

@ -9,9 +9,11 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
uniswapv2 "github.com/status-im/status-go/contracts/uniswapV2"
uniswapv3 "github.com/status-im/status-go/contracts/uniswapV3"
"github.com/status-im/status-go/rpc/chain"
w_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/token"
)
@ -86,7 +88,7 @@ func identifyUniswapV2Asset(tokenManager *token.Manager, chainID uint64, amount0
}
func fetchUniswapV2Info(ctx context.Context, client *chain.ClientWithFallback, tokenManager *token.Manager, log *types.Log) (fromAsset string, fromAmount *hexutil.Big, toAsset string, toAmount *hexutil.Big, err error) {
pairAddress, _, _, amount0In, amount1In, amount0Out, amount1Out, err := parseUniswapV2Log(log)
pairAddress, _, _, amount0In, amount1In, amount0Out, amount1Out, err := w_common.ParseUniswapV2Log(log)
if err != nil {
return
}
@ -155,7 +157,7 @@ func identifyUniswapV3Assets(tokenManager *token.Manager, chainID uint64, amount
}
func fetchUniswapV3Info(ctx context.Context, client *chain.ClientWithFallback, tokenManager *token.Manager, log *types.Log) (fromAsset string, fromAmount *hexutil.Big, toAsset string, toAmount *hexutil.Big, err error) {
poolAddress, _, _, amount0, amount1, err := parseUniswapV3Log(log)
poolAddress, _, _, amount0, amount1, err := w_common.ParseUniswapV3Log(log)
if err != nil {
return
}
@ -183,11 +185,11 @@ func fetchUniswapV3Info(ctx context.Context, client *chain.ClientWithFallback, t
return
}
func fetchUniswapInfo(ctx context.Context, client *chain.ClientWithFallback, tokenManager *token.Manager, log *types.Log, logType EventType) (fromAsset string, fromAmount *hexutil.Big, toAsset string, toAmount *hexutil.Big, err error) {
func fetchUniswapInfo(ctx context.Context, client *chain.ClientWithFallback, tokenManager *token.Manager, log *types.Log, logType w_common.EventType) (fromAsset string, fromAmount *hexutil.Big, toAsset string, toAmount *hexutil.Big, err error) {
switch logType {
case uniswapV2SwapEventType:
case w_common.UniswapV2SwapEventType:
return fetchUniswapV2Info(ctx, client, tokenManager, log)
case uniswapV3SwapEventType:
case w_common.UniswapV3SwapEventType:
return fetchUniswapV3Info(ctx, client, tokenManager, log)
}
err = fmt.Errorf("wrong log type %s", logType)
@ -204,12 +206,12 @@ func buildUniswapSwapMultitransaction(ctx context.Context, client *chain.ClientW
}
var firstSwapLog, lastSwapLog *types.Log
var firstSwapLogType, lastSwapLogType EventType
var firstSwapLogType, lastSwapLogType w_common.EventType
for _, ethlog := range transfer.Receipt.Logs {
logType := GetEventType(ethlog)
logType := w_common.GetEventType(ethlog)
switch logType {
case uniswapV2SwapEventType, uniswapV3SwapEventType:
case w_common.UniswapV2SwapEventType, w_common.UniswapV3SwapEventType:
if firstSwapLog == nil {
firstSwapLog = ethlog
firstSwapLogType = logType

View File

@ -5,13 +5,14 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
w_common "github.com/status-im/status-go/services/wallet/common"
)
// View stores only fields used by a client and ensures that all relevant fields are
// encoded in hex.
type View struct {
ID common.Hash `json:"id"`
Type Type `json:"type"`
Type w_common.Type `json:"type"`
Address common.Address `json:"address"`
BlockNumber *hexutil.Big `json:"blockNumber"`
BlockHash common.Hash `json:"blockhash"`
@ -27,8 +28,8 @@ type View struct {
TxStatus hexutil.Uint64 `json:"txStatus"`
Input hexutil.Bytes `json:"input"`
TxHash common.Hash `json:"txHash"`
Value *hexutil.Big `json:"value"` // Only used for Type ethTransfer and erc20Transfer
TokenID *hexutil.Big `json:"tokenId"` // Only used for Type erc721Transfer
Value *hexutil.Big `json:"value"` // Only used for Type EthTransfer and Erc20Transfer
TokenID *hexutil.Big `json:"tokenId"` // Only used for Type Erc721Transfer
From common.Address `json:"from"`
To common.Address `json:"to"`
Contract common.Address `json:"contract"`
@ -41,7 +42,7 @@ func castToTransferViews(transfers []Transfer) []View {
views := make([]View, 0, len(transfers))
for _, tx := range transfers {
switch tx.Type {
case ethTransfer, erc20Transfer, erc721Transfer:
case w_common.EthTransfer, w_common.Erc20Transfer, w_common.Erc721Transfer:
view := CastToTransferView(tx)
views = append(views, view)
}
@ -82,20 +83,20 @@ func CastToTransferView(t Transfer) View {
tokenID := new(hexutil.Big)
switch view.Type {
case ethTransfer:
case w_common.EthTransfer:
view.From = t.From
if t.Transaction.To() != nil {
view.To = *t.Transaction.To()
}
value = (*hexutil.Big)(t.Transaction.Value())
view.Contract = t.Receipt.ContractAddress
case erc20Transfer:
case w_common.Erc20Transfer:
view.Contract = t.Log.Address
from, to, valueInt := parseErc20TransferLog(t.Log)
from, to, valueInt := w_common.ParseErc20TransferLog(t.Log)
view.From, view.To, value = from, to, (*hexutil.Big)(valueInt)
case erc721Transfer:
case w_common.Erc721Transfer:
view.Contract = t.Log.Address
from, to, tokenIDInt := parseErc721TransferLog(t.Log)
from, to, tokenIDInt := w_common.ParseErc721TransferLog(t.Log)
view.From, view.To, tokenID = from, to, (*hexutil.Big)(tokenIDInt)
}
@ -106,12 +107,12 @@ func CastToTransferView(t Transfer) View {
return view
}
func getFixedTransferType(tx Transfer) Type {
func getFixedTransferType(tx Transfer) w_common.Type {
// erc721 transfers share signature with erc20 ones, so they both used to be categorized as erc20
// by the Downloader. We fix this here since they might be mis-categorized in the db.
if tx.Type == erc20Transfer {
eventType := GetEventType(tx.Log)
return EventTypeToSubtransactionType(eventType)
if tx.Type == w_common.Erc20Transfer {
eventType := w_common.GetEventType(tx.Log)
return w_common.EventTypeToSubtransactionType(eventType)
}
return tx.Type
}

View File

@ -4,28 +4,44 @@ import (
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"math"
"math/big"
"reflect"
)
// JSONBlob type for marshaling/unmarshaling inner type to json.
type JSONBlob struct {
Data interface{}
Data interface{}
Valid bool
}
// Scan implements interface.
func (blob *JSONBlob) Scan(value interface{}) error {
dataVal := reflect.ValueOf(blob.Data)
blob.Valid = false
if value == nil || dataVal.Kind() == reflect.Ptr && dataVal.IsNil() {
return nil
}
bytes, ok := value.([]byte)
var bytes []byte
ok := true
switch v := value.(type) {
case []byte:
bytes, ok = value.([]byte)
case string:
bytes = []byte(v)
default:
ok = false
}
if !ok {
return errors.New("not a byte slice")
return errors.New("not a byte slice or string")
}
if len(bytes) == 0 {
return nil
}
err := json.Unmarshal(bytes, blob.Data)
blob.Valid = err == nil
return err
}
@ -45,3 +61,29 @@ func (blob *JSONBlob) Value() (driver.Value, error) {
return json.Marshal(blob.Data)
}
func BigIntToClampedInt64(val *big.Int) *int64 {
if val == nil {
return nil
}
var v int64
if val.IsInt64() {
v = val.Int64()
} else {
v = math.MaxInt64
}
return &v
}
// BigIntToPadded128BitsStr converts a big.Int to a string, padding it with 0 to account for 128 bits size
// Returns nil if input val is nil
// This should work to sort and compare big.Ints values in SQLite
func BigIntToPadded128BitsStr(val *big.Int) *string {
if val == nil {
return nil
}
hexStr := val.Text(16)
res := new(string)
*res = fmt.Sprintf("%032s", hexStr)
return res
}

59
sqlite/fields_test.go Normal file
View File

@ -0,0 +1,59 @@
package sqlite
import (
"math/big"
"testing"
)
func strToPtr(s string) *string {
res := new(string)
*res = s
return res
}
func TestBigIntToPadded128BitsStr(t *testing.T) {
testCases := []struct {
name string
input *big.Int
expected *string
}{
{
name: "case small",
input: big.NewInt(123456),
expected: strToPtr("0000000000000000000000000001e240"),
},
{
name: "case zero",
input: big.NewInt(0),
expected: strToPtr("00000000000000000000000000000000"),
},
{
name: "case very large",
input: new(big.Int).Exp(big.NewInt(10), big.NewInt(26), nil),
expected: strToPtr("000000000052b7d2dcc80cd2e4000000"),
},
{
name: "case max",
input: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 128), big.NewInt(1)),
expected: strToPtr("ffffffffffffffffffffffffffffffff"),
},
{
name: "case 3",
input: nil,
expected: nil,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := BigIntToPadded128BitsStr(tc.input)
if result != nil && tc.expected != nil {
if *result != *tc.expected {
t.Errorf("expected %s, got %s", *tc.expected, *result)
}
} else if result != nil || tc.expected != nil {
t.Errorf("expected %v, got %v", tc.expected, result)
}
})
}
}

View File

@ -2,37 +2,178 @@ package sqlite
import (
"database/sql"
"fmt"
"sort"
"github.com/status-im/migrate/v4"
"github.com/status-im/migrate/v4/database/sqlcipher"
bindata "github.com/status-im/migrate/v4/source/go_bindata"
)
// Migrate database using provided resources.
func Migrate(db *sql.DB, resources *bindata.AssetSource) error {
type PostStep struct {
Version uint
CustomMigration func(tx *sql.Tx) error
RollBackVersion uint
}
var migrationTable = "status_go_" + sqlcipher.DefaultMigrationsTable
// Migrate database with option to augment the migration steps with additional processing using the customSteps
// parameter. For each PostStep entry in customSteps the CustomMigration will be called after the migration step
// with the matching Version number has been executed. If the CustomMigration returns an error, the migration process
// is aborted. In case the custom step failures the migrations are run down to RollBackVersion if > 0.
//
// The recommended way to create a custom migration is by providing empty and versioned run/down sql files as markers.
// Then running all the SQL code inside the same transaction to transform and commit provides the possibility
// to completely rollback the migration in case of failure, avoiding to leave the DB in an inconsistent state.
//
// Marker migrations can be created by using PostStep structs with specific Version numbers and a callback function,
// even when no accompanying SQL migration is needed. This can be used to trigger Go code at specific points
// during the migration process.
//
// Caution: This mechanism should be used as a last resort. Prefer data migration using SQL migration files
// whenever possible to ensure consistency and compatibility with standard migration tools.
//
// untilVersion, for testing purposes optional parameter, can be used to limit the migration to a specific version.
// Pass nil to migrate to the latest available version.
func Migrate(db *sql.DB, resources *bindata.AssetSource, customSteps []PostStep, untilVersion *uint) error {
source, err := bindata.WithInstance(resources)
if err != nil {
return err
return fmt.Errorf("failed to create bindata migration source: %w", err)
}
driver, err := sqlcipher.WithInstance(db, &sqlcipher.Config{
MigrationsTable: "status_go_" + sqlcipher.DefaultMigrationsTable,
MigrationsTable: migrationTable,
})
if err != nil {
return err
return fmt.Errorf("failed to create sqlcipher driver: %w", err)
}
m, err := migrate.NewWithInstance(
"go-bindata",
source,
"sqlcipher",
driver)
m, err := migrate.NewWithInstance("go-bindata", source, "sqlcipher", driver)
if err != nil {
return fmt.Errorf("failed to create migration instance: %w", err)
}
if len(customSteps) == 0 {
return runRemainingMigrations(m, untilVersion)
}
sort.Slice(customSteps, func(i, j int) bool {
return customSteps[i].Version < customSteps[j].Version
})
lastVersion, err := getCurrentVersion(m, db)
if err != nil {
return err
}
if err = m.Up(); err != migrate.ErrNoChange {
customIndex := 0
// ignore processed versions
for customIndex < len(customSteps) && customSteps[customIndex].Version <= lastVersion {
customIndex++
}
if err := runCustomMigrations(m, db, customSteps, customIndex, untilVersion); err != nil {
return err
}
return runRemainingMigrations(m, untilVersion)
}
// runCustomMigrations performs source migrations from current to each custom steps, then runs custom migration callback
// until it executes all custom migrations or an error occurs and it tries to rollback to RollBackVersion if > 0.
func runCustomMigrations(m *migrate.Migrate, db *sql.DB, customSteps []PostStep, customIndex int, untilVersion *uint) error {
for customIndex < len(customSteps) && (untilVersion == nil || customSteps[customIndex].Version <= *untilVersion) {
customStep := customSteps[customIndex]
if err := m.Migrate(customStep.Version); err != nil && err != migrate.ErrNoChange {
return fmt.Errorf("failed to migrate to version %d: %w", customStep.Version, err)
}
if err := runCustomMigrationStep(db, customStep, m); err != nil {
return err
}
customIndex++
}
return nil
}
func runCustomMigrationStep(db *sql.DB, customStep PostStep, m *migrate.Migrate) error {
sqlTx, err := db.Begin()
if err != nil {
return fmt.Errorf("failed to begin transaction: %w", err)
}
if err := customStep.CustomMigration(sqlTx); err != nil {
_ = sqlTx.Rollback()
return rollbackCustomMigration(m, customStep, err)
}
if err := sqlTx.Commit(); err != nil {
return fmt.Errorf("failed to commit transaction: %w", err)
}
return nil
}
func rollbackCustomMigration(m *migrate.Migrate, customStep PostStep, customErr error) error {
if customStep.RollBackVersion > 0 {
err := m.Migrate(customStep.RollBackVersion)
newV, _, _ := m.Version()
if err != nil {
return fmt.Errorf("failed to rollback migration to version %d: %w", customStep.RollBackVersion, err)
}
return fmt.Errorf("custom migration step failed for version %d. Successfully rolled back migration to version %d: %w", customStep.Version, newV, customErr)
}
return fmt.Errorf("custom migration step failed for version %d: %w", customStep.Version, customErr)
}
func runRemainingMigrations(m *migrate.Migrate, untilVersion *uint) error {
if untilVersion != nil {
if err := m.Migrate(*untilVersion); err != nil && err != migrate.ErrNoChange {
return fmt.Errorf("failed to migrate to version %d: %w", *untilVersion, err)
}
} else {
if err := m.Up(); err != nil && err != migrate.ErrNoChange {
return fmt.Errorf("failed to migrate up: %w", err)
}
}
return nil
}
func getCurrentVersion(m *migrate.Migrate, db *sql.DB) (uint, error) {
lastVersion, dirty, err := m.Version()
if err != nil && err != migrate.ErrNilVersion {
return 0, fmt.Errorf("failed to get migration version: %w", err)
}
if dirty {
return 0, fmt.Errorf("DB is dirty after migration version %d", lastVersion)
}
if err == migrate.ErrNilVersion {
lastVersion, _, err = GetLastMigrationVersion(db)
return lastVersion, err
}
return lastVersion, nil
}
// GetLastMigrationVersion returns the last migration version stored in the migration table.
// Returns 0 for version in case migrationTableExists is true
func GetLastMigrationVersion(db *sql.DB) (version uint, migrationTableExists bool, err error) {
// Check if the migration table exists
row := db.QueryRow("SELECT exists(SELECT name FROM sqlite_master WHERE type='table' AND name=?)", migrationTable)
migrationTableExists = false
err = row.Scan(&migrationTableExists)
if err != nil && err != sql.ErrNoRows {
return 0, false, err
}
var lastMigration uint64 = 0
if migrationTableExists {
row = db.QueryRow("SELECT version FROM status_go_schema_migrations")
err = row.Scan(&lastMigration)
if err != nil && err != sql.ErrNoRows {
return 0, true, err
}
}
return uint(lastMigration), migrationTableExists, nil
}