Skip to content

Commit

Permalink
Bugfixing numeric serialize (#392)
Browse files Browse the repository at this point in the history
  • Loading branch information
arndey authored Dec 7, 2023
1 parent f8b733a commit 4d74923
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 44 deletions.
21 changes: 11 additions & 10 deletions modules/block/src/main/kotlin/jp/co/soramitsu/iroha2/Serde.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import jp.co.soramitsu.iroha2.generated.DomainId
import jp.co.soramitsu.iroha2.generated.EvaluatesTo
import jp.co.soramitsu.iroha2.generated.ExecutorMode
import jp.co.soramitsu.iroha2.generated.Expression
import jp.co.soramitsu.iroha2.generated.Fixed
import jp.co.soramitsu.iroha2.generated.GrantExpr
import jp.co.soramitsu.iroha2.generated.Hash
import jp.co.soramitsu.iroha2.generated.HashValue
Expand Down Expand Up @@ -75,7 +76,6 @@ import jp.co.soramitsu.iroha2.generated.TriggerId
import jp.co.soramitsu.iroha2.generated.TriggerOfTriggeringFilterBox
import jp.co.soramitsu.iroha2.generated.Value
import java.io.ByteArrayOutputStream
import java.math.BigInteger
import kotlin.reflect.KClass
import kotlin.reflect.full.createInstance
import kotlin.reflect.full.memberProperties
Expand Down Expand Up @@ -777,10 +777,10 @@ private fun mintBurnSerialize(
}

private fun NumericValue.formatAsString() = when (this) {
is NumericValue.U32 -> this.u32
is NumericValue.U64 -> this.u64
is NumericValue.U128 -> this.u128
is NumericValue.Fixed -> this.fixed.fixedPointOfI64
is NumericValue.U32 -> "${this.u32}_u32"
is NumericValue.U64 -> "${this.u64}_u64"
is NumericValue.U128 -> "${this.u128}_u128"
is NumericValue.Fixed -> "${this.fixed.fixedPointOfI64}_fx"
}.toString()

private fun NumericValue.format() = when (this) {
Expand Down Expand Up @@ -1135,11 +1135,12 @@ private fun deserializeMetadata(p: JsonParser, mapper: ObjectMapper): Metadata {
}

private fun String.toNumericValue(): NumericValue {
val number = BigInteger(this)
return when {
number >= BigInteger.ZERO && number <= "4294967295".toBigInteger() -> NumericValue.U32(number.toLong())
number <= "18446744073709551615".toBigInteger() -> NumericValue.U64(number)
number <= "340282366920938463463374607431768211455".toBigInteger() -> NumericValue.U128(number)
val (number, type) = this.split('_')
return when (type) {
NumericValue.U32::class.simpleName?.lowercase() -> NumericValue.U32(number.toLong())
NumericValue.U64::class.simpleName?.lowercase() -> NumericValue.U64(number.toBigInteger())
NumericValue.U128::class.simpleName?.lowercase() -> NumericValue.U128(number.toBigInteger())
"fx" -> NumericValue.Fixed(Fixed(number.toBigDecimal()))
else -> throw IllegalArgumentException("Number out of range")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,14 @@ fun String.asValue() = Value.String(this)

fun Int.asValue() = Value.Numeric(NumericValue.U32(this.toLong()))

fun Long.asValue() = Value.Numeric(NumericValue.U128(BigInteger.valueOf(this)))

fun BigInteger.asValue() = Value.Numeric(NumericValue.U128(this))
fun Double.asValue() = Value.Numeric(NumericValue.Fixed(Fixed(this.toBigDecimal())))

fun BigDecimal.asValue() = Value.Numeric(NumericValue.Fixed(Fixed(this)))

fun Long.asValue() = Value.Numeric(NumericValue.U64(BigInteger.valueOf(this)))

fun BigInteger.asValue() = Value.Numeric(NumericValue.U128(this))

fun Boolean.asValue() = Value.Bool(this)

fun AccountId.asValue() = Value.Id(IdBox.AccountId(this))
Expand Down Expand Up @@ -298,6 +300,7 @@ inline fun <reified T> T.asValue() = when (this) {
is String -> this.asValue()
is Long -> this.asValue()
is Int -> this.asValue()
is Double -> this.asValue()
is BigInteger -> this.asValue()
is BigDecimal -> this.asValue()
is Boolean -> this.asValue()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,9 @@ object Instructions {
/**
* Execute a trigger
*/
fun executeTrigger(triggerId: TriggerId) = InstructionExpr.ExecuteTrigger(ExecuteTriggerExpr(triggerId.evaluatesTo()))
fun executeTrigger(triggerId: TriggerId) = InstructionExpr.ExecuteTrigger(
ExecuteTriggerExpr(triggerId.evaluatesTo()),
)

/**
* Mint an asset of the [AssetValueType.Quantity] asset value type
Expand Down Expand Up @@ -513,6 +515,19 @@ object Instructions {
}
}

/**
* Revoke an account the [Permissions.CanSetKeyValueInDomain] permission
*/
fun grantSetKeyValueDomain(domainId: DomainId, target: AccountId): InstructionExpr {
return grantSome(
target,
PermissionToken(
definitionId = Permissions.CanSetKeyValueInDomain.type,
payload = domainId.asJsonString().asStringWithJson(),
).asValue(),
)
}

/**
* Revoke an account the [Permissions.CanSetKeyValueInDomain] permission
*/
Expand Down Expand Up @@ -552,7 +567,10 @@ object Instructions {
),
)

private inline fun revokeSome(accountId: AccountId, permissionToken: () -> PermissionToken): InstructionExpr.Revoke {
private inline fun revokeSome(
accountId: AccountId,
permissionToken: () -> PermissionToken,
): InstructionExpr.Revoke {
return InstructionExpr.Revoke(
RevokeExpr(
destinationId = accountId.evaluatesTo(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import jp.co.soramitsu.iroha2.generated.AssetDefinitionId
import jp.co.soramitsu.iroha2.generated.AssetId
import jp.co.soramitsu.iroha2.generated.AssetValue
import jp.co.soramitsu.iroha2.generated.AssetValueType
import jp.co.soramitsu.iroha2.generated.DomainId
import jp.co.soramitsu.iroha2.generated.IdBox
import jp.co.soramitsu.iroha2.generated.Metadata
import jp.co.soramitsu.iroha2.generated.Name
Expand Down Expand Up @@ -44,6 +45,7 @@ import jp.co.soramitsu.iroha2.testengine.NewAccountWithMetadata
import jp.co.soramitsu.iroha2.testengine.NewDomainWithMetadata
import jp.co.soramitsu.iroha2.testengine.RubbishToTestMultipleGenesis
import jp.co.soramitsu.iroha2.testengine.StoreAssetWithMetadata
import jp.co.soramitsu.iroha2.testengine.WithDomainTransferredToBob
import jp.co.soramitsu.iroha2.testengine.WithIroha
import jp.co.soramitsu.iroha2.testengine.WithIrohaManual
import jp.co.soramitsu.iroha2.testengine.XorAndValAssets
Expand Down Expand Up @@ -411,6 +413,24 @@ class InstructionsTest : IrohaTest<Iroha2Client>() {
}
}

@Test
@WithIroha([DefaultGenesis::class])
fun `domain metadata set key value with permissions`(): Unit = runBlocking {
val domainId = DomainId(randomAlphabetic(10).asName())
client.tx(BOB_ACCOUNT_ID, BOB_KEYPAIR) {
registerDomain(domainId)
grantPermissionToken(
Permissions.CanSetKeyValueInDomain,
domainId.asJsonString(),
ALICE_ACCOUNT_ID,
)
}

client.tx(ALICE_ACCOUNT_ID, ALICE_KEYPAIR) {
setKeyValue(domainId, randomAlphabetic(10).asName(), randomAlphabetic(10).asValue())
}
}

@Test
@WithIroha([DefaultGenesis::class])
@Feature("Accounts")
Expand Down Expand Up @@ -1051,43 +1071,64 @@ class InstructionsTest : IrohaTest<Iroha2Client>() {
}
}

@Test
@WithIroha([WithDomainTransferredToBob::class])
@Feature("Domains")
@Story("Account transfers domain ownership")
@SdkTestId("transfer_domain_ownership_in_genesis")
fun `transfer domain ownership in genesis`(): Unit = runBlocking {
val key = randomAlphabetic(5).asName()
val value = randomAlphabetic(5).asValue()
client.tx(BOB_ACCOUNT_ID, BOB_KEYPAIR) {
setKeyValue(WithDomainTransferredToBob.DOMAIN_ID, key, value)
}
val extractedValue = QueryBuilder.findDomainById(WithDomainTransferredToBob.DOMAIN_ID)
.account(ALICE_ACCOUNT_ID)
.buildSigned(ALICE_KEYPAIR)
.let { query -> client.sendQuery(query) }
.metadata.map[key]
assertEquals(value.string, extractedValue?.cast<Value.String>()?.string)
}

@Test
@WithIroha([DefaultGenesis::class])
@Feature("Domains")
@Story("Account transfers domain ownership")
@SdkTestId("transfer_domain_ownership")
fun `transfer domain ownership`(): Unit = runBlocking {
val domainId = "Kingdom".asDomainId()
client.tx(ALICE_ACCOUNT_ID, ALICE_KEYPAIR) { registerDomain(domainId) }

client.sendTransaction {
account(super.account)
registerDomain(domainId)
buildSigned(super.keyPair)
}.also { d ->
withTimeout(txTimeout) { d.await() }
assertFailsWith(TransactionRejectedException::class) {
client.tx(BOB_ACCOUNT_ID, BOB_KEYPAIR) {
setKeyValue(domainId, randomAlphabetic(5).asName(), randomAlphabetic(5).asValue())
}
}
var kingdomDomainOwnedBy = QueryBuilder.findDomainById(domainId)
.account(super.account)
.buildSigned(super.keyPair)
.let { query ->
client.sendQuery(query)
}.ownedBy
.account(ALICE_ACCOUNT_ID)
.buildSigned(ALICE_KEYPAIR)
.let { query -> client.sendQuery(query) }.ownedBy
assertEquals(ALICE_ACCOUNT_ID, kingdomDomainOwnedBy)

client.tx {
transferDomainOwnership(
ALICE_ACCOUNT_ID,
IdBox.DomainId(domainId),
BOB_ACCOUNT_ID,
)
client.tx(ALICE_ACCOUNT_ID, ALICE_KEYPAIR) {
transferDomainOwnership(ALICE_ACCOUNT_ID, IdBox.DomainId(domainId), BOB_ACCOUNT_ID)
}
kingdomDomainOwnedBy = QueryBuilder.findDomainById(domainId)
.account(super.account)
.buildSigned(super.keyPair)
.let { query ->
client.sendQuery(query)
}.ownedBy
.account(ALICE_ACCOUNT_ID)
.buildSigned(ALICE_KEYPAIR)
.let { query -> client.sendQuery(query) }.ownedBy
assertEquals(BOB_ACCOUNT_ID, kingdomDomainOwnedBy)

val key = randomAlphabetic(5).asName()
val value = randomAlphabetic(5).asValue()
client.tx(BOB_ACCOUNT_ID, BOB_KEYPAIR) { setKeyValue(domainId, key, value) }

val extractedValue = QueryBuilder.findDomainById(domainId)
.account(ALICE_ACCOUNT_ID)
.buildSigned(ALICE_KEYPAIR)
.let { query -> client.sendQuery(query) }
.metadata.map[key]
assertEquals(value.string, extractedValue?.cast<Value.String>()?.string)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ import jp.co.soramitsu.iroha2.query.QueryBuilder
import jp.co.soramitsu.iroha2.testengine.ALICE_ACCOUNT_ID
import jp.co.soramitsu.iroha2.testengine.ALICE_ACCOUNT_NAME
import jp.co.soramitsu.iroha2.testengine.ALICE_KEYPAIR
import jp.co.soramitsu.iroha2.testengine.AliceAndBobHasPermissionToMintPublicKeys
import jp.co.soramitsu.iroha2.testengine.AliceCanMintXor
import jp.co.soramitsu.iroha2.testengine.AliceHas100XorAndPermissionToBurn
import jp.co.soramitsu.iroha2.testengine.AliceHasRoleWithAccessToBobsMetadata
import jp.co.soramitsu.iroha2.testengine.AliceWithTestAssets
import jp.co.soramitsu.iroha2.testengine.BOB_ACCOUNT_ID
import jp.co.soramitsu.iroha2.testengine.BOB_ACCOUNT_NAME
import jp.co.soramitsu.iroha2.testengine.BOB_KEYPAIR
import jp.co.soramitsu.iroha2.testengine.DEFAULT_ASSET_DEFINITION_ID
import jp.co.soramitsu.iroha2.testengine.DEFAULT_ASSET_ID
import jp.co.soramitsu.iroha2.testengine.DEFAULT_DOMAIN_ID
Expand Down Expand Up @@ -64,6 +66,33 @@ import kotlin.test.assertTrue
@Permission("no_permission_required")
class QueriesTest : IrohaTest<Iroha2Client>() {

@Test
@WithIroha([AliceAndBobHasPermissionToMintPublicKeys::class])
@Feature("Accounts")
@Story("Account sets key value pair")
@Permission("CanSetKeyValueInUserAsset")
@SdkTestId("query_permission_tokens_by_accountId")
fun `query permission tokens by accountId`(): Unit = runBlocking {
val permissionsBefore = QueryBuilder.findPermissionTokensByAccountId(BOB_ACCOUNT_ID)
.account(BOB_ACCOUNT_ID)
.buildSigned(BOB_KEYPAIR)
.let { query -> client.sendQuery(query) }
assertEquals(1, permissionsBefore.size)

client.tx(ALICE_ACCOUNT_ID, ALICE_KEYPAIR) {
grantPermissionToken(
Permissions.CanSetKeyValueInUserAccount,
ALICE_ACCOUNT_ID.asJsonString(),
BOB_ACCOUNT_ID,
)
}
val permissionsAfter = QueryBuilder.findPermissionTokensByAccountId(BOB_ACCOUNT_ID)
.account(BOB_ACCOUNT_ID)
.buildSigned(BOB_KEYPAIR)
.let { query -> client.sendQuery(query) }
assertEquals(2, permissionsAfter.size)
}

@Test
@WithIroha([NewAccountWithMetadata::class])
@Feature("Accounts")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package jp.co.soramitsu.iroha2.testengine

import jp.co.soramitsu.iroha2.ACCOUNT_ID_DELIMITER
import jp.co.soramitsu.iroha2.Genesis
import jp.co.soramitsu.iroha2.Permissions
import jp.co.soramitsu.iroha2.asAccountId
Expand All @@ -15,6 +16,7 @@ import jp.co.soramitsu.iroha2.generated.AssetDefinitionId
import jp.co.soramitsu.iroha2.generated.AssetId
import jp.co.soramitsu.iroha2.generated.AssetValueType
import jp.co.soramitsu.iroha2.generated.DomainId
import jp.co.soramitsu.iroha2.generated.IdBox
import jp.co.soramitsu.iroha2.generated.InstructionExpr
import jp.co.soramitsu.iroha2.generated.Metadata
import jp.co.soramitsu.iroha2.generated.PermissionToken
Expand All @@ -26,6 +28,9 @@ import jp.co.soramitsu.iroha2.toIrohaPublicKey
import jp.co.soramitsu.iroha2.transaction.Instructions
import org.apache.commons.lang3.RandomStringUtils.randomAlphabetic
import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils
import java.math.BigDecimal
import java.math.BigInteger
import kotlin.random.Random.Default.nextDouble

/**
* Create a default genesis where there is just one domain with only Alice and Bob in it
Expand All @@ -42,6 +47,21 @@ open class AliceCanUpgradeExecutor : Genesis(
),
)

open class WithDomainTransferredToBob : Genesis(
rawGenesisBlock(
Instructions.registerDomain(DOMAIN_ID),
Instructions.transferDomainOwnership(
"$GENESIS$ACCOUNT_ID_DELIMITER$GENESIS".asAccountId(),
IdBox.DomainId(DOMAIN_ID),
BOB_ACCOUNT_ID,
),
),
) {
companion object {
val DOMAIN_ID = randomAlphabetic(10).asDomainId()
}
}

open class AliceCanUnregisterAnyPeer : Genesis(
rawGenesisBlock(
Instructions.grantPermissionToken(
Expand Down Expand Up @@ -369,8 +389,17 @@ open class FatGenesis : Genesis(
Instructions.grantRole(ROLE_ID, ALICE_ACCOUNT_ID),
Instructions.mintAsset(AssetId(DEFAULT_ASSET_DEFINITION_ID, BOB_ACCOUNT_ID), 100),
Instructions.burnAsset(AssetId(DEFAULT_ASSET_DEFINITION_ID, BOB_ACCOUNT_ID), 100),
Instructions.setKeyValue(ASSET_ID, randomAlphabetic(10).asName(), 100.asValue()),
Instructions.setKeyValue(ASSET_ID, randomAlphabetic(10).asName(), Int.MAX_VALUE.asValue()),
Instructions.setKeyValue(ASSET_ID, randomAlphabetic(10).asName(), (Int.MAX_VALUE * 10L).asValue()),
Instructions.setKeyValue(ASSET_ID, randomAlphabetic(10).asName(), nextDouble().asValue()),
Instructions.setKeyValue(ASSET_ID, randomAlphabetic(10).asName(), BigDecimal(nextDouble()).asValue()),
Instructions.setKeyValue(
ASSET_ID,
randomAlphabetic(10).asName(),
(BigInteger.valueOf(Long.MAX_VALUE) * BigInteger.valueOf(2)).asValue(),
),
Instructions.setKeyValue(ASSET_ID, randomAlphabetic(10).asName(), randomAlphabetic(10).asValue()),
Instructions.setKeyValue(DEFAULT_DOMAIN_ID, randomAlphabetic(10).asName(), randomAlphabetic(10).asValue()),
),
) {
companion object {
Expand Down
Binary file modified modules/test-tools/src/main/resources/executor.wasm
100755 → 100644
Binary file not shown.
Loading

0 comments on commit 4d74923

Please sign in to comment.