From f89e6cf7bd812b055239ce6472e314b171f6492a Mon Sep 17 00:00:00 2001 From: Timofey Gusev Date: Tue, 11 Feb 2020 11:51:16 +0300 Subject: [PATCH 1/2] initial commit --- .../api/http/routes/WalletInfoApiRoute.scala | 10 ++- .../WalletVersionalLevelDB.scala | 66 ++++++++++++++++--- 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/main/scala/encry/api/http/routes/WalletInfoApiRoute.scala b/src/main/scala/encry/api/http/routes/WalletInfoApiRoute.scala index 17e4cc51d5..47003ad93c 100644 --- a/src/main/scala/encry/api/http/routes/WalletInfoApiRoute.scala +++ b/src/main/scala/encry/api/http/routes/WalletInfoApiRoute.scala @@ -19,9 +19,10 @@ import encry.view.wallet.EncryWallet import io.circe.syntax._ import org.encryfoundation.common.crypto.PrivateKey25519 import org.encryfoundation.common.modifiers.mempool.transaction.{PubKeyLockedContract, Transaction} -import org.encryfoundation.common.modifiers.state.box.{AssetBox, MonetaryBox, TokenIssuingBox} +import org.encryfoundation.common.modifiers.state.box.{AssetBox, EncryBox, EncryProposition, MonetaryBox, TokenIssuingBox} import org.encryfoundation.common.utils.Algos import org.encryfoundation.common.utils.TaggedTypes.ADKey + import scala.concurrent.Future import scala.util.{Failure, Success, Try} @@ -137,6 +138,13 @@ case class WalletInfoApiRoute(dataHolder: ActorRef, case Success(value) => ADKey @@ value case Failure(e) => throw new RuntimeException(s"Failed to decode tokeId $s. Cause: $e") }) + val a: Seq[MonetaryBox] = wallet.vault.walletStorage + .getAllBoxes() + .collect { + case ab: AssetBox if ab.tokenIdOpt.isEmpty || ab.tokenIdOpt === decodedTokenOpt => ab + case tib: TokenIssuingBox if decodedTokenOpt.exists(_.sameElements(tib.tokenId)) => tib + } + val boxes: IndexedSeq[MonetaryBox] = wallet.vault.walletStorage .getAllBoxes() .collect { diff --git a/src/main/scala/encry/storage/levelDb/versionalLevelDB/WalletVersionalLevelDB.scala b/src/main/scala/encry/storage/levelDb/versionalLevelDB/WalletVersionalLevelDB.scala index 9991ea0933..b8fc36bae0 100644 --- a/src/main/scala/encry/storage/levelDb/versionalLevelDB/WalletVersionalLevelDB.scala +++ b/src/main/scala/encry/storage/levelDb/versionalLevelDB/WalletVersionalLevelDB.scala @@ -9,12 +9,13 @@ import encry.storage.levelDb.versionalLevelDB.VersionalLevelDBCompanion._ import encry.utils.{BalanceCalculator, ByteStr} import org.encryfoundation.common.modifiers.state.StateModifierSerializer import org.encryfoundation.common.modifiers.state.box.Box.Amount -import org.encryfoundation.common.modifiers.state.box.EncryBaseBox +import org.encryfoundation.common.modifiers.state.box.{AssetBox, DataBox, EncryBaseBox, TokenIssuingBox} import org.encryfoundation.common.modifiers.state.box.TokenIssuingBox.TokenId -import org.encryfoundation.common.utils.Algos +import org.encryfoundation.common.utils.{Algos, TaggedTypes} import org.encryfoundation.common.utils.TaggedTypes.{ADKey, ModifierId} import org.iq80.leveldb.DB -import scorex.crypto.hash.Digest32 +import supertagged.@@ + import scala.util.Success case class WalletVersionalLevelDB(db: DB, settings: LevelDBSettings) extends StrictLogging with AutoCloseable { @@ -29,8 +30,26 @@ case class WalletVersionalLevelDB(db: DB, settings: LevelDBSettings) extends Str .map { case (key, bytes) => StateModifierSerializer.parseBytes(bytes, key.head) } .collect { case Success(box) => box } + def getBoxesByPredicate[BXT](f: List[BXT] => Boolean): Unit = { + val keys: List[VersionalLevelDbKey] = levelDb.getCurrentElementsKeys().filterNot(_.sameElements(BALANCE_KEY)) + @scala.annotation.tailrec + def loop(acc: List[BXT], newKeys: List[VersionalLevelDbKey]): List[BXT] = { + (for { + nextKey <- newKeys.headOption + nextBox <- getBoxById(ADKey @@ nextKey.untag(VersionalLevelDbKey)) + } yield nextBox) match { + case Some(box: BXT) => + val updatedAcc: List[BXT] = box :: acc + if (f(updatedAcc)) acc else loop(updatedAcc, newKeys.drop(1)) + case Some(_) => loop(acc, newKeys.drop(1)) + case None if newKeys.nonEmpty => loop(acc, newKeys.drop(1)) + case None => acc + } + } + } + def getBoxById(id: ADKey): Option[EncryBaseBox] = levelDb.get(VersionalLevelDbKey @@ id.untag(ADKey)) - .flatMap(wrappedBx => StateModifierSerializer.parseBytes(wrappedBx, id.head).toOption) + .flatMap(StateModifierSerializer.parseBytes(_, id.head).toOption) def getTokenBalanceById(id: TokenId): Option[Amount] = getBalances .find(_._1._2 == Algos.encode(id)) @@ -43,6 +62,16 @@ case class WalletVersionalLevelDB(db: DB, settings: LevelDBSettings) extends Str def updateWallet(modifierId: ModifierId, newBxs: Seq[EncryBaseBox], spentBxs: Seq[EncryBaseBox], intrinsicTokenId: ADKey): Unit = { val bxsToInsert: Seq[EncryBaseBox] = newBxs.filter(bx => !spentBxs.contains(bx)) + val boxesToInsert: (List[DataBox], List[TokenIssuingBox], List[AssetBox]) = + newBxs.foldLeft(List.empty[DataBox], List.empty[TokenIssuingBox], List.empty[AssetBox]) { + case ((dataBoxes, tokenIssuingBoxes, assetBoxes), nextBox: AssetBox) if !spentBxs.contains(nextBox) => + (dataBoxes, tokenIssuingBoxes, nextBox :: assetBoxes) + case ((dataBoxes, tokenIssuingBoxes, assetBoxes), nextBox: TokenIssuingBox) if !spentBxs.contains(nextBox) => + (dataBoxes, nextBox :: tokenIssuingBoxes, assetBoxes) + case ((dataBoxes, tokenIssuingBoxes, assetBoxes), nextBox: DataBox) if !spentBxs.contains(nextBox) => + (nextBox :: dataBoxes, tokenIssuingBoxes, assetBoxes) + case ((dataBoxes, tokenIssuingBoxes, assetBoxes), nextBox) => (dataBoxes, tokenIssuingBoxes, assetBoxes) + } val newBalances: Map[(String, String), Amount] = { val toRemoveFromBalance = BalanceCalculator.balanceSheet(spentBxs, intrinsicTokenId) .map { case ((hash, key), value) => (hash, ByteStr(key)) -> value * -1 } @@ -55,10 +84,14 @@ case class WalletVersionalLevelDB(db: DB, settings: LevelDBSettings) extends Str newBalances.foldLeft(Array.emptyByteArray) { case (acc, ((hash, tokenId), balance)) => acc ++ Algos.decode(hash).get ++ Algos.decode(tokenId).get ++ Longs.toByteArray(balance) } - levelDb.insert(LevelDbDiff(LevelDBVersion @@ modifierId.untag(ModifierId), - newBalanceKeyValue :: bxsToInsert.map(bx => (VersionalLevelDbKey @@ bx.id.untag(ADKey), - VersionalLevelDbValue @@ bx.bytes)).toList, - spentBxs.map(elem => VersionalLevelDbKey @@ elem.id.untag(ADKey))) + levelDb.insert( + LevelDbDiff( + LevelDBVersion @@ modifierId.untag(ModifierId), + newBalanceKeyValue :: bxsToInsert.map((bx: EncryBaseBox) => + (VersionalLevelDbKey @@ bx.id.untag(ADKey), VersionalLevelDbValue @@ bx.bytes) + ).toList, + spentBxs.map(elem => VersionalLevelDbKey @@ elem.id.untag(ADKey)) + ) ) } @@ -68,13 +101,26 @@ case class WalletVersionalLevelDB(db: DB, settings: LevelDBSettings) extends Str .map(ch => (Algos.encode(ch.take(32)), Algos.encode(ch.slice(32, 64))) -> Longs.fromByteArray(ch.takeRight(8))) .toMap).getOrElse(Map.empty) + private def formIdsList(input: Option[VersionalLevelDbValue]): List[ADKey] = + input + .map(_.grouped(32).map(ADKey @@ _).toList) + .getOrElse(List.empty[ADKey]) + + private def getAssetBoxesIds: List[ADKey] = formIdsList(levelDb.get(ASSET_BOX_KEY)) + + private def getDataBoxesIds: List[ADKey] = formIdsList(levelDb.get(DATA_BOX_KEY)) + + private def getTokenIssueBoxesIds: List[ADKey] = formIdsList(levelDb.get(TOKEN_ISSUE_BOX_KEY)) + override def close(): Unit = levelDb.close() } object WalletVersionalLevelDBCompanion extends StrictLogging { - val BALANCE_KEY: VersionalLevelDbKey = - VersionalLevelDbKey @@ Algos.hash("BALANCE_KEY").untag(Digest32) + val ASSET_BOX_KEY: VersionalLevelDbKey = VersionalLevelDbKey @@ Algos.hash("ASSET_BOX_KEY") + val DATA_BOX_KEY: VersionalLevelDbKey = VersionalLevelDbKey @@ Algos.hash("DATA_BOX_KEY") + val TOKEN_ISSUE_BOX_KEY: VersionalLevelDbKey = VersionalLevelDbKey @@ Algos.hash("TOKEN_ISSUE_BOX_KEY") + val BALANCE_KEY: VersionalLevelDbKey = VersionalLevelDbKey @@ Algos.hash("BALANCE_KEY") val INIT_MAP: Map[VersionalLevelDbKey, VersionalLevelDbValue] = Map( BALANCE_KEY -> VersionalLevelDbValue @@ Array.emptyByteArray From 1e644d169aff06ceed81ada961b39843f2382cb2 Mon Sep 17 00:00:00 2001 From: Timofey Gusev Date: Tue, 11 Feb 2020 15:40:34 +0300 Subject: [PATCH 2/2] new additions --- .../versionalLevelDB/WalletVersionalLevelDB.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/scala/encry/storage/levelDb/versionalLevelDB/WalletVersionalLevelDB.scala b/src/main/scala/encry/storage/levelDb/versionalLevelDB/WalletVersionalLevelDB.scala index b8fc36bae0..df6ef9eb77 100644 --- a/src/main/scala/encry/storage/levelDb/versionalLevelDB/WalletVersionalLevelDB.scala +++ b/src/main/scala/encry/storage/levelDb/versionalLevelDB/WalletVersionalLevelDB.scala @@ -61,8 +61,7 @@ case class WalletVersionalLevelDB(db: DB, settings: LevelDBSettings) extends Str def updateWallet(modifierId: ModifierId, newBxs: Seq[EncryBaseBox], spentBxs: Seq[EncryBaseBox], intrinsicTokenId: ADKey): Unit = { - val bxsToInsert: Seq[EncryBaseBox] = newBxs.filter(bx => !spentBxs.contains(bx)) - val boxesToInsert: (List[DataBox], List[TokenIssuingBox], List[AssetBox]) = + val (dataBoxes: List[DataBox], tokenIssuingBoxes: List[TokenIssuingBox], assetBoxes: List[AssetBox]) = newBxs.foldLeft(List.empty[DataBox], List.empty[TokenIssuingBox], List.empty[AssetBox]) { case ((dataBoxes, tokenIssuingBoxes, assetBoxes), nextBox: AssetBox) if !spentBxs.contains(nextBox) => (dataBoxes, tokenIssuingBoxes, nextBox :: assetBoxes) @@ -70,7 +69,8 @@ case class WalletVersionalLevelDB(db: DB, settings: LevelDBSettings) extends Str (dataBoxes, nextBox :: tokenIssuingBoxes, assetBoxes) case ((dataBoxes, tokenIssuingBoxes, assetBoxes), nextBox: DataBox) if !spentBxs.contains(nextBox) => (nextBox :: dataBoxes, tokenIssuingBoxes, assetBoxes) - case ((dataBoxes, tokenIssuingBoxes, assetBoxes), nextBox) => (dataBoxes, tokenIssuingBoxes, assetBoxes) + case ((dataBoxes, tokenIssuingBoxes, assetBoxes), _) => + (dataBoxes, tokenIssuingBoxes, assetBoxes) } val newBalances: Map[(String, String), Amount] = { val toRemoveFromBalance = BalanceCalculator.balanceSheet(spentBxs, intrinsicTokenId) @@ -87,9 +87,9 @@ case class WalletVersionalLevelDB(db: DB, settings: LevelDBSettings) extends Str levelDb.insert( LevelDbDiff( LevelDBVersion @@ modifierId.untag(ModifierId), - newBalanceKeyValue :: bxsToInsert.map((bx: EncryBaseBox) => + newBalanceKeyValue :: (dataBoxes ::: tokenIssuingBoxes ::: assetBoxes).map(bx => (VersionalLevelDbKey @@ bx.id.untag(ADKey), VersionalLevelDbValue @@ bx.bytes) - ).toList, + ), spentBxs.map(elem => VersionalLevelDbKey @@ elem.id.untag(ADKey)) ) )