Skip to content

Commit

Permalink
Prune owned coin idx when inputs are spent (#1055)
Browse files Browse the repository at this point in the history
fixes: #1053

Remove owned coin index entries when coins are spent to improve the
performance of random-improve based coin selection.

Already released v0.17.4 hotfix from this branch, ready to merge into
mainline now.

---------

Co-authored-by: Green Baneling <XgreenX9999@gmail.com>
  • Loading branch information
Voxelot and xgreenx committed Mar 17, 2023
1 parent c19bd95 commit 13aa644
Show file tree
Hide file tree
Showing 46 changed files with 729 additions and 941 deletions.
897 changes: 537 additions & 360 deletions Cargo.lock

Large diffs are not rendered by default.

46 changes: 23 additions & 23 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,32 +45,32 @@ homepage = "https://fuel.network/"
keywords = ["blockchain", "cryptocurrencies", "fuel-vm", "vm"]
license = "BUSL-1.1"
repository = "https://github.com/FuelLabs/fuel-core"
version = "0.17.3"
version = "0.17.4"

[workspace.dependencies]
# Workspace members
fuel-core = { version = "0.17.3", path = "./crates/fuel-core", default-features = false }
fuel-core-client-bin = { version = "0.17.3", path = "./bin/client" }
fuel-core-bin = { version = "0.17.3", path = "./bin/fuel-core" }
fuel-core-keygen = { version = "0.17.3", path = "./bin/keygen" }
fuel-core-chain-config = { version = "0.17.3", path = "./crates/chain-config" }
fuel-core-client = { version = "0.17.3", path = "./crates/client" }
fuel-core-database = { version = "0.17.3", path = "./crates/database" }
fuel-core-metrics = { version = "0.17.3", path = "./crates/metrics" }
fuel-core-services = { version = "0.17.3", path = "./crates/services" }
fuel-core-consensus-module = { version = "0.17.3", path = "./crates/services/consensus_module" }
fuel-core-bft = { version = "0.17.3", path = "./crates/services/consensus_module/bft" }
fuel-core-poa = { version = "0.17.3", path = "./crates/services/consensus_module/poa" }
fuel-core-executor = { version = "0.17.3", path = "./crates/services/executor" }
fuel-core-importer = { version = "0.17.3", path = "./crates/services/importer" }
fuel-core-p2p = { version = "0.17.3", path = "./crates/services/p2p" }
fuel-core-producer = { version = "0.17.3", path = "./crates/services/producer" }
fuel-core-relayer = { version = "0.17.3", path = "./crates/services/relayer" }
fuel-core-sync = { version = "0.17.3", path = "./crates/services/sync" }
fuel-core-txpool = { version = "0.17.3", path = "./crates/services/txpool" }
fuel-core-storage = { version = "0.17.3", path = "./crates/storage" }
fuel-core-trace = { version = "0.17.3", path = "./crates/trace" }
fuel-core-types = { version = "0.17.3", path = "./crates/types", default-features = false }
fuel-core = { version = "0.17.4", path = "./crates/fuel-core", default-features = false }
fuel-core-client-bin = { version = "0.17.4", path = "./bin/client" }
fuel-core-bin = { version = "0.17.4", path = "./bin/fuel-core" }
fuel-core-keygen = { version = "0.17.4", path = "./bin/keygen" }
fuel-core-chain-config = { version = "0.17.4", path = "./crates/chain-config" }
fuel-core-client = { version = "0.17.4", path = "./crates/client" }
fuel-core-database = { version = "0.17.4", path = "./crates/database" }
fuel-core-metrics = { version = "0.17.4", path = "./crates/metrics" }
fuel-core-services = { version = "0.17.4", path = "./crates/services" }
fuel-core-consensus-module = { version = "0.17.4", path = "./crates/services/consensus_module" }
fuel-core-bft = { version = "0.17.4", path = "./crates/services/consensus_module/bft" }
fuel-core-poa = { version = "0.17.4", path = "./crates/services/consensus_module/poa" }
fuel-core-executor = { version = "0.17.4", path = "./crates/services/executor" }
fuel-core-importer = { version = "0.17.4", path = "./crates/services/importer" }
fuel-core-p2p = { version = "0.17.4", path = "./crates/services/p2p" }
fuel-core-producer = { version = "0.17.4", path = "./crates/services/producer" }
fuel-core-relayer = { version = "0.17.4", path = "./crates/services/relayer" }
fuel-core-sync = { version = "0.17.4", path = "./crates/services/sync" }
fuel-core-txpool = { version = "0.17.4", path = "./crates/services/txpool" }
fuel-core-storage = { version = "0.17.4", path = "./crates/storage" }
fuel-core-trace = { version = "0.17.4", path = "./crates/trace" }
fuel-core-types = { version = "0.17.4", path = "./crates/types", default-features = false }
fuel-core-tests = { version = "0.0.0", path = "./tests" }
fuel-core-xtask = { version = "0.0.0", path = "./xtask" }

Expand Down
1 change: 0 additions & 1 deletion crates/chain-config/src/config/coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ impl GenesisCommitment for CompressedCoin {
.chain(self.amount.to_be_bytes())
.chain(self.asset_id)
.chain((*self.maturity).to_be_bytes())
.chain([self.status as u8])
.chain(self.tx_pointer.block_height().to_be_bytes())
.chain(self.tx_pointer.tx_index().to_be_bytes())
.finalize();
Expand Down
8 changes: 4 additions & 4 deletions crates/chain-config/src/config/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
use fuel_core_storage::MerkleRoot;
use fuel_core_types::{
blockchain::primitives::DaBlockHeight,
entities::message::CompressedMessage,
entities::message::Message,
fuel_asm::Word,
fuel_types::Address,
};
Expand Down Expand Up @@ -40,9 +40,9 @@ pub struct MessageConfig {
pub da_height: DaBlockHeight,
}

impl From<MessageConfig> for CompressedMessage {
impl From<MessageConfig> for Message {
fn from(msg: MessageConfig) -> Self {
CompressedMessage {
Message {
sender: msg.sender,
recipient: msg.recipient,
nonce: msg.nonce,
Expand All @@ -53,7 +53,7 @@ impl From<MessageConfig> for CompressedMessage {
}
}

impl GenesisCommitment for CompressedMessage {
impl GenesisCommitment for Message {
fn root(&self) -> anyhow::Result<MerkleRoot> {
Ok(self.id().into())
}
Expand Down
3 changes: 2 additions & 1 deletion crates/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ hex = "0.4"
# Included to enable webpki in the eventsource client
hyper-rustls = { version = "0.22", features = ["webpki-tokio"], optional = true }
itertools = { workspace = true }
reqwest = { version = "0.11", default-features = false, features = ["rustls-tls"] }
# enable cookie store to support L7 sticky sessions
reqwest = { version = "0.11", default-features = false, features = ["rustls-tls", "cookie_store"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { version = "1.0", features = ["raw_value"] }
tai64 = { version = "4.0", features = ["serde"] }
Expand Down
15 changes: 0 additions & 15 deletions crates/client/assets/schema.sdl
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,6 @@ type Coin {
assetId: AssetId!
maturity: U64!
"""
The spendable status of the coin
"""
status: CoinStatus!
"""
TxPointer - the height of the block this coin was created in
"""
blockCreated: U64!
Expand Down Expand Up @@ -170,11 +166,6 @@ type CoinOutput {
assetId: AssetId!
}

enum CoinStatus {
UNSPENT
SPENT
}

union Consensus = Genesis | PoAConsensus

type ConsensusParameters {
Expand Down Expand Up @@ -382,7 +373,6 @@ type Message {
nonce: U64!
data: HexString!
daHeight: U64!
status: MessageStatus!
}

type MessageConnection {
Expand Down Expand Up @@ -433,11 +423,6 @@ type MessageProof {
header: Header!
}

enum MessageStatus {
UNSPENT
SPENT
}

type Mutation {
startSession: ID!
endSession(id: ID!): Boolean!
Expand Down
8 changes: 0 additions & 8 deletions crates/client/src/client/schema/coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,6 @@ pub struct Coin {
pub utxo_id: UtxoId,
pub maturity: U64,
pub owner: Address,
pub status: CoinStatus,
}

#[derive(cynic::Enum, Clone, Copy, Debug, Eq, PartialEq)]
#[cynic(schema_path = "./assets/schema.sdl")]
pub enum CoinStatus {
Unspent,
Spent,
}

#[derive(cynic::QueryFragment, Debug)]
Expand Down
8 changes: 0 additions & 8 deletions crates/client/src/client/schema/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@ pub struct Message {
pub nonce: U64,
pub data: HexString,
pub da_height: U64,
pub status: MessageStatus,
}

#[derive(cynic::Enum, Clone, Copy, Debug, Eq, PartialEq)]
#[cynic(schema_path = "./assets/schema.sdl")]
pub enum MessageStatus {
Unspent,
Spent,
}

#[derive(cynic::QueryFragment, Debug)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ query($utxoId: UtxoId!) {
utxoId
maturity
owner
status
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ query($filter: CoinFilterInput!, $after: String, $before: String, $first: Int, $
utxoId
maturity
owner
status
}
}
pageInfo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ query($owner: Address, $after: String, $before: String, $first: Int, $last: Int)
nonce
data
daHeight
status
}
}
pageInfo {
Expand Down
3 changes: 2 additions & 1 deletion crates/fuel-core/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ use tempfile::TempDir;
// TODO: Move to separate `database/storage` folder, because it is only implementation of storages traits.
mod block;
mod code_root;
mod coin;
mod contracts;
mod message;
mod receipts;
Expand All @@ -61,6 +60,8 @@ mod relayer;
mod sealed_block;
mod state;

pub(crate) mod coin;

pub mod balances;
pub mod metadata;
pub mod storage;
Expand Down
50 changes: 26 additions & 24 deletions crates/fuel-core/src/database/coin.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::database::{
storage::DatabaseColumn,
Column,
Database,
Error as DatabaseError,
Expand All @@ -9,15 +10,14 @@ use fuel_core_storage::{
iter::IterDirection,
tables::Coins,
Error as StorageError,
Mappable,
StorageAsMut,
StorageInspect,
StorageMutate,
};
use fuel_core_txpool::types::TxId;
use fuel_core_types::{
entities::coin::{
CoinStatus,
CompressedCoin,
},
entities::coin::CompressedCoin,
fuel_tx::{
Address,
Bytes32,
Expand All @@ -27,10 +27,7 @@ use fuel_core_types::{
use std::borrow::Cow;

// TODO: Reuse `fuel_vm::storage::double_key` macro.
fn owner_coin_id_key(
owner: &Address,
coin_id: &UtxoId,
) -> [u8; Address::LEN + TxId::LEN + 1] {
pub fn owner_coin_id_key(owner: &Address, coin_id: &UtxoId) -> OwnedCoinKey {
let mut default = [0u8; Address::LEN + TxId::LEN + 1];
default[0..Address::LEN].copy_from_slice(owner.as_ref());
default[Address::LEN..].copy_from_slice(utxo_id_to_bytes(coin_id).as_ref());
Expand All @@ -44,6 +41,24 @@ fn utxo_id_to_bytes(utxo_id: &UtxoId) -> [u8; TxId::LEN + 1] {
default
}

/// The storage table of owned coin ids. Maps addresses to owned coins.
pub struct OwnedCoins;
/// The storage key for owned coins: `Address ++ UtxoId`
pub type OwnedCoinKey = [u8; Address::LEN + TxId::LEN + 1];

impl Mappable for OwnedCoins {
type Key = Self::OwnedKey;
type OwnedKey = OwnedCoinKey;
type Value = Self::OwnedValue;
type OwnedValue = bool;
}

impl DatabaseColumn for OwnedCoins {
fn column() -> Column {
Column::OwnedCoins
}
}

impl StorageInspect<Coins> for Database {
type Error = StorageError;

Expand All @@ -67,8 +82,8 @@ impl StorageMutate<Coins> for Database {
// insert primary record
let insert = Database::insert(self, utxo_id_to_bytes(key), Column::Coins, value)?;
// insert secondary index by owner
let _: Option<bool> =
Database::insert(self, coin_by_owner, Column::OwnedCoins, &true)?;
self.storage_as_mut::<OwnedCoins>()
.insert(&coin_by_owner, &true)?;
Ok(insert)
}

Expand All @@ -79,8 +94,7 @@ impl StorageMutate<Coins> for Database {
// cleanup secondary index
if let Some(coin) = &coin {
let key = owner_coin_id_key(&coin.owner, key);
let _: Option<bool> =
Database::remove(self, key.as_slice(), Column::OwnedCoins)?;
self.storage_as_mut::<OwnedCoins>().remove(&key)?;
}

Ok(coin)
Expand Down Expand Up @@ -114,18 +128,6 @@ impl Database {
pub fn get_coin_config(&self) -> DatabaseResult<Option<Vec<CoinConfig>>> {
let configs = self
.iter_all::<Vec<u8>, CompressedCoin>(Column::Coins, None)
.filter_map(|coin| {
// Return only unspent coins
if let Ok(coin) = coin {
if coin.1.status == CoinStatus::Unspent {
Some(Ok(coin))
} else {
None
}
} else {
Some(coin)
}
})
.map(|raw_coin| -> DatabaseResult<CoinConfig> {
let coin = raw_coin?;

Expand Down
30 changes: 10 additions & 20 deletions crates/fuel-core/src/database/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use fuel_core_storage::{
};
use fuel_core_types::{
entities::message::{
CompressedMessage,
Message,
MessageStatus,
},
fuel_types::{
Expand All @@ -36,10 +36,7 @@ use super::storage::DatabaseColumn;
impl StorageInspect<Messages> for Database {
type Error = StorageError;

fn get(
&self,
key: &MessageId,
) -> Result<Option<Cow<CompressedMessage>>, Self::Error> {
fn get(&self, key: &MessageId) -> Result<Option<Cow<Message>>, Self::Error> {
Database::get(self, key.as_ref(), Column::Messages).map_err(Into::into)
}

Expand All @@ -52,8 +49,8 @@ impl StorageMutate<Messages> for Database {
fn insert(
&mut self,
key: &MessageId,
value: &CompressedMessage,
) -> Result<Option<CompressedMessage>, Self::Error> {
value: &Message,
) -> Result<Option<Message>, Self::Error> {
// insert primary record
let result = Database::insert(self, key.as_ref(), Column::Messages, value)?;

Expand All @@ -68,11 +65,8 @@ impl StorageMutate<Messages> for Database {
Ok(result)
}

fn remove(
&mut self,
key: &MessageId,
) -> Result<Option<CompressedMessage>, Self::Error> {
let result: Option<CompressedMessage> =
fn remove(&mut self, key: &MessageId) -> Result<Option<Message>, Self::Error> {
let result: Option<Message> =
Database::remove(self, key.as_ref(), Column::Messages)?;

if let Some(message) = &result {
Expand Down Expand Up @@ -118,14 +112,10 @@ impl Database {
&self,
start: Option<MessageId>,
direction: Option<IterDirection>,
) -> impl Iterator<Item = DatabaseResult<CompressedMessage>> + '_ {
) -> impl Iterator<Item = DatabaseResult<Message>> + '_ {
let start = start.map(|v| v.deref().to_vec());
self.iter_all_by_start::<Vec<u8>, CompressedMessage, _>(
Column::Messages,
start,
direction,
)
.map(|res| res.map(|(_, message)| message))
self.iter_all_by_start::<Vec<u8>, Message, _>(Column::Messages, start, direction)
.map(|res| res.map(|(_, message)| message))
}

pub fn get_message_config(&self) -> StorageResult<Option<Vec<MessageConfig>>> {
Expand Down Expand Up @@ -194,7 +184,7 @@ mod tests {
#[test]
fn owned_message_ids() {
let mut db = Database::default();
let message = CompressedMessage::default();
let message = Message::default();

// insert a message with the first id
let first_id = MessageId::new([1; 32]);
Expand Down
Loading

0 comments on commit 13aa644

Please sign in to comment.