fix(db): enable foreign key enforcement on pooled connections
This commit is contained in:
@@ -123,6 +123,10 @@ pub async fn create_pool(url: Option<&str>) -> Result<DatabasePool, DatabaseSetu
|
|||||||
conn.batch_execute("PRAGMA journal_mode = WAL;")
|
conn.batch_execute("PRAGMA journal_mode = WAL;")
|
||||||
.await
|
.await
|
||||||
.map_err(diesel::ConnectionError::CouldntSetupConfiguration)?;
|
.map_err(diesel::ConnectionError::CouldntSetupConfiguration)?;
|
||||||
|
// Per-connection in SQLite: the migration connection enabling it is not enough.
|
||||||
|
conn.batch_execute("PRAGMA foreign_keys = ON;")
|
||||||
|
.await
|
||||||
|
.map_err(diesel::ConnectionError::CouldntSetupConfiguration)?;
|
||||||
|
|
||||||
Ok(conn)
|
Ok(conn)
|
||||||
})
|
})
|
||||||
@@ -156,3 +160,33 @@ pub async fn create_test_pool() -> DatabasePool {
|
|||||||
.await
|
.await
|
||||||
.expect("Failed to create test database pool")
|
.expect("Failed to create test database pool")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use diesel::{ExpressionMethods as _, dsl::insert_into};
|
||||||
|
use diesel_async::RunQueryDsl;
|
||||||
|
|
||||||
|
/// `operator.id` references `operator_identity(id)`. Without `PRAGMA foreign_keys = ON`
|
||||||
|
/// on the pooled connection, SQLite accepts a share row for an operator that does not exist.
|
||||||
|
#[tokio::test]
|
||||||
|
async fn pooled_connections_enforce_foreign_keys() {
|
||||||
|
let pool = create_test_pool().await;
|
||||||
|
let mut conn = pool.get().await.unwrap();
|
||||||
|
|
||||||
|
let result = insert_into(schema::operator::table)
|
||||||
|
.values((
|
||||||
|
schema::operator::id.eq(4242),
|
||||||
|
schema::operator::share.eq(vec![0u8; 32]),
|
||||||
|
schema::operator::share_nonce.eq(vec![0u8; 24]),
|
||||||
|
schema::operator::share_salt.eq(vec![0u8; 32]),
|
||||||
|
))
|
||||||
|
.execute(&mut conn)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
result.is_err(),
|
||||||
|
"insert with a dangling operator_identity reference was accepted"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -352,16 +352,17 @@ impl Engine {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use alloy::primitives::{Address, Bytes, U256, address};
|
use alloy::primitives::{Address, Bytes, U256, address};
|
||||||
use chrono::{Duration, Utc};
|
use chrono::{Duration, Utc};
|
||||||
use diesel::{SelectableHelper, insert_into};
|
use diesel::{ExpressionMethods as _, SelectableHelper, insert_into};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
use crate::db::{
|
use crate::db::{
|
||||||
self, DatabaseConnection,
|
self, DatabaseConnection, models,
|
||||||
models::{
|
models::{
|
||||||
EvmBasicGrant, EvmWalletAccess, EvmWalletId, NewEvmBasicGrant, NewEvmTransactionLog,
|
EvmBasicGrant, EvmWalletAccess, EvmWalletId, NewEvmBasicGrant, NewEvmTransactionLog,
|
||||||
SqliteTimestamp,
|
SqliteTimestamp,
|
||||||
},
|
},
|
||||||
|
schema,
|
||||||
schema::{evm_basic_grant, evm_transaction_log},
|
schema::{evm_basic_grant, evm_transaction_log},
|
||||||
};
|
};
|
||||||
use crate::evm::policies::{
|
use crate::evm::policies::{
|
||||||
@@ -403,10 +404,82 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates the parent chain a fresh `evm_wallet_access` row needs under foreign-key
|
||||||
|
/// enforcement (a root key, an aead-encrypted secret, a wallet, and a client) and
|
||||||
|
/// returns the new access row's id.
|
||||||
|
async fn seed_wallet_access(conn: &mut DatabaseConnection) -> i32 {
|
||||||
|
let root_key_id: models::RootKeyHistoryId = insert_into(schema::root_key_history::table)
|
||||||
|
.values(&models::NewRootKeyHistory {
|
||||||
|
ciphertext: vec![0u8; 32],
|
||||||
|
tag: vec![0u8; 16],
|
||||||
|
root_key_encryption_nonce: vec![0u8; 24],
|
||||||
|
data_encryption_nonce: vec![0u8; 24],
|
||||||
|
schema_version: 1,
|
||||||
|
salt: vec![0u8; 16],
|
||||||
|
})
|
||||||
|
.returning(schema::root_key_history::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let aead_id: i32 = insert_into(schema::aead_encrypted::table)
|
||||||
|
.values(&models::NewAeadEncrypted {
|
||||||
|
ciphertext: vec![0u8; 32],
|
||||||
|
tag: vec![0u8; 16],
|
||||||
|
current_nonce: vec![0u8; 24],
|
||||||
|
schema_version: 1,
|
||||||
|
associated_root_key_id: root_key_id,
|
||||||
|
created_at: Utc::now().into(),
|
||||||
|
})
|
||||||
|
.returning(schema::aead_encrypted::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let wallet_id: EvmWalletId = insert_into(schema::evm_wallet::table)
|
||||||
|
.values((
|
||||||
|
schema::evm_wallet::address.eq(rand::random::<[u8; 20]>().to_vec()),
|
||||||
|
schema::evm_wallet::aead_encrypted_id.eq(aead_id),
|
||||||
|
))
|
||||||
|
.returning(schema::evm_wallet::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let metadata_id: i32 = insert_into(schema::client_metadata::table)
|
||||||
|
.values(schema::client_metadata::name.eq("test"))
|
||||||
|
.returning(schema::client_metadata::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let client_id: i32 = insert_into(schema::program_client::table)
|
||||||
|
.values((
|
||||||
|
schema::program_client::public_key.eq(rand::random::<[u8; 32]>().to_vec()),
|
||||||
|
schema::program_client::metadata_id.eq(metadata_id),
|
||||||
|
))
|
||||||
|
.returning(schema::program_client::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
insert_into(schema::evm_wallet_access::table)
|
||||||
|
.values((
|
||||||
|
schema::evm_wallet_access::wallet_id.eq(wallet_id),
|
||||||
|
schema::evm_wallet_access::client_id.eq(client_id),
|
||||||
|
))
|
||||||
|
.returning(schema::evm_wallet_access::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
async fn insert_basic_grant(
|
async fn insert_basic_grant(
|
||||||
conn: &mut DatabaseConnection,
|
conn: &mut DatabaseConnection,
|
||||||
shared: &SharedGrantSettings,
|
shared: &SharedGrantSettings,
|
||||||
) -> EvmBasicGrant {
|
) -> EvmBasicGrant {
|
||||||
|
let wallet_access_id = seed_wallet_access(conn).await;
|
||||||
|
|
||||||
#[expect(
|
#[expect(
|
||||||
clippy::cast_possible_truncation,
|
clippy::cast_possible_truncation,
|
||||||
clippy::cast_possible_wrap,
|
clippy::cast_possible_wrap,
|
||||||
@@ -415,7 +488,7 @@ mod tests {
|
|||||||
)]
|
)]
|
||||||
insert_into(evm_basic_grant::table)
|
insert_into(evm_basic_grant::table)
|
||||||
.values(NewEvmBasicGrant {
|
.values(NewEvmBasicGrant {
|
||||||
wallet_access_id: shared.wallet_access_id,
|
wallet_access_id,
|
||||||
chain_id: shared.chain.into(),
|
chain_id: shared.chain.into(),
|
||||||
valid_from: shared.valid_from.map(SqliteTimestamp),
|
valid_from: shared.valid_from.map(SqliteTimestamp),
|
||||||
valid_until: shared.valid_until.map(SqliteTimestamp),
|
valid_until: shared.valid_until.map(SqliteTimestamp),
|
||||||
@@ -579,7 +652,7 @@ mod tests {
|
|||||||
insert_into(evm_transaction_log::table)
|
insert_into(evm_transaction_log::table)
|
||||||
.values(NewEvmTransactionLog {
|
.values(NewEvmTransactionLog {
|
||||||
grant_id: basic_grant.id,
|
grant_id: basic_grant.id,
|
||||||
wallet_access_id: WALLET_ACCESS_ID,
|
wallet_access_id: basic_grant.wallet_access_id,
|
||||||
chain_id: CHAIN_ID.into(),
|
chain_id: CHAIN_ID.into(),
|
||||||
eth_value: super::utils::u256_to_bytes(U256::ZERO).to_vec(),
|
eth_value: super::utils::u256_to_bytes(U256::ZERO).to_vec(),
|
||||||
signed_at: SqliteTimestamp(Utc::now()),
|
signed_at: SqliteTimestamp(Utc::now()),
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
use super::{EtherTransfer, Settings};
|
use super::{EtherTransfer, Settings};
|
||||||
use crate::{
|
use crate::{
|
||||||
db::{
|
db::{
|
||||||
self, DatabaseConnection,
|
self, DatabaseConnection, models,
|
||||||
models::{
|
models::{
|
||||||
EvmBasicGrant, EvmWalletAccess, EvmWalletId, NewEvmBasicGrant, NewEvmTransactionLog,
|
EvmBasicGrant, EvmWalletAccess, EvmWalletId, NewEvmBasicGrant, NewEvmTransactionLog,
|
||||||
SqliteTimestamp,
|
SqliteTimestamp,
|
||||||
},
|
},
|
||||||
|
schema,
|
||||||
schema::{evm_basic_grant, evm_transaction_log},
|
schema::{evm_basic_grant, evm_transaction_log},
|
||||||
},
|
},
|
||||||
evm::{
|
evm::{
|
||||||
@@ -19,7 +20,7 @@ use crate::{
|
|||||||
|
|
||||||
use alloy::primitives::{Address, Bytes, U256, address};
|
use alloy::primitives::{Address, Bytes, U256, address};
|
||||||
use chrono::{Duration, Utc};
|
use chrono::{Duration, Utc};
|
||||||
use diesel::{SelectableHelper, insert_into};
|
use diesel::{ExpressionMethods as _, SelectableHelper, insert_into};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
|
|
||||||
const WALLET_ACCESS_ID: i32 = 1;
|
const WALLET_ACCESS_ID: i32 = 1;
|
||||||
@@ -45,10 +46,82 @@ fn ctx(to: Address, value: U256) -> EvalContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates the parent chain a fresh `evm_wallet_access` row needs under foreign-key
|
||||||
|
/// enforcement (a root key, an aead-encrypted secret, a wallet, and a client) and returns
|
||||||
|
/// the new access row's id.
|
||||||
|
async fn seed_wallet_access(conn: &mut DatabaseConnection) -> i32 {
|
||||||
|
let root_key_id: models::RootKeyHistoryId = insert_into(schema::root_key_history::table)
|
||||||
|
.values(&models::NewRootKeyHistory {
|
||||||
|
ciphertext: vec![0u8; 32],
|
||||||
|
tag: vec![0u8; 16],
|
||||||
|
root_key_encryption_nonce: vec![0u8; 24],
|
||||||
|
data_encryption_nonce: vec![0u8; 24],
|
||||||
|
schema_version: 1,
|
||||||
|
salt: vec![0u8; 16],
|
||||||
|
})
|
||||||
|
.returning(schema::root_key_history::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let aead_id: i32 = insert_into(schema::aead_encrypted::table)
|
||||||
|
.values(&models::NewAeadEncrypted {
|
||||||
|
ciphertext: vec![0u8; 32],
|
||||||
|
tag: vec![0u8; 16],
|
||||||
|
current_nonce: vec![0u8; 24],
|
||||||
|
schema_version: 1,
|
||||||
|
associated_root_key_id: root_key_id,
|
||||||
|
created_at: Utc::now().into(),
|
||||||
|
})
|
||||||
|
.returning(schema::aead_encrypted::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let wallet_id: EvmWalletId = insert_into(schema::evm_wallet::table)
|
||||||
|
.values((
|
||||||
|
schema::evm_wallet::address.eq(rand::random::<[u8; 20]>().to_vec()),
|
||||||
|
schema::evm_wallet::aead_encrypted_id.eq(aead_id),
|
||||||
|
))
|
||||||
|
.returning(schema::evm_wallet::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let metadata_id: i32 = insert_into(schema::client_metadata::table)
|
||||||
|
.values(schema::client_metadata::name.eq("test"))
|
||||||
|
.returning(schema::client_metadata::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let client_id: i32 = insert_into(schema::program_client::table)
|
||||||
|
.values((
|
||||||
|
schema::program_client::public_key.eq(rand::random::<[u8; 32]>().to_vec()),
|
||||||
|
schema::program_client::metadata_id.eq(metadata_id),
|
||||||
|
))
|
||||||
|
.returning(schema::program_client::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
insert_into(schema::evm_wallet_access::table)
|
||||||
|
.values((
|
||||||
|
schema::evm_wallet_access::wallet_id.eq(wallet_id),
|
||||||
|
schema::evm_wallet_access::client_id.eq(client_id),
|
||||||
|
))
|
||||||
|
.returning(schema::evm_wallet_access::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
async fn insert_basic(conn: &mut DatabaseConnection, revoked: bool) -> EvmBasicGrant {
|
async fn insert_basic(conn: &mut DatabaseConnection, revoked: bool) -> EvmBasicGrant {
|
||||||
|
let wallet_access_id = seed_wallet_access(conn).await;
|
||||||
|
|
||||||
insert_into(evm_basic_grant::table)
|
insert_into(evm_basic_grant::table)
|
||||||
.values(NewEvmBasicGrant {
|
.values(NewEvmBasicGrant {
|
||||||
wallet_access_id: WALLET_ACCESS_ID,
|
wallet_access_id,
|
||||||
chain_id: CHAIN_ID.into(),
|
chain_id: CHAIN_ID.into(),
|
||||||
valid_from: None,
|
valid_from: None,
|
||||||
valid_until: None,
|
valid_until: None,
|
||||||
@@ -161,7 +234,7 @@ async fn evaluate_passes_when_volume_within_limit() {
|
|||||||
insert_into(evm_transaction_log::table)
|
insert_into(evm_transaction_log::table)
|
||||||
.values(NewEvmTransactionLog {
|
.values(NewEvmTransactionLog {
|
||||||
grant_id,
|
grant_id,
|
||||||
wallet_access_id: WALLET_ACCESS_ID,
|
wallet_access_id: basic.wallet_access_id,
|
||||||
chain_id: CHAIN_ID.into(),
|
chain_id: CHAIN_ID.into(),
|
||||||
eth_value: utils::u256_to_bytes(U256::from(500u64)).to_vec(),
|
eth_value: utils::u256_to_bytes(U256::from(500u64)).to_vec(),
|
||||||
signed_at: SqliteTimestamp(Utc::now()),
|
signed_at: SqliteTimestamp(Utc::now()),
|
||||||
@@ -203,7 +276,7 @@ async fn evaluate_rejects_volume_over_limit() {
|
|||||||
insert_into(evm_transaction_log::table)
|
insert_into(evm_transaction_log::table)
|
||||||
.values(NewEvmTransactionLog {
|
.values(NewEvmTransactionLog {
|
||||||
grant_id,
|
grant_id,
|
||||||
wallet_access_id: WALLET_ACCESS_ID,
|
wallet_access_id: basic.wallet_access_id,
|
||||||
chain_id: CHAIN_ID.into(),
|
chain_id: CHAIN_ID.into(),
|
||||||
eth_value: utils::u256_to_bytes(U256::from(1_000u64)).to_vec(),
|
eth_value: utils::u256_to_bytes(U256::from(1_000u64)).to_vec(),
|
||||||
signed_at: SqliteTimestamp(Utc::now()),
|
signed_at: SqliteTimestamp(Utc::now()),
|
||||||
@@ -246,7 +319,7 @@ async fn evaluate_passes_at_exactly_volume_limit() {
|
|||||||
insert_into(evm_transaction_log::table)
|
insert_into(evm_transaction_log::table)
|
||||||
.values(NewEvmTransactionLog {
|
.values(NewEvmTransactionLog {
|
||||||
grant_id,
|
grant_id,
|
||||||
wallet_access_id: WALLET_ACCESS_ID,
|
wallet_access_id: basic.wallet_access_id,
|
||||||
chain_id: CHAIN_ID.into(),
|
chain_id: CHAIN_ID.into(),
|
||||||
eth_value: utils::u256_to_bytes(U256::from(900u64)).to_vec(),
|
eth_value: utils::u256_to_bytes(U256::from(900u64)).to_vec(),
|
||||||
signed_at: SqliteTimestamp(Utc::now()),
|
signed_at: SqliteTimestamp(Utc::now()),
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use super::{Settings, TokenTransfer};
|
use super::{Settings, TokenTransfer};
|
||||||
use crate::{
|
use crate::{
|
||||||
db::{
|
db::{
|
||||||
self, DatabaseConnection,
|
self, DatabaseConnection, models,
|
||||||
models::{EvmBasicGrant, EvmWalletAccess, EvmWalletId, NewEvmBasicGrant, SqliteTimestamp},
|
models::{EvmBasicGrant, EvmWalletAccess, EvmWalletId, NewEvmBasicGrant, SqliteTimestamp},
|
||||||
|
schema,
|
||||||
schema::evm_basic_grant,
|
schema::evm_basic_grant,
|
||||||
},
|
},
|
||||||
evm::{
|
evm::{
|
||||||
@@ -20,7 +21,7 @@ use alloy::{
|
|||||||
sol_types::SolCall,
|
sol_types::SolCall,
|
||||||
};
|
};
|
||||||
use chrono::{Duration, Utc};
|
use chrono::{Duration, Utc};
|
||||||
use diesel::{SelectableHelper, insert_into};
|
use diesel::{ExpressionMethods as _, SelectableHelper, insert_into};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
|
|
||||||
// DAI on Ethereum mainnet — present in the static token registry
|
// DAI on Ethereum mainnet — present in the static token registry
|
||||||
@@ -58,10 +59,82 @@ fn ctx(to: Address, calldata: Bytes) -> EvalContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates the parent chain a fresh `evm_wallet_access` row needs under foreign-key
|
||||||
|
/// enforcement (a root key, an aead-encrypted secret, a wallet, and a client) and returns
|
||||||
|
/// the new access row's id.
|
||||||
|
async fn seed_wallet_access(conn: &mut DatabaseConnection) -> i32 {
|
||||||
|
let root_key_id: models::RootKeyHistoryId = insert_into(schema::root_key_history::table)
|
||||||
|
.values(&models::NewRootKeyHistory {
|
||||||
|
ciphertext: vec![0u8; 32],
|
||||||
|
tag: vec![0u8; 16],
|
||||||
|
root_key_encryption_nonce: vec![0u8; 24],
|
||||||
|
data_encryption_nonce: vec![0u8; 24],
|
||||||
|
schema_version: 1,
|
||||||
|
salt: vec![0u8; 16],
|
||||||
|
})
|
||||||
|
.returning(schema::root_key_history::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let aead_id: i32 = insert_into(schema::aead_encrypted::table)
|
||||||
|
.values(&models::NewAeadEncrypted {
|
||||||
|
ciphertext: vec![0u8; 32],
|
||||||
|
tag: vec![0u8; 16],
|
||||||
|
current_nonce: vec![0u8; 24],
|
||||||
|
schema_version: 1,
|
||||||
|
associated_root_key_id: root_key_id,
|
||||||
|
created_at: Utc::now().into(),
|
||||||
|
})
|
||||||
|
.returning(schema::aead_encrypted::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let wallet_id: EvmWalletId = insert_into(schema::evm_wallet::table)
|
||||||
|
.values((
|
||||||
|
schema::evm_wallet::address.eq(rand::random::<[u8; 20]>().to_vec()),
|
||||||
|
schema::evm_wallet::aead_encrypted_id.eq(aead_id),
|
||||||
|
))
|
||||||
|
.returning(schema::evm_wallet::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let metadata_id: i32 = insert_into(schema::client_metadata::table)
|
||||||
|
.values(schema::client_metadata::name.eq("test"))
|
||||||
|
.returning(schema::client_metadata::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let client_id: i32 = insert_into(schema::program_client::table)
|
||||||
|
.values((
|
||||||
|
schema::program_client::public_key.eq(rand::random::<[u8; 32]>().to_vec()),
|
||||||
|
schema::program_client::metadata_id.eq(metadata_id),
|
||||||
|
))
|
||||||
|
.returning(schema::program_client::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
insert_into(schema::evm_wallet_access::table)
|
||||||
|
.values((
|
||||||
|
schema::evm_wallet_access::wallet_id.eq(wallet_id),
|
||||||
|
schema::evm_wallet_access::client_id.eq(client_id),
|
||||||
|
))
|
||||||
|
.returning(schema::evm_wallet_access::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
async fn insert_basic(conn: &mut DatabaseConnection, revoked: bool) -> EvmBasicGrant {
|
async fn insert_basic(conn: &mut DatabaseConnection, revoked: bool) -> EvmBasicGrant {
|
||||||
|
let wallet_access_id = seed_wallet_access(conn).await;
|
||||||
|
|
||||||
insert_into(evm_basic_grant::table)
|
insert_into(evm_basic_grant::table)
|
||||||
.values(NewEvmBasicGrant {
|
.values(NewEvmBasicGrant {
|
||||||
wallet_access_id: WALLET_ACCESS_ID,
|
wallet_access_id,
|
||||||
chain_id: CHAIN_ID.into(),
|
chain_id: CHAIN_ID.into(),
|
||||||
valid_from: None,
|
valid_from: None,
|
||||||
valid_until: None,
|
valid_until: None,
|
||||||
@@ -77,6 +150,27 @@ async fn insert_basic(conn: &mut DatabaseConnection, revoked: bool) -> EvmBasicG
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `evm_token_transfer_log.log_id` references the shared `evm_transaction_log` table, so
|
||||||
|
/// tests recording a token transfer need a real row there to point at.
|
||||||
|
async fn insert_transaction_log(
|
||||||
|
conn: &mut DatabaseConnection,
|
||||||
|
basic: &EvmBasicGrant,
|
||||||
|
eth_value: U256,
|
||||||
|
) -> i32 {
|
||||||
|
insert_into(schema::evm_transaction_log::table)
|
||||||
|
.values(models::NewEvmTransactionLog {
|
||||||
|
grant_id: basic.id,
|
||||||
|
wallet_access_id: basic.wallet_access_id,
|
||||||
|
chain_id: CHAIN_ID.into(),
|
||||||
|
eth_value: utils::u256_to_bytes(eth_value).to_vec(),
|
||||||
|
signed_at: SqliteTimestamp(Utc::now()),
|
||||||
|
})
|
||||||
|
.returning(schema::evm_transaction_log::id)
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn make_settings(target: Option<Address>, max_volume: Option<u64>) -> Settings {
|
fn make_settings(target: Option<Address>, max_volume: Option<u64>) -> Settings {
|
||||||
Settings {
|
Settings {
|
||||||
token_contract: DAI,
|
token_contract: DAI,
|
||||||
@@ -241,10 +335,11 @@ async fn evaluate_passes_volume_at_exact_limit() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Record a past transfer of 900, with current transfer 100 => exactly 1000 limit
|
// Record a past transfer of 900, with current transfer 100 => exactly 1000 limit
|
||||||
insert_into(db::schema::evm_token_transfer_log::table)
|
let log_id = insert_transaction_log(&mut conn, &basic, U256::from(900u64)).await;
|
||||||
.values(db::models::NewEvmTokenTransferLog {
|
insert_into(schema::evm_token_transfer_log::table)
|
||||||
|
.values(models::NewEvmTokenTransferLog {
|
||||||
grant_id,
|
grant_id,
|
||||||
log_id: 0,
|
log_id,
|
||||||
chain_id: CHAIN_ID.into(),
|
chain_id: CHAIN_ID.into(),
|
||||||
token_contract: DAI.to_vec(),
|
token_contract: DAI.to_vec(),
|
||||||
recipient_address: RECIPIENT.to_vec(),
|
recipient_address: RECIPIENT.to_vec(),
|
||||||
@@ -285,10 +380,11 @@ async fn evaluate_rejects_volume_over_limit() {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
insert_into(db::schema::evm_token_transfer_log::table)
|
let log_id = insert_transaction_log(&mut conn, &basic, U256::from(1_000u64)).await;
|
||||||
.values(db::models::NewEvmTokenTransferLog {
|
insert_into(schema::evm_token_transfer_log::table)
|
||||||
|
.values(models::NewEvmTokenTransferLog {
|
||||||
grant_id,
|
grant_id,
|
||||||
log_id: 0,
|
log_id,
|
||||||
chain_id: CHAIN_ID.into(),
|
chain_id: CHAIN_ID.into(),
|
||||||
token_contract: DAI.to_vec(),
|
token_contract: DAI.to_vec(),
|
||||||
recipient_address: RECIPIENT.to_vec(),
|
recipient_address: RECIPIENT.to_vec(),
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ use arbiter_server::{
|
|||||||
};
|
};
|
||||||
use arbiter_server::actors::vault::Bootstrap;
|
use arbiter_server::actors::vault::Bootstrap;
|
||||||
use arbiter_server::db::schema::{
|
use arbiter_server::db::schema::{
|
||||||
aead_encrypted, evm_basic_grant, evm_wallet, evm_wallet_access, operator_identity,
|
aead_encrypted, arbiter_settings, evm_basic_grant, evm_wallet, evm_wallet_access,
|
||||||
proposal_one_off_transaction_result, recovery_operator_identity,
|
operator_identity, proposal_one_off_transaction_result, recovery_operator_identity,
|
||||||
};
|
};
|
||||||
use diesel::{ExpressionMethods, QueryDsl, insert_into};
|
use diesel::{ExpressionMethods, QueryDsl, insert_into};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
@@ -82,14 +82,22 @@ async fn insert_active_wakeup(db: &db::DatabasePool, operator_id: OperatorIdenti
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Requires the vault to already be bootstrapped: it reads the root key row `Bootstrap`
|
||||||
|
/// creates so the aead-encrypted wallet secret has a real parent to reference.
|
||||||
async fn insert_evm_wallet(db: &db::DatabasePool) -> i32 {
|
async fn insert_evm_wallet(db: &db::DatabasePool) -> i32 {
|
||||||
let mut conn = db.get().await.unwrap();
|
let mut conn = db.get().await.unwrap();
|
||||||
|
let root_key_id: i32 = arbiter_settings::table
|
||||||
|
.select(arbiter_settings::root_key_id)
|
||||||
|
.first::<Option<i32>>(&mut conn)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.expect("vault must be bootstrapped before creating an aead-encrypted row");
|
||||||
let aead_id: i32 = insert_into(aead_encrypted::table)
|
let aead_id: i32 = insert_into(aead_encrypted::table)
|
||||||
.values((
|
.values((
|
||||||
aead_encrypted::current_nonce.eq(vec![0u8; 4]),
|
aead_encrypted::current_nonce.eq(vec![0u8; 4]),
|
||||||
aead_encrypted::ciphertext.eq(vec![0u8; 32]),
|
aead_encrypted::ciphertext.eq(vec![0u8; 32]),
|
||||||
aead_encrypted::tag.eq(vec![0u8; 16]),
|
aead_encrypted::tag.eq(vec![0u8; 16]),
|
||||||
aead_encrypted::associated_root_key_id.eq(0i32),
|
aead_encrypted::associated_root_key_id.eq(root_key_id),
|
||||||
))
|
))
|
||||||
.returning(aead_encrypted::id)
|
.returning(aead_encrypted::id)
|
||||||
.get_result::<i32>(&mut conn)
|
.get_result::<i32>(&mut conn)
|
||||||
@@ -143,11 +151,16 @@ async fn create_proposal_returns_id() {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let key = authn::SigningKey::generate();
|
||||||
|
let operator_id = register_operator(&db, &key.public_key()).await;
|
||||||
|
let client_key = authn::SigningKey::generate();
|
||||||
|
let client_id = insert_unapproved_client(&db, &client_key.public_key()).await;
|
||||||
|
|
||||||
let proposal_id = actors
|
let proposal_id = actors
|
||||||
.proposal_manager
|
.proposal_manager
|
||||||
.ask(CreateProposal {
|
.ask(CreateProposal {
|
||||||
kind: ProposalKind::ApproveSdkClient(approve_sdk_client::Settings { client_id: 42 }),
|
kind: ProposalKind::ApproveSdkClient(approve_sdk_client::Settings { client_id }),
|
||||||
initiator_id: OperatorIdentityId::from_raw(1),
|
initiator_id: operator_id,
|
||||||
ttl_secs: None,
|
ttl_secs: None,
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@@ -170,12 +183,14 @@ async fn create_proposal_caps_the_ttl() {
|
|||||||
|
|
||||||
let key = authn::SigningKey::generate();
|
let key = authn::SigningKey::generate();
|
||||||
let op = register_operator(&db, &key.public_key()).await;
|
let op = register_operator(&db, &key.public_key()).await;
|
||||||
|
let client_key = authn::SigningKey::generate();
|
||||||
|
let client_id = insert_unapproved_client(&db, &client_key.public_key()).await;
|
||||||
|
|
||||||
let create = async |ttl: u32| {
|
let create = async |ttl: u32| {
|
||||||
actors
|
actors
|
||||||
.proposal_manager
|
.proposal_manager
|
||||||
.ask(CreateProposal {
|
.ask(CreateProposal {
|
||||||
kind: ProposalKind::ApproveSdkClient(approve_sdk_client::Settings { client_id: 1 }),
|
kind: ProposalKind::ApproveSdkClient(approve_sdk_client::Settings { client_id }),
|
||||||
initiator_id: op,
|
initiator_id: op,
|
||||||
ttl_secs: Some(ttl),
|
ttl_secs: Some(ttl),
|
||||||
})
|
})
|
||||||
@@ -429,7 +444,9 @@ async fn query_pending_reports_a_tally_per_proposal() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut ids = Vec::new();
|
let mut ids = Vec::new();
|
||||||
for client_id in 1..=3 {
|
for _ in 1..=3 {
|
||||||
|
let client_key = authn::SigningKey::generate();
|
||||||
|
let client_id = insert_unapproved_client(&db, &client_key.public_key()).await;
|
||||||
let id = actors
|
let id = actors
|
||||||
.proposal_manager
|
.proposal_manager
|
||||||
.ask(CreateProposal {
|
.ask(CreateProposal {
|
||||||
|
|||||||
Reference in New Issue
Block a user