Exemple #1
0
        /// <inheritdoc cref="BaseStore.AppendIndex(Guid, BlockHash)"/>
        public override long AppendIndex(Guid chainId, BlockHash hash)
        {
            long index = CountIndex(chainId);

            try
            {
                byte[] indexBytes = RocksDBStoreBitConverter.GetBytes(index);

                byte[]             key = IndexKeyPrefix.Concat(indexBytes).ToArray();
                ColumnFamilyHandle cf  = GetColumnFamily(_chainDb, chainId);

                using var writeBatch = new WriteBatch();

                writeBatch.Put(key, hash.ToByteArray(), cf);
                writeBatch.Put(IndexCountKey, RocksDBStoreBitConverter.GetBytes(index + 1), cf);

                _chainDb.Write(writeBatch);
            }
            catch (Exception e)
            {
                LogUnexpectedException(nameof(AppendIndex), e);
            }

            return(index);
        }
Exemple #2
0
        /// <inheritdoc/>
        public override bool DeleteBlock(HashDigest <SHA256> blockHash)
        {
            byte[] key = BlockKey(blockHash);

            if (!(_blockIndexDb.Get(key) is byte[] blockDbNameByte))
            {
                return(false);
            }

            _rwBlockLock.EnterWriteLock();
            try
            {
                string blockDbName = RocksDBStoreBitConverter.GetString(blockDbNameByte);
                if (!_blockDbCache.TryGetValue(blockDbName, out RocksDb blockDb))
                {
                    blockDb = RocksDBUtils.OpenRocksDb(_options, BlockDbPath(blockDbName));
                    _blockDbCache.AddOrUpdate(blockDbName, blockDb);
                }

                _blockCache.Remove(blockHash);
                _blockIndexDb.Remove(key);
                blockDb.Remove(key);
                return(true);
            }
            finally
            {
                _rwBlockLock.ExitWriteLock();
            }
        }
Exemple #3
0
        /// <inheritdoc/>
        public override IEnumerable <Tuple <HashDigest <SHA256>, long> > IterateStateReferences(
            Guid chainId,
            string key,
            long?highestIndex,
            long?lowestIndex,
            int?limit)
        {
            highestIndex ??= long.MaxValue;
            lowestIndex ??= 0;
            limit ??= int.MaxValue;

            if (highestIndex < lowestIndex)
            {
                var message =
                    $"highestIndex({highestIndex}) must be greater than or equal to " +
                    $"lowestIndex({lowestIndex})";
                throw new ArgumentException(
                          message,
                          nameof(highestIndex));
            }

            byte[] keyBytes = RocksDBStoreBitConverter.GetBytes(key);
            byte[] prefix   = StateRefKeyPrefix.Concat(keyBytes).ToArray();

            return(IterateStateReferences(
                       chainId, prefix, highestIndex.Value, lowestIndex.Value, limit.Value));
        }
Exemple #4
0
        /// <inheritdoc/>
        public override BlockDigest?GetBlockDigest(HashDigest <SHA256> blockHash)
        {
            if (_blockCache.TryGetValue(blockHash, out BlockDigest cachedDigest))
            {
                return(cachedDigest);
            }

            byte[] key = BlockKey(blockHash);
            if (!(_blockIndexDb.Get(key) is byte[] blockDbNameBytes))
            {
                return(null);
            }

            _rwBlockLock.EnterReadLock();
            try
            {
                string blockDbName = RocksDBStoreBitConverter.GetString(blockDbNameBytes);
                if (!_blockDbCache.TryGetValue(blockDbName, out RocksDb blockDb))
                {
                    blockDb = RocksDBUtils.OpenRocksDb(_options, BlockDbPath(blockDbName));
                    _blockDbCache.AddOrUpdate(blockDbName, blockDb);
                }

                byte[] blockBytes = blockDb.Get(key);

                BlockDigest blockDigest = BlockDigest.Deserialize(blockBytes);

                _blockCache.AddOrUpdate(blockHash, blockDigest);
                return(blockDigest);
            }
            finally
            {
                _rwBlockLock.ExitReadLock();
            }
        }
Exemple #5
0
        /// <inheritdoc/>
        public override bool DeleteTransaction(TxId txid)
        {
            byte[] key = TxKey(txid);

            if (!(_txIndexDb.Get(key) is byte[] txDbNameBytes))
            {
                return(false);
            }

            _rwTxLock.EnterWriteLock();
            try
            {
                string txDbName = RocksDBStoreBitConverter.GetString(txDbNameBytes);
                if (!_txDbCache.TryGetValue(txDbName, out RocksDb txDb))
                {
                    txDb = RocksDBUtils.OpenRocksDb(_options, TxDbPath(txDbName));
                    _txDbCache.AddOrUpdate(txDbName, txDb);
                }

                _txCache.Remove(txid);
                _txIndexDb.Remove(key);
                txDb.Remove(key);

                return(true);
            }
            finally
            {
                _rwTxLock.ExitWriteLock();
            }
        }
Exemple #6
0
        /// <inheritdoc/>
        public override void PutTransaction <T>(Transaction <T> tx)
        {
            if (_txCache.ContainsKey(tx.Id))
            {
                return;
            }

            byte[] key = TxKey(tx.Id);
            if (!(_txIndexDb.Get(key) is null))
            {
                return;
            }

            long   timestamp = tx.Timestamp.ToUnixTimeSeconds();
            string txDbName  = $"epoch{(int)timestamp / _txEpochUnitSeconds}";

            _rwTxLock.EnterWriteLock();
            try
            {
                if (!_txDbCache.TryGetValue(txDbName, out RocksDb txDb))
                {
                    txDb = RocksDBUtils.OpenRocksDb(_options, TxDbPath(txDbName));
                    _txDbCache.AddOrUpdate(txDbName, txDb);
                }

                txDb.Put(key, tx.Serialize(true));
                _txIndexDb.Put(key, RocksDBStoreBitConverter.GetBytes(txDbName));
                _txCache.AddOrUpdate(tx.Id, tx);
            }
            finally
            {
                _rwTxLock.ExitWriteLock();
            }
        }
Exemple #7
0
        /// <inheritdoc/>
        public override long CountIndex(Guid chainId)
        {
            ColumnFamilyHandle cf = GetColumnFamily(_chainDb, chainId);

            byte[] bytes = _chainDb.Get(IndexCountKey, cf);
            return(bytes is null
                ? 0
                : RocksDBStoreBitConverter.ToInt64(bytes));
        }
Exemple #8
0
        /// <inheritdoc/>
        public override void IncreaseTxNonce(Guid chainId, Address signer, long delta = 1)
        {
            ColumnFamilyHandle cf = GetColumnFamily(_chainDb, chainId);
            long nextNonce        = GetTxNonce(chainId, signer) + delta;

            byte[] key   = TxNonceKey(signer);
            byte[] bytes = RocksDBStoreBitConverter.GetBytes(nextNonce);

            _chainDb.Put(key, bytes, cf);
        }
Exemple #9
0
        private (Guid, long)? GetPreviousChainInfo(ColumnFamilyHandle cf)
        {
            if (_chainDb.Get(PreviousChainIdKey, cf) is { } prevChainId&&
                _chainDb.Get(PreviousChainIndexKey, cf) is { } prevChainIndex)
            {
                return(new Guid(prevChainId), RocksDBStoreBitConverter.ToInt64(prevChainIndex));
            }

            return(null);
        }
Exemple #10
0
        private byte[] StateRefKey(string stateKey, long blockIndex)
        {
            byte[] stateKeyBytes   = RocksDBStoreBitConverter.GetBytes(stateKey);
            byte[] blockIndexBytes = RocksDBStoreBitConverter.GetBytes(blockIndex);

            return(StateRefKeyPrefix
                   .Concat(stateKeyBytes)
                   .Concat(blockIndexBytes)
                   .ToArray());
        }
Exemple #11
0
        /// <inheritdoc/>
        public override long GetTxNonce(Guid chainId, Address address)
        {
            ColumnFamilyHandle cf = GetColumnFamily(_chainDb, chainId);

            byte[] key   = TxNonceKey(address);
            byte[] bytes = _chainDb.Get(key, cf);

            return(bytes is null
                ? 0
                : RocksDBStoreBitConverter.ToInt64(bytes));
        }
Exemple #12
0
        /// <inheritdoc/>
        public override void ForkBlockIndexes(
            Guid sourceChainId,
            Guid destinationChainId,
            HashDigest <SHA256> branchPoint)
        {
            HashDigest <SHA256>?genesisHash = IterateIndexes(sourceChainId, 0, 1)
                                              .Cast <HashDigest <SHA256>?>()
                                              .FirstOrDefault();

            if (genesisHash is null || branchPoint.Equals(genesisHash))
            {
                return;
            }

            ColumnFamilyHandle cf = GetColumnFamily(_chainDb, destinationChainId);
            var  writeBatch       = new WriteBatch();
            long index            = 0;

            try
            {
                foreach (Iterator it in IterateDb(_chainDb, IndexKeyPrefix, sourceChainId))
                {
                    byte[] hashBytes = it.Value();
                    writeBatch.Put(it.Key(), hashBytes, cf);
                    index += 1;

                    if (writeBatch.Count() >= ForkWriteBatchSize)
                    {
                        _chainDb.Write(writeBatch);
                        writeBatch.Dispose();
                        writeBatch = new WriteBatch();
                    }

                    if (branchPoint.ToByteArray().SequenceEqual(hashBytes))
                    {
                        break;
                    }
                }
            }
            finally
            {
                _chainDb.Write(writeBatch);
                writeBatch.Dispose();
            }

            _chainDb.Put(
                IndexCountKey,
                RocksDBStoreBitConverter.GetBytes(index),
                cf
                );
        }
Exemple #13
0
        /// <inheritdoc/>
        public override void PutBlock <T>(Block <T> block)
        {
            if (_blockCache.ContainsKey(block.Hash))
            {
                return;
            }

            byte[] key = BlockKey(block.Hash);

            if (!(_blockIndexDb.Get(key) is null))
            {
                return;
            }

            long timestamp = block.Timestamp.ToUnixTimeSeconds();

            foreach (Transaction <T> tx in block.Transactions)
            {
                PutTransaction(tx);
            }

            _rwBlockLock.EnterWriteLock();
            try
            {
                string  blockDbName = $"epoch{timestamp / _blockEpochUnitSeconds}";
                RocksDb blockDb;
                lock (_blockDbCache)
                {
                    if (!_blockDbCache.TryGetValue(blockDbName, out blockDb))
                    {
                        blockDb = RocksDBUtils.OpenRocksDb(_options, BlockDbPath(blockDbName));
                        _blockDbCache.AddOrUpdate(blockDbName, blockDb);
                    }
                }

                BlockDigest digest = BlockDigest.FromBlock(block);
                byte[]      value  = digest.Serialize();
                blockDb.Put(key, value);
                _blockIndexDb.Put(key, RocksDBStoreBitConverter.GetBytes(blockDbName));
                _blockCache.AddOrUpdate(block.Hash, digest);
            }
            catch (Exception e)
            {
                LogUnexpectedException(nameof(PutBlock), e);
            }
            finally
            {
                _rwBlockLock.ExitWriteLock();
            }
        }
Exemple #14
0
        /// <inheritdoc/>
        public override IEnumerable <KeyValuePair <Address, long> > ListTxNonces(Guid chainId)
        {
            byte[] prefix = TxNonceKeyPrefix;

            foreach (Iterator it in IterateDb(_chainDb, prefix, chainId))
            {
                byte[] addressBytes = it.Key()
                                      .Skip(prefix.Length)
                                      .ToArray();
                var  address = new Address(addressBytes);
                long nonce   = RocksDBStoreBitConverter.ToInt64(it.Value());
                yield return(new KeyValuePair <Address, long>(address, nonce));
            }
        }
Exemple #15
0
        /// <inheritdoc/>
        public override void IncreaseTxNonce(Guid chainId, Address signer, long delta = 1)
        {
            try
            {
                ColumnFamilyHandle cf = GetColumnFamily(_chainDb, chainId);
                long nextNonce        = GetTxNonce(chainId, signer) + delta;

                byte[] key   = TxNonceKey(signer);
                byte[] bytes = RocksDBStoreBitConverter.GetBytes(nextNonce);

                _chainDb.Put(key, bytes, cf);
            }
            catch (Exception e)
            {
                LogUnexpectedException(nameof(IncreaseTxNonce), e);
            }
        }
Exemple #16
0
        /// <inheritdoc/>
        public override long CountIndex(Guid chainId)
        {
            try
            {
                ColumnFamilyHandle cf    = GetColumnFamily(_chainDb, chainId);
                byte[]             bytes = _chainDb.Get(IndexCountKey, cf);
                return(bytes is null
                    ? 0
                    : RocksDBStoreBitConverter.ToInt64(bytes));
            }
            catch (Exception e)
            {
                LogUnexpectedException(nameof(CountIndex), e);
            }

            return(0);
        }
Exemple #17
0
        /// <inheritdoc/>
        public override Transaction <T> GetTransaction <T>(TxId txid)
        {
            if (_txCache.TryGetValue(txid, out object cachedTx))
            {
                return((Transaction <T>)cachedTx);
            }

            byte[] key = TxKey(txid);
            if (!(_txIndexDb.Get(key) is byte[] txDbNameBytes))
            {
                return(null);
            }

            string txDbName = RocksDBStoreBitConverter.GetString(txDbNameBytes);

            _rwTxLock.EnterReadLock();
            try
            {
                RocksDb txDb;
                lock (_txDbCache)
                {
                    if (!_txDbCache.TryGetValue(txDbName, out txDb))
                    {
                        txDb = RocksDBUtils.OpenRocksDb(_options, TxDbPath(txDbName));
                        _txDbCache.AddOrUpdate(txDbName, txDb);
                    }
                }

                byte[] txBytes = txDb.Get(key);

                Transaction <T> tx = Transaction <T> .Deserialize(txBytes, false);

                _txCache.AddOrUpdate(txid, tx);
                return(tx);
            }
            catch (Exception e)
            {
                LogUnexpectedException(nameof(GetTransaction), e);
                return(null);
            }
            finally
            {
                _rwTxLock.ExitReadLock();
            }
        }
Exemple #18
0
        /// <inheritdoc/>
        public override long AppendIndex(Guid chainId, HashDigest <SHA256> hash)
        {
            long index = CountIndex(chainId);

            byte[] indexBytes = RocksDBStoreBitConverter.GetBytes(index);

            byte[]             key = IndexKeyPrefix.Concat(indexBytes).ToArray();
            ColumnFamilyHandle cf  = GetColumnFamily(_chainDb, chainId);

            using var writeBatch = new WriteBatch();

            writeBatch.Put(key, hash.ToByteArray(), cf);
            writeBatch.Put(IndexCountKey, RocksDBStoreBitConverter.GetBytes(index + 1), cf);

            _chainDb.Write(writeBatch);

            return(index);
        }
Exemple #19
0
        /// <inheritdoc/>
        public override long GetTxNonce(Guid chainId, Address address)
        {
            try
            {
                ColumnFamilyHandle cf    = GetColumnFamily(_chainDb, chainId);
                byte[]             key   = TxNonceKey(address);
                byte[]             bytes = _chainDb.Get(key, cf);
                return(bytes is null
                    ? 0
                    : RocksDBStoreBitConverter.ToInt64(bytes));
            }
            catch (Exception e)
            {
                LogUnexpectedException(nameof(GetTxNonce), e);
            }

            return(0);
        }
Exemple #20
0
        ListAllStateReferences(
            Guid chainId,
            long lowestIndex  = 0,
            long highestIndex = long.MaxValue)
        {
            byte[] prefix = StateRefKeyPrefix;

            var stateRefs = new List <StateRef>();

            foreach (Iterator it in IterateDb(_stateRefDb, prefix, chainId))
            {
                byte[] key            = it.Key();
                int    stateKeyLength = key.Length - sizeof(long) - prefix.Length;
                byte[] stateKeyBytes  = key.Skip(prefix.Length).Take(stateKeyLength).ToArray();
                string stateKey       = RocksDBStoreBitConverter.GetString(stateKeyBytes);

                byte[] indexBytes = key.Skip(prefix.Length + stateKeyLength).ToArray();
                long   index      = RocksDBStoreBitConverter.ToInt64(indexBytes);

                if (index < lowestIndex || index > highestIndex)
                {
                    continue;
                }

                var hash     = new HashDigest <SHA256>(it.Value());
                var stateRef = new StateRef
                {
                    StateKey   = stateKey,
                    BlockHash  = hash,
                    BlockIndex = index,
                };

                stateRefs.Add(stateRef);
            }

            return(stateRefs
                   .GroupBy(stateRef => stateRef.StateKey)
                   .ToImmutableDictionary(
                       g => g.Key,
                       g => (IImmutableList <HashDigest <SHA256> >)g
                       .Select(r => r.BlockHash).ToImmutableList()
                       ));
        }
Exemple #21
0
        /// <inheritdoc cref="BaseStore.ForkBlockIndexes(Guid, Guid, BlockHash)"/>
        public override void ForkBlockIndexes(
            Guid sourceChainId,
            Guid destinationChainId,
            BlockHash branchpoint
            )
        {
            BlockHash?genesisHash = IterateIndexes(sourceChainId, 0, 1).FirstOrDefault();

            if (genesisHash is null || branchpoint.Equals(genesisHash))
            {
                return;
            }

            ColumnFamilyHandle srcCf  = GetColumnFamily(_chainDb, sourceChainId);
            ColumnFamilyHandle destCf = GetColumnFamily(_chainDb, destinationChainId);

            foreach (Iterator k in IterateDb(_chainDb, IndexKeyPrefix, destinationChainId))
            {
                _chainDb.Remove(k.Key(), destCf);
            }

            long bpIndex = GetBlockIndex(branchpoint).Value;

            if (GetPreviousChainInfo(srcCf) is { } chainInfo&&
                chainInfo.Item2 == bpIndex)
            {
                ForkBlockIndexes(chainInfo.Item1, destinationChainId, branchpoint);
                return;
            }

            _chainDb.Put(PreviousChainIdKey, sourceChainId.ToByteArray(), destCf);
            _chainDb.Put(
                PreviousChainIndexKey,
                RocksDBStoreBitConverter.GetBytes(bpIndex),
                destCf
                );
            _chainDb.Put(
                IndexCountKey,
                RocksDBStoreBitConverter.GetBytes(bpIndex + 1),
                destCf
                );
            AddFork(srcCf, destinationChainId);
        }
Exemple #22
0
        private IEnumerable <Tuple <HashDigest <SHA256>, long> > IterateStateReferences(
            Guid chainId,
            byte[] prefix,
            long highestIndex,
            long lowestIndex,
            int limit)
        {
            ColumnFamilyHandle cf = GetColumnFamily(_stateRefDb, chainId);

            using Iterator it = _stateRefDb.NewIterator(cf);

            // FIXME: We need to change the state reference to be ordered by reverse byte-wise
            // and use the Seek function.
            it.SeekToLast();
            while (it.Valid() && !it.Key().StartsWith(prefix))
            {
                it.Prev();
            }

            for (; it.Valid() && it.Key().StartsWith(prefix); it.Prev())
            {
                byte[] indexBytes = it.Key().Skip(prefix.Length).ToArray();
                long   index      = RocksDBStoreBitConverter.ToInt64(indexBytes);

                if (index > highestIndex)
                {
                    continue;
                }

                if (index < lowestIndex || limit <= 0)
                {
                    break;
                }

                byte[] hashBytes = it.Value();
                var    hash      = new HashDigest <SHA256>(hashBytes);

                yield return(new Tuple <HashDigest <SHA256>, long>(hash, index));

                limit--;
            }
        }
Exemple #23
0
        /// <inheritdoc/>
        public override IEnumerable <string> ListStateKeys(Guid chainId)
        {
            byte[] prefix       = StateRefKeyPrefix;
            var    prevStateKey = string.Empty;

            foreach (Iterator it in IterateDb(_stateRefDb, prefix, chainId))
            {
                byte[] key            = it.Key();
                int    stateKeyLength = key.Length - sizeof(long) - prefix.Length;
                byte[] stateKeyBytes  = key.Skip(prefix.Length).Take(stateKeyLength).ToArray();
                string stateKey       = RocksDBStoreBitConverter.GetString(stateKeyBytes);

                if (stateKey != prevStateKey)
                {
                    yield return(stateKey);

                    prevStateKey = stateKey;
                }
            }
        }
Exemple #24
0
        /// <inheritdoc cref="BaseStore.IndexBlockHash(Guid, long)"/>
        public override BlockHash?IndexBlockHash(Guid chainId, long index)
        {
            if (index < 0)
            {
                index += CountIndex(chainId);

                if (index < 0)
                {
                    return(null);
                }
            }

            ColumnFamilyHandle cf = GetColumnFamily(_chainDb, chainId);

            byte[] indexBytes = RocksDBStoreBitConverter.GetBytes(index);

            byte[] key   = IndexKeyPrefix.Concat(indexBytes).ToArray();
            byte[] bytes = _chainDb.Get(key, cf);
            return(bytes is null ? (BlockHash?)null : new BlockHash(bytes));
        }
Exemple #25
0
        private BlockHash?IndexBlockHash(Guid chainId, long index, bool includeDeleted)
        {
            try
            {
                if (index < 0)
                {
                    index += CountIndex(chainId);

                    if (index < 0)
                    {
                        return(null);
                    }
                }

                ColumnFamilyHandle cf = GetColumnFamily(_chainDb, chainId);

                if (!includeDeleted && IsDeletionMarked(cf))
                {
                    return(null);
                }

                if (GetPreviousChainInfo(cf) is { } chainInfo&&
                    chainInfo.Item2 >= index)
                {
                    return(IndexBlockHash(chainInfo.Item1, index, true));
                }

                byte[] indexBytes = RocksDBStoreBitConverter.GetBytes(index);

                byte[] key   = IndexKeyPrefix.Concat(indexBytes).ToArray();
                byte[] bytes = _chainDb.Get(key, cf);
                return(bytes is null ? (BlockHash?)null : new BlockHash(bytes));
            }
            catch (Exception e)
            {
                LogUnexpectedException(nameof(IndexBlockHash), e);
            }

            return(null);
        }
Exemple #26
0
        /// <inheritdoc cref="BaseStore.DeleteBlock(BlockHash)"/>
        public override bool DeleteBlock(BlockHash blockHash)
        {
            byte[] key = BlockKey(blockHash);

            if (!(_blockIndexDb.Get(key) is byte[] blockDbNameByte))
            {
                return(false);
            }

            _rwBlockLock.EnterWriteLock();
            try
            {
                string  blockDbName = RocksDBStoreBitConverter.GetString(blockDbNameByte);
                RocksDb blockDb;
                lock (_blockDbCache)
                {
                    if (!_blockDbCache.TryGetValue(blockDbName, out blockDb))
                    {
                        blockDb = RocksDBUtils.OpenRocksDb(_options, BlockDbPath(blockDbName));
                        _blockDbCache.AddOrUpdate(blockDbName, blockDb);
                    }
                }

                _blockCache.Remove(blockHash);
                _blockIndexDb.Remove(key);
                blockDb.Remove(key);
                return(true);
            }
            catch (Exception e)
            {
                LogUnexpectedException(nameof(DeleteBlock), e);
            }
            finally
            {
                _rwBlockLock.ExitWriteLock();
            }

            return(false);
        }
Exemple #27
0
        /// <inheritdoc/>
        public override void ForkStateReferences <T>(
            Guid sourceChainId,
            Guid destinationChainId,
            Block <T> branchPoint)
        {
            byte[]             prefix = StateRefKeyPrefix;
            ColumnFamilyHandle destCf = GetColumnFamily(_stateRefDb, destinationChainId);

            foreach (Iterator it in IterateDb(_stateRefDb, prefix, sourceChainId))
            {
                byte[] key        = it.Key();
                byte[] indexBytes = key.Skip(key.Length - sizeof(long)).ToArray();
                long   index      = RocksDBStoreBitConverter.ToInt64(indexBytes);

                if (index > branchPoint.Index)
                {
                    continue;
                }

                _stateRefDb.Put(key, it.Value(), destCf);
            }

            using Iterator destIt = _stateRefDb.NewIterator(destCf);

            destIt.Seek(prefix);

            if (!(destIt.Valid() && destIt.Key().StartsWith(prefix)) &&
                CountIndex(sourceChainId) < 1)
            {
                throw new ChainIdNotFoundException(
                          sourceChainId,
                          "The source chain to be forked does not exist.");
            }

            _lastStateRefCaches.Remove(destinationChainId);
        }