diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 456ee91e..142ffe28 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,57 +1,57 @@ -name: Release -on: - push: - branches: - - main - -jobs: - build: - if: "!contains(github.event.commits[0].message, '[skip ci]')" - strategy: - matrix: - include: - - os: macos-latest - gradle_args: assemble publishIosX64PublicationToSonatypeRepository - - os: macos-latest - gradle_args: assemble publishIosArm64PublicationToSonatypeRepository - - os: macos-latest - gradle_args: assemble publishIosSimulatorArm64PublicationToSonatypeRepository - - os: macos-latest - gradle_args: assemble publishTvosX64PublicationToSonatypeRepository - - os: macos-latest - gradle_args: assemble publishTvosArm64PublicationToSonatypeRepository - - os: macos-latest - gradle_args: assemble publishTvosSimulatorArm64PublicationToSonatypeRepository - - os: macos-latest - gradle_args: assemble publishWatchosArm32PublicationToSonatypeRepository - - os: macos-latest - gradle_args: assemble publishWatchosArm64PublicationToSonatypeRepository - - os: macos-latest - gradle_args: assemble publishWatchosX64PublicationToSonatypeRepository - - os: macos-latest - gradle_args: assemble publishWatchosSimulatorArm64PublicationToSonatypeRepository - - os: macos-latest - gradle_args: assemble publishMacosX64PublicationToSonatypeRepository - - os: macos-latest - gradle_args: assemble publishMacosArm64PublicationToSonatypeRepository - - os: ubuntu-latest - gradle_args: assemble publishKotlinMultiplatformPublicationToSonatypeRepository publishJvmPublicationToSonatypeRepository publishLinuxX64PublicationToSonatypeRepository publishLinuxArm64PublicationToSonatypeRepository publishMingwX64PublicationToSonatypeRepository - - runs-on: ${{ matrix.os }} - steps: - - name: Checkout project sources - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 - with: - distribution: liberica - java-version: 8 - - name: Build using gradle - uses: gradle/gradle-build-action@v2 - with: - arguments: ${{ matrix.gradle_args }} - env: - SIGNING_SECRET_KEY: ${{ secrets.SIGNING_SECRET_KEY }} - SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} - OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} - OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +#name: Release +#on: +# push: +# branches: +# - main +# +#jobs: +# build: +# if: "!contains(github.event.commits[0].message, '[skip ci]')" +# strategy: +# matrix: +# include: +# - os: macos-latest +# gradle_args: assemble publishIosX64PublicationToSonatypeRepository +# - os: macos-latest +# gradle_args: assemble publishIosArm64PublicationToSonatypeRepository +# - os: macos-latest +# gradle_args: assemble publishIosSimulatorArm64PublicationToSonatypeRepository +# - os: macos-latest +# gradle_args: assemble publishTvosX64PublicationToSonatypeRepository +# - os: macos-latest +# gradle_args: assemble publishTvosArm64PublicationToSonatypeRepository +# - os: macos-latest +# gradle_args: assemble publishTvosSimulatorArm64PublicationToSonatypeRepository +# - os: macos-latest +# gradle_args: assemble publishWatchosArm32PublicationToSonatypeRepository +# - os: macos-latest +# gradle_args: assemble publishWatchosArm64PublicationToSonatypeRepository +# - os: macos-latest +# gradle_args: assemble publishWatchosX64PublicationToSonatypeRepository +# - os: macos-latest +# gradle_args: assemble publishWatchosSimulatorArm64PublicationToSonatypeRepository +# - os: macos-latest +# gradle_args: assemble publishMacosX64PublicationToSonatypeRepository +# - os: macos-latest +# gradle_args: assemble publishMacosArm64PublicationToSonatypeRepository +# - os: ubuntu-latest +# gradle_args: assemble publishKotlinMultiplatformPublicationToSonatypeRepository publishJvmPublicationToSonatypeRepository publishLinuxX64PublicationToSonatypeRepository publishLinuxArm64PublicationToSonatypeRepository publishMingwX64PublicationToSonatypeRepository +# +# runs-on: ${{ matrix.os }} +# steps: +# - name: Checkout project sources +# uses: actions/checkout@v3 +# - uses: actions/setup-java@v3 +# with: +# distribution: liberica +# java-version: 8 +# - name: Build using gradle +# uses: gradle/gradle-build-action@v2 +# with: +# arguments: ${{ matrix.gradle_args }} +# env: +# SIGNING_SECRET_KEY: ${{ secrets.SIGNING_SECRET_KEY }} +# SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} +# OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} +# OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index a31afdf8..53b2055c 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,60 @@ local.properties # Ignore Gradle build output directory build + +.jreleaser/config.tomlreplay_pid* +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf +.idea/**/aws.xml +.idea/**/contentModel.xml +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml +.idea/**/gradle.xml +.idea/**/libraries +cmake-build-*/ +.idea/**/mongoSettings.xml +*.iws +out/ +.idea_modules/ +atlassian-ide-plugin.xml +.idea/replstate.xml +.idea/sonarlint/ +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties +.idea/httpRequests +.idea/caches/build_file_checksums.ser +**/build/ +!src/**/build/ +gradle-app.setting +!gradle-wrapper.jar +!gradle-wrapper.properties +.gradletasknamecache +.project +.classpath +.DS_Store +.AppleDouble +.LSOverride +Icon +._* +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/README.md b/README.md index f7f8d55d..6f9b7608 100644 --- a/README.md +++ b/README.md @@ -10,20 +10,20 @@ ### Core components -* `org.ton:ton-kotlin-tvm:0.3.1` - TVM Primitives (Cells, BOC, etc.) -* `org.ton:ton-kotlin-crypto:0.3.1` - Crypto primitives for TON (ED25519, SHA, etc.) -* `org.ton:ton-kotlin-adnl:0.3.1` - ADNL (Abstract Datagram Network Layer) TON Network implementation +* `org.ton.kotlin:ton-kotlin-tvm:0.4.0` - TVM Primitives (Cells, BOC, etc.) +* `org.ton.kotlin:ton-kotlin-crypto:0.4.0` - Crypto primitives for TON (ED25519, SHA, etc.) +* `org.ton.kotlin:ton-kotlin-adnl:0.4.0` - ADNL (Abstract Datagram Network Layer) TON Network implementation ### API Interfaces -* `org.ton:ton-kotlin-contract:0.3.1` - Smart-contracts API interface -* `org.ton:ton-kotlin-liteclient:0.3.1` - Lite-client API implementation +* `org.ton.kotlin:ton-kotlin-contract:0.4.0` - Smart-contracts API interface +* `org.ton.kotlin:ton-kotlin-liteclient:0.4.0` - Lite-client API implementation ### TL-B (TL-Binary) -* `org.ton:ton-kotlin-tlb:0.3.1` - TON TL-B (TL-Binary) serialization/deserialization -* `org.ton:ton-kotlin-block-tlb:0.3.1` - Pre-generated TL-B schemas for TON Blockchain -* `org.ton:ton-kotlin-hashmap-tlb:0.3.1` - Pre-generated TL-B schemas for TON Hashmap (also known as Dictionary) +* `org.ton.kotlin:ton-kotlin-tlb:0.4.0` - TON TL-B (TL-Binary) serialization/deserialization +* `org.ton.kotlin:ton-kotlin-block-tlb:0.4.0` - Pre-generated TL-B schemas for TON Blockchain +* `org.ton.kotlin:ton-kotlin-hashmap-tlb:0.4.0` - Pre-generated TL-B schemas for TON Hashmap (also known as Dictionary) ## Documentation @@ -31,7 +31,7 @@ https://github.com/andreypfau/ton-kotlin/wiki/TON-Kotlin-documentation -[maven-central]: https://central.sonatype.com/artifact/org.ton/ton-kotlin-tvm/0.3.1 +[maven-central]: https://central.sonatype.com/artifact/org.ton/ton-kotlin-tvm/0.4.0 [license]: LICENSE diff --git a/bitstring/src/BitString.kt b/bitstring/src/BitString.kt index 31992f8b..26697927 100644 --- a/bitstring/src/BitString.kt +++ b/bitstring/src/BitString.kt @@ -14,7 +14,7 @@ public inline fun BitString(size: Int): BitString = BitString.of(size) public inline fun BitString(vararg bits: Boolean): BitString = BitString.of(*bits) public inline fun BitString(bits: Iterable): BitString = BitString.of(bits) public inline fun BitString(bits: Collection): BitString = BitString.of(bits) -public inline fun BitString(hex: String): BitString = BitString.of(hex) +public inline fun BitString(hex: String): BitString = BitString.parse(hex) public inline fun Iterable.toBitString(): BitString = BitString(this) public inline fun BooleanArray.toBitString(): BitString = BitString(*this) @@ -27,13 +27,14 @@ public interface BitString : Iterable, Comparable { public operator fun get(index: Int): Boolean public fun getOrNull(index: Int): Boolean? + public fun countLeadingBits(fromIndex: Int = 0, toIndex: Int = size, bit: Boolean): Int + public operator fun plus(bit: Boolean): BitString = plus(booleanArrayOf(bit)) public operator fun plus(bits: BooleanArray): BitString = plus(bits.asIterable()) - public operator fun plus(bits: Collection): BitString = plus(bits.asIterable()) @@ -61,8 +62,17 @@ public interface BitString : Iterable, Comparable { public fun commonSuffixWith(other: BitString): BitString = binary(toBinary().commonSuffixWith(other.toBinary())) - public fun slice(indices: IntRange): BitString = slice(indices.first, indices.last) + @Deprecated("use substring(indices) instead", ReplaceWith("substring(indices)")) + public fun slice(indices: IntRange): BitString = substring(indices.first, indices.last) + + @Deprecated("use substring(startIndex, endIndex) instead", ReplaceWith("substring(startIndex, endIndex)")) public fun slice(startIndex: Int, endIndex: Int = size): BitString = + substring(startIndex, endIndex) + + public fun substring(range: IntRange): BitString = + substring(range.first, range.last) + + public fun substring(startIndex: Int, endIndex: Int = size): BitString = binary(toBinary().substring(startIndex, endIndex)) public infix fun xor(other: BitString): BitString @@ -81,6 +91,18 @@ public interface BitString : Iterable, Comparable { public fun toHexString(): String + public fun copyInto( + destination: MutableBitString, + destinationOffset: Int = 0, + startIndex: Int = 0, + endIndex: Int = size + ) { + val length = endIndex - startIndex + for (i in 0 until length) { + destination[destinationOffset + i] = this[startIndex + i] + } + } + public companion object { @JvmStatic public fun empty(): BitString = EmptyBitString @@ -132,12 +154,16 @@ public interface BitString : Iterable, Comparable { } @JvmStatic - public fun of(hex: String): BitString { - if (hex.isEmpty()) return empty() + @Deprecated("use parse(hex) instead", replaceWith = ReplaceWith("parse(hex)")) + public fun of(hex: String): BitString = parse(hex) + + @JvmStatic + public fun parse(source: CharSequence): BitString { + if (source.isEmpty()) return empty() // True if bit string doesn't contain mod 4 number of bits - val incomplete = hex.isNotEmpty() && hex.last() == '_' + val incomplete = source.isNotEmpty() && source.last() == '_' - val bits = hex.asSequence() + val bits = source.asSequence() .takeWhile { it != '_' } // consume entire hexadecimal string, except for `_` .map { char -> char.digitToInt(16) diff --git a/bitstring/src/ByteBackedBitString.kt b/bitstring/src/ByteBackedBitString.kt index 6e470603..4b7b3ee1 100644 --- a/bitstring/src/ByteBackedBitString.kt +++ b/bitstring/src/ByteBackedBitString.kt @@ -22,6 +22,10 @@ public open class ByteBackedBitString protected constructor( override fun getOrNull(index: Int): Boolean? = if (index in 0..size) get(bytes, index) else null + override fun countLeadingBits(fromIndex: Int, toIndex: Int, bit: Boolean): Int { + return countLeadingBits(bytes, fromIndex, toIndex - fromIndex, bit) + } + override fun plus(bits: BitString): BitString = toMutableBitString().plus(bits) override fun plus(bytes: ByteArray): BitString = toMutableBitString().plus(bytes) override fun plus(bytes: ByteArray, bits: Int): BitString = toMutableBitString().plus(bytes, bits) @@ -41,7 +45,7 @@ public open class ByteBackedBitString protected constructor( if (augment && (size % 8 != 0)) { appendAugmentTag(bytes, size) } else { - bytes.copyOf() + bytes.copyOf((size + 7) ushr 3) } override fun toBooleanArray(): BooleanArray = toList().toBooleanArray() @@ -84,6 +88,13 @@ public open class ByteBackedBitString protected constructor( } } + override fun copyInto(destination: MutableBitString, destinationOffset: Int, startIndex: Int, endIndex: Int) { + if (destination !is ByteBackedBitString) { + return super.copyInto(destination, destinationOffset, startIndex, endIndex) + } + bitsCopy(destination.bytes, destinationOffset, bytes, startIndex, endIndex - startIndex) + } + override fun toString(): String = "x{${toHexString()}}" override fun toHexString(): String { @@ -218,3 +229,117 @@ private fun appendAugmentTag(data: ByteArray, bits: Int): ByteArray { return newData } } + +internal fun bitsCopy(dest: ByteArray, toIndex: Int, src: ByteArray, fromIndex: Int, bitCount: Int) { + if (bitCount <= 0) return + + var srcOffset = fromIndex shr 3 + var destOffset = toIndex shr 3 + val fromOffset = fromIndex and 7 + val toOffset = toIndex and 7 + + var remainingBits = bitCount + val bitCountTotal = bitCount + fromOffset + + if (fromOffset == toOffset) { + if (bitCountTotal < 8) { + val mask = ((-0x100 ushr bitCountTotal) and (0xff ushr toOffset)) + dest[destOffset] = ((dest[destOffset].toInt() and mask.inv()) or (src[srcOffset].toInt() and mask)).toByte() + return + } + + val bytesToCopy = bitCountTotal shr 3 + if (toOffset == 0) { + src.copyInto(dest, destOffset, srcOffset, srcOffset + bytesToCopy) + } else { + val mask = (0xff ushr toOffset) + dest[destOffset] = ((dest[destOffset].toInt() and mask.inv()) or (src[srcOffset].toInt() and mask)).toByte() + src.copyInto(dest, destOffset + 1, srcOffset + 1, srcOffset + bytesToCopy) + } + + if (bitCountTotal and 7 != 0) { + val mask = (-0x100 ushr (bitCountTotal and 7)) + dest[destOffset + bytesToCopy] = + ((dest[destOffset + bytesToCopy].toInt() and mask.inv()) or (src[srcOffset + bytesToCopy].toInt() and mask)).toByte() + } + } else { + var bitsInAcc = toOffset + var accumulator = if (bitsInAcc != 0) dest[destOffset].toLong() ushr (8 - bitsInAcc) else 0L + + if (bitCountTotal < 8) { + accumulator = accumulator shl remainingBits + accumulator = + accumulator or ((src[srcOffset].toLong() and (0xffL ushr fromOffset)) ushr (8 - bitCountTotal)) + bitsInAcc += remainingBits + } else { + val leadingBits = 8 - fromOffset + accumulator = (accumulator shl leadingBits) + accumulator = accumulator or (src[srcOffset++].toLong() and (0xffL ushr fromOffset)) + bitsInAcc += leadingBits + remainingBits -= leadingBits + + while (remainingBits >= 8) { + accumulator = accumulator shl 8 + accumulator = accumulator or (src[srcOffset++].toLong() and 0xffL) + dest[destOffset++] = (accumulator ushr bitsInAcc).toByte() + remainingBits -= 8 + } + + if (remainingBits > 0) { + accumulator = + (accumulator shl remainingBits) or ((src[srcOffset].toLong() and 0xff) ushr (8 - remainingBits)) + bitsInAcc += remainingBits + } + } + + while (bitsInAcc >= 8) { + bitsInAcc -= 8 + dest[destOffset++] = (accumulator ushr bitsInAcc).toByte() + } + + if (bitsInAcc > 0) { + dest[destOffset] = + ((dest[destOffset].toInt() and (0xff ushr bitsInAcc)) or (accumulator.toInt() shl (8 - bitsInAcc))).toByte() + } + } +} + +internal fun countLeadingBits( + array: ByteArray, + offset: Int, + bitCount: Int, + bit: Boolean +): Int { + if (bitCount == 0) return 0 + + val xorVal = if (bit) -1 else 0 + var index = offset ushr 3 + val bitOffset = offset and 7 + var reminder = bitCount + + if (bitOffset != 0) { + val v = ((array[index++].toInt() and 0xFF) xor xorVal) shl (24 + bitOffset) + val c = v.countLeadingZeroBits() + val remainingBits = 8 - bitOffset + if (c < remainingBits || bitCount <= remainingBits) { + return min(c, bitCount) + } + reminder -= remainingBits + } + + while (reminder >= 8) { + val v = ((array[index++].toInt() xor xorVal) and 0xFF) shl 24 + if (v != 0) { + return bitCount - reminder + v.countLeadingZeroBits() + } + reminder -= 8 + } + + if (reminder > 0) { + val v = (((array[index].toInt() xor xorVal) and 0xFF) shl 24).countLeadingZeroBits() + if (v < reminder) { + return bitCount - reminder + v + } + } + return bitCount +} \ No newline at end of file diff --git a/bitstring/src/ByteBackedMutableBitString.kt b/bitstring/src/ByteBackedMutableBitString.kt index 5e55e733..7c830db5 100644 --- a/bitstring/src/ByteBackedMutableBitString.kt +++ b/bitstring/src/ByteBackedMutableBitString.kt @@ -9,6 +9,8 @@ public open class ByteBackedMutableBitString( override var bytes: ByteArray, override var size: Int ) : ByteBackedBitString(size, bytes), MutableBitString { + public constructor(size: Int) : this(ByteArray((size + 7) ushr 3), size) + override operator fun set(index: Int, bit: Int) { set(index, bit != 0) } diff --git a/bitstring/src/EmptyBitString.kt b/bitstring/src/EmptyBitString.kt index 72e1628e..6c993e1c 100644 --- a/bitstring/src/EmptyBitString.kt +++ b/bitstring/src/EmptyBitString.kt @@ -7,6 +7,8 @@ internal object EmptyBitString : BitString { override fun getOrNull(index: Int): Boolean? = null + override fun countLeadingBits(fromIndex: Int, toIndex: Int, bit: Boolean): Int = 0 + override fun plus(bits: BooleanArray): BitString = BitString(*bits) override fun plus(bits: Iterable): BitString = BitString(bits) @@ -24,7 +26,7 @@ internal object EmptyBitString : BitString { throw IndexOutOfBoundsException(indices.toString()) } - override fun slice(startIndex: Int, endIndex: Int): BitString { + override fun substring(startIndex: Int, endIndex: Int): BitString { if (startIndex == 0 && endIndex == 0) return this throw IndexOutOfBoundsException((startIndex..endIndex).toString()) } diff --git a/block-tlb/src/AccStatusChange.kt b/block-tlb/src/AccStatusChange.kt index 4038396b..bce2fbe9 100644 --- a/block-tlb/src/AccStatusChange.kt +++ b/block-tlb/src/AccStatusChange.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.tlb.TlbCodec @@ -9,7 +8,7 @@ import org.ton.tlb.TlbCombinator import org.ton.tlb.TlbConstructor import org.ton.tlb.TlbStorer -@Serializable + public enum class AccStatusChange { @SerialName("acst_unchanged") UNCHANGED { diff --git a/block-tlb/src/Account.kt b/block-tlb/src/Account.kt index 84b6c8f0..9114e5ff 100644 --- a/block-tlb/src/Account.kt +++ b/block-tlb/src/Account.kt @@ -1,21 +1,86 @@ -@file:Suppress("OPT_IN_USAGE") - package org.ton.block -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonClassDiscriminator -import org.ton.tlb.TlbCombinator -import org.ton.tlb.TlbObject -import org.ton.tlb.providers.TlbCombinatorProvider +import org.ton.cell.CellBuilder +import org.ton.cell.CellSlice +import org.ton.cell.invoke +import org.ton.tlb.* +import org.ton.tlb.TlbConstructor + +/** + * Existing account data. + */ +public data class Account( + /** + * Account address. + */ + val address: MsgAddressInt, + + /** + * Storage statistics. + */ + val storageStat: StorageInfo, + + /** + * Logical time after the last transaction execution. + */ + val lastTransLt: Long, + + /** + * Account balance for all currencies. + */ + val balance: CurrencyCollection, + + /** + * Account state. + */ + val state: AccountState +) { + public companion object : TlbCodec by AccountInfoTlbConstructor.asNullable() + + @Deprecated("Use fields lastTransLt, balance, state instead") + val storage: AccountStorage // storage : AccountStorage + get() = AccountStorage(lastTransLt.toULong(), balance, state) -@JsonClassDiscriminator("@type") -@Serializable -public sealed interface Account : TlbObject { - public companion object : TlbCombinatorProvider by AccountTlbCombinator + @Deprecated("Use address instead", ReplaceWith("address")) + val addr: MsgAddressInt + get() = address + + val isActive: Boolean get() = storage.state is AccountActive + val isFrozen: Boolean get() = storage.state is AccountFrozen + val isUninit: Boolean get() = storage.state is AccountUninit } -private object AccountTlbCombinator : TlbCombinator( - Account::class, - AccountNone::class to AccountNone, - AccountInfo::class to AccountInfo -) +public val Account?.balance: CurrencyCollection + get() = this?.balance ?: CurrencyCollection.ZERO + +public val Account?.accountLastTransLt: Long + get() = this?.lastTransLt ?: 0 + +public val Account?.status: AccountStatus + get() = this?.state?.status ?: AccountStatus.NONEXIST + +private object AccountInfoTlbConstructor : TlbConstructor( + schema = "account\$1 addr:MsgAddressInt storage_stat:StorageInfo storage:AccountStorage = Account;" +) { + override fun storeTlb( + cellBuilder: CellBuilder, + value: Account + ) = cellBuilder { + storeTlb(MsgAddressInt, value.addr) + storeTlb(StorageInfo, value.storageStat) + storeULong(value.lastTransLt.toULong()) + storeTlb(CurrencyCollection, value.balance) + storeTlb(AccountState, value.state) + } + + override fun loadTlb( + cellSlice: CellSlice + ): Account = cellSlice { + val addr = loadTlb(MsgAddressInt) + val storageStat = loadTlb(StorageInfo) + val lastTransLt = loadULong().toLong() + val balance = loadTlb(CurrencyCollection) + val state = loadTlb(AccountState) + Account(addr, storageStat, lastTransLt, balance, state) + } +} diff --git a/block-tlb/src/AccountActive.kt b/block-tlb/src/AccountActive.kt index 4b3f5ce1..7d6d8429 100644 --- a/block-tlb/src/AccountActive.kt +++ b/block-tlb/src/AccountActive.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -14,12 +13,14 @@ import kotlin.jvm.JvmInline import kotlin.jvm.JvmName @JvmInline -@Serializable + @SerialName("account_active") public value class AccountActive( @get:JvmName("value") public val value: StateInit ) : AccountState { + override val status: AccountStatus get() = AccountStatus.ACTIVE + override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter { return printer.type("account_active") { value.print(printer) diff --git a/block-tlb/src/AccountBlock.kt b/block-tlb/src/AccountBlock.kt index 3378b041..b98e845b 100644 --- a/block-tlb/src/AccountBlock.kt +++ b/block-tlb/src/AccountBlock.kt @@ -1,16 +1,16 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.hashmap.HashmapAug import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbCombinatorProvider -@Serializable + @SerialName("acc_trans") public data class AccountBlock( @SerialName("account_addr") val accountAddr: BitString, diff --git a/block-tlb/src/AccountFrozen.kt b/block-tlb/src/AccountFrozen.kt index e3debae9..63dcecc6 100644 --- a/block-tlb/src/AccountFrozen.kt +++ b/block-tlb/src/AccountFrozen.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -11,7 +10,7 @@ import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider import kotlin.jvm.JvmName -@Serializable + @SerialName("account_frozen") public data class AccountFrozen( @SerialName("state_hash") @@ -22,6 +21,8 @@ public data class AccountFrozen( require(stateHash.size == 256) { "stateHash must be 256 bits long" } } + override val status: AccountStatus get() = AccountStatus.FROZEN + override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer.type("account_frozen") { printer.field("state_hash", stateHash) } diff --git a/block-tlb/src/AccountInfo.kt b/block-tlb/src/AccountInfo.kt deleted file mode 100644 index 11ae179e..00000000 --- a/block-tlb/src/AccountInfo.kt +++ /dev/null @@ -1,71 +0,0 @@ -package org.ton.block - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice -import org.ton.cell.invoke -import org.ton.tlb.TlbConstructor -import org.ton.tlb.TlbPrettyPrinter -import org.ton.tlb.loadTlb -import org.ton.tlb.providers.TlbConstructorProvider -import org.ton.tlb.storeTlb -import kotlin.jvm.JvmName -import kotlin.jvm.JvmStatic - -@Serializable -@SerialName("account") -public data class AccountInfo( - @SerialName("addr") - @get:JvmName("addr") - val addr: MsgAddressInt, // addr : MsgAddressInt - - @SerialName("storage_stat") - @get:JvmName("storageStat") - val storageStat: StorageInfo, // storage_stat : StorageInfo - - @SerialName("storage") - @get:JvmName("storage") - val storage: AccountStorage // storage : AccountStorage -) : Account { - public companion object : TlbConstructorProvider by AccountInfoTlbConstructor { - @JvmStatic - override fun tlbConstructor(): TlbConstructor = AccountInfoTlbConstructor - } - - val isActive: Boolean get() = storage.state is AccountActive - val isFrozen: Boolean get() = storage.state is AccountFrozen - val isUninit: Boolean get() = storage.state is AccountUninit - - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { - type("account") { - field("addr", addr) - field("storage_stat", storageStat) - field("storage", storage) - } - } - - override fun toString(): String = print().toString() -} - -private object AccountInfoTlbConstructor : TlbConstructor( - schema = "account\$1 addr:MsgAddressInt storage_stat:StorageInfo storage:AccountStorage = Account;" -) { - override fun storeTlb( - cellBuilder: CellBuilder, - value: AccountInfo - ) = cellBuilder { - storeTlb(MsgAddressInt, value.addr) - storeTlb(StorageInfo, value.storageStat) - storeTlb(AccountStorage, value.storage) - } - - override fun loadTlb( - cellSlice: CellSlice - ): AccountInfo = cellSlice { - val addr = loadTlb(MsgAddressInt) - val storageStat = loadTlb(StorageInfo) - val storage = loadTlb(AccountStorage) - AccountInfo(addr, storageStat, storage) - } -} diff --git a/block-tlb/src/AccountNone.kt b/block-tlb/src/AccountNone.kt deleted file mode 100644 index 85c507d7..00000000 --- a/block-tlb/src/AccountNone.kt +++ /dev/null @@ -1,28 +0,0 @@ -package org.ton.block - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice -import org.ton.tlb.TlbConstructor -import org.ton.tlb.TlbPrettyPrinter -import org.ton.tlb.providers.TlbConstructorProvider - -@Serializable -@SerialName("account_none") -public object AccountNone : Account, TlbConstructorProvider by AccountNoneTlbConstructor { - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer.type("account_none") - - override fun toString(): String = print().toString() -} - -private object AccountNoneTlbConstructor : TlbConstructor( - schema = "account_none\$0 = Account;" -) { - override fun storeTlb(cellBuilder: CellBuilder, value: AccountNone) { - } - - override fun loadTlb(cellSlice: CellSlice): AccountNone { - return AccountNone - } -} diff --git a/block-tlb/src/AccountState.kt b/block-tlb/src/AccountState.kt index 2b4832eb..84d65c0c 100644 --- a/block-tlb/src/AccountState.kt +++ b/block-tlb/src/AccountState.kt @@ -2,15 +2,19 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.tlb.TlbCombinator import org.ton.tlb.TlbObject import org.ton.tlb.providers.TlbCombinatorProvider -@Serializable + @JsonClassDiscriminator("@type") public sealed interface AccountState : TlbObject { + /** + * Account status. + */ + public val status: AccountStatus + public companion object : TlbCombinatorProvider by AccountStateTlbCombinator } diff --git a/block-tlb/src/AccountStatus.kt b/block-tlb/src/AccountStatus.kt index 0d2cd8b8..5622c253 100644 --- a/block-tlb/src/AccountStatus.kt +++ b/block-tlb/src/AccountStatus.kt @@ -1,14 +1,13 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.tlb.TlbCombinator import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbCombinatorProvider -@Serializable + public enum class AccountStatus { @SerialName("acc_state_uninit") UNINIT { diff --git a/block-tlb/src/AccountStorage.kt b/block-tlb/src/AccountStorage.kt index 6e8ff281..f4c04d8b 100644 --- a/block-tlb/src/AccountStorage.kt +++ b/block-tlb/src/AccountStorage.kt @@ -1,16 +1,17 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider import kotlin.jvm.JvmName @SerialName("account_storage") -@Serializable + +@Deprecated("Use fields from Account instead") public data class AccountStorage( @SerialName("last_trans_lt") @get:JvmName("lastTransLt") diff --git a/block-tlb/src/AccountUninit.kt b/block-tlb/src/AccountUninit.kt index 7d41b15b..577ed04a 100644 --- a/block-tlb/src/AccountUninit.kt +++ b/block-tlb/src/AccountUninit.kt @@ -1,16 +1,17 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.tlb.TlbConstructor import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("account_uninit") public object AccountUninit : AccountState, TlbConstructorProvider by AccountUninitTlbConstructor { + override val status: AccountStatus get() = AccountStatus.UNINIT + override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter { return printer.type("account_uninit") } diff --git a/block-tlb/src/ActionChangeLibrary.kt b/block-tlb/src/ActionChangeLibrary.kt index 17e7f474..d5bd10d6 100644 --- a/block-tlb/src/ActionChangeLibrary.kt +++ b/block-tlb/src/ActionChangeLibrary.kt @@ -1,9 +1,8 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -@Serializable + @SerialName("action_change_library") public data class ActionChangeLibrary( val mode: Int, diff --git a/block-tlb/src/TrActionPhase.kt b/block-tlb/src/ActionPhase.kt similarity index 92% rename from block-tlb/src/TrActionPhase.kt rename to block-tlb/src/ActionPhase.kt index 735c03f2..02b114a4 100644 --- a/block-tlb/src/TrActionPhase.kt +++ b/block-tlb/src/ActionPhase.kt @@ -3,7 +3,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers import org.ton.bitstring.BitString import org.ton.cell.CellBuilder @@ -11,12 +10,13 @@ import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.crypto.HexByteArraySerializer import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.constructor.IntTlbConstructor import org.ton.tlb.providers.TlbConstructorProvider @SerialName("tr_phase_action") -@Serializable -public data class TrActionPhase( + +public data class ActionPhase( val success: Boolean, val valid: Boolean, @SerialName("no_funds") val noFunds: Boolean, @@ -57,10 +57,10 @@ public data class TrActionPhase( override fun toString(): String = print().toString() - public companion object : TlbConstructorProvider by TrActionPhaseTlbConstructor + public companion object : TlbConstructorProvider by TrActionPhaseTlbConstructor } -private object TrActionPhaseTlbConstructor : TlbConstructor( +private object TrActionPhaseTlbConstructor : TlbConstructor( schema = "tr_phase_action\$_ success:Bool valid:Bool no_funds:Bool " + "status_change:AccStatusChange " + "total_fwd_fees:(Maybe Coins) total_action_fees:(Maybe Coins) " + @@ -74,7 +74,7 @@ private object TrActionPhaseTlbConstructor : TlbConstructor( override fun storeTlb( cellBuilder: CellBuilder, - value: TrActionPhase + value: ActionPhase ) = cellBuilder { storeBit(value.success) storeBit(value.valid) @@ -94,7 +94,7 @@ private object TrActionPhaseTlbConstructor : TlbConstructor( override fun loadTlb( cellSlice: CellSlice - ): TrActionPhase = cellSlice { + ): ActionPhase = cellSlice { val success = loadBit() val valid = loadBit() val noFunds = loadBit() @@ -109,7 +109,7 @@ private object TrActionPhaseTlbConstructor : TlbConstructor( val msgCreated = loadUInt(16).toInt() val actionListHash = loadBits(256) val totMsgSize = loadTlb(StorageUsedShort) - TrActionPhase( + ActionPhase( success, valid, noFunds, diff --git a/block-tlb/src/ActionReserveCurrency.kt b/block-tlb/src/ActionReserveCurrency.kt index f082bf79..6257d652 100644 --- a/block-tlb/src/ActionReserveCurrency.kt +++ b/block-tlb/src/ActionReserveCurrency.kt @@ -1,9 +1,8 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -@Serializable + @SerialName("action_reserve_currency") public data class ActionReserveCurrency( val mode: Int, diff --git a/block-tlb/src/ActionSendMsg.kt b/block-tlb/src/ActionSendMsg.kt index d7490811..52cf58d3 100644 --- a/block-tlb/src/ActionSendMsg.kt +++ b/block-tlb/src/ActionSendMsg.kt @@ -1,10 +1,9 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.Cell -@Serializable + @SerialName("action_send_msg") public data class ActionSendMsg( val mode: Int, diff --git a/block-tlb/src/ActionSetCode.kt b/block-tlb/src/ActionSetCode.kt index 8891b606..3ee23da3 100644 --- a/block-tlb/src/ActionSetCode.kt +++ b/block-tlb/src/ActionSetCode.kt @@ -1,10 +1,9 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.Cell -@Serializable + @SerialName("action_set_code") public data class ActionSetCode( val newCode: Cell diff --git a/block-tlb/src/AddrExtern.kt b/block-tlb/src/AddrExtern.kt index 1044f0b7..27c6dfa4 100644 --- a/block-tlb/src/AddrExtern.kt +++ b/block-tlb/src/AddrExtern.kt @@ -1,18 +1,18 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.bitstring.toBitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke +import org.ton.kotlin.cell.CellSize import org.ton.tlb.TlbConstructor import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider import kotlin.jvm.JvmName -@Serializable + @SerialName("addr_extern") public data class AddrExtern( @SerialName("len") @@ -29,6 +29,8 @@ public data class AddrExtern( public constructor(externalAddress: ByteArray) : this(externalAddress.toBitString()) public constructor(externalAddress: BitString) : this(externalAddress.size, externalAddress) + override val cellSize: CellSize get() = CellSize(9 + len, 0) + override fun toString(): String = print().toString() public override fun print(tlbPrettyPrinter: TlbPrettyPrinter): TlbPrettyPrinter = tlbPrettyPrinter { diff --git a/block-tlb/src/AddrNone.kt b/block-tlb/src/AddrNone.kt index 88ece5e9..9f5caa03 100644 --- a/block-tlb/src/AddrNone.kt +++ b/block-tlb/src/AddrNone.kt @@ -1,16 +1,18 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice +import org.ton.kotlin.cell.CellSize import org.ton.tlb.TlbConstructor import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider @SerialName("addr_none") -@Serializable + public object AddrNone : MsgAddressExt, TlbConstructorProvider by AddrNoneTlbConstructor { + override val cellSize: CellSize = CellSize(2, 0) + override fun toString(): String = print().toString() override fun print(tlbPrettyPrinter: TlbPrettyPrinter): TlbPrettyPrinter = tlbPrettyPrinter { diff --git a/block-tlb/src/AddrStd.kt b/block-tlb/src/AddrStd.kt index de22fbb5..2cf4b6df 100644 --- a/block-tlb/src/AddrStd.kt +++ b/block-tlb/src/AddrStd.kt @@ -1,14 +1,15 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.bitstring.toBitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.crypto.crc16 +import org.ton.kotlin.cell.CellSize import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import kotlin.experimental.and import kotlin.experimental.or import kotlin.io.encoding.Base64 @@ -17,7 +18,7 @@ import kotlin.jvm.JvmStatic public inline fun AddrStd(address: String): AddrStd = AddrStd.parse(address) -@Serializable + @SerialName("addr_std") public data class AddrStd( @get:JvmName("anycast") @@ -48,6 +49,11 @@ public data class AddrStd( require(address.size == 256) { "expected address.size == 256, actual: ${address.size}" } } + override val cellSize: CellSize + get() = anycast.value?.let { CELL_SIZE_MIN + it.cellSize } ?: CELL_SIZE_MIN + + override fun toAddrStd(): AddrStd = this + override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { type("addr_std") { field("anycast", anycast) @@ -66,6 +72,9 @@ public data class AddrStd( ): String = toString(this, userFriendly, urlSafe, testOnly, bounceable) public companion object : TlbCodec by AddrStdTlbConstructor { + public const val BITS_MIN: Int = 2 + 1 + 8 + 256 + public val CELL_SIZE_MIN: CellSize = CellSize(BITS_MIN, 0) + @JvmStatic public fun tlbCodec(): TlbConstructor = AddrStdTlbConstructor @@ -190,3 +199,5 @@ private object AddrStdTlbConstructor : TlbConstructor( AddrStd(anycast, workchainId, address) } } +//1000100000000001011010100101010000101101011101000110111001101010101000000011101111100011001100110010111010101010000111001111110110101001100010000010111010101001110111001010000000111011110110110001010100001000001000010001000110011100100001001111000101101100110110111100100000000111011100001111111111010011011110101011010110100100011010111101110000101001100110100011111001001110000010000110010111100100010001111001111010001101110101010011111000010101100110110101011111111011010010100011111011010100001000001101110000011101110110011100001010001111110111010101010010000110101110011100001100100110001100001100111000111110101101001001001000010000111100000101111001111001100000100100011010111100110011101000101011110101000110001100101010100110000110111001001010001000111010110100000010010000001010000000000000000000000000000000000000011 +//1000100000000001011010100101010000101101011101000110111001101010101000000011101111100011001100110010111010101010000111001111110110101001100010000010111010101001110111001010000000111011110110110001010100001000001000010001000110011100100001001111000101101100110110111100100000000101110110001111011100100010000111111001010101011110101110100110100110101000001101100010000100011100011111001001010001100100000010010001000100010101110000100000101111010010101011011001010010111011111000101100110010000101111001101101000111110100010001010011100110001010000010100010101010110110100000101110101000111011011001011100011010100001100100100000100101011000101100111110101110001101111011001000011100100101100110100110110110001110011100101000110000100010010011011111100101100100010000110001111010100000010000000000000000000000000000000000000000011 \ No newline at end of file diff --git a/block-tlb/src/AddrVar.kt b/block-tlb/src/AddrVar.kt index 703e236f..edfdd30b 100644 --- a/block-tlb/src/AddrVar.kt +++ b/block-tlb/src/AddrVar.kt @@ -1,16 +1,17 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.bitstring.toBitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke +import org.ton.kotlin.cell.CellSize import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import kotlin.jvm.JvmStatic -@Serializable + @SerialName("addr_var") public data class AddrVar( val anycast: Maybe, @@ -38,6 +39,13 @@ public data class AddrVar( address.toBitString() ) + override val cellSize: CellSize + get() = CellSize(2 + 1 + 9 + 32 + addrLen, 0).let { cellSize -> + anycast.value?.let { anycast -> anycast.cellSize + cellSize } ?: cellSize + } + + override fun toAddrStd(): AddrStd = AddrStd(workchainId, address) + override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { type("addr_var") { field("anycast", anycast) diff --git a/block-tlb/src/Anycast.kt b/block-tlb/src/Anycast.kt index 49eae7c0..02a420ed 100644 --- a/block-tlb/src/Anycast.kt +++ b/block-tlb/src/Anycast.kt @@ -1,22 +1,23 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke +import org.ton.kotlin.cell.CellSize +import org.ton.kotlin.cell.CellSizeable import org.ton.tlb.TlbConstructor import org.ton.tlb.TlbObject import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider @SerialName("anycast_info") -@Serializable + public data class Anycast( val depth: Int, @SerialName("rewrite_pfx") val rewritePfx: BitString -) : TlbObject { +) : TlbObject, CellSizeable { public constructor( rewritePfx: BitString ) : this(rewritePfx.size, rewritePfx) @@ -25,6 +26,8 @@ public data class Anycast( require(depth in 1..30) { "required: depth in 1..30, actual: $depth" } } + override val cellSize: CellSize get() = CellSize(5 + rewritePfx.size, 0) + override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { type("anycast_info") { field("depth", depth) @@ -34,6 +37,7 @@ public data class Anycast( override fun toString(): String = print().toString() + public companion object : TlbConstructorProvider by AnycastTlbConstructor } diff --git a/block-tlb/src/BinTree.kt b/block-tlb/src/BinTree.kt index d582242d..4ab3b81d 100644 --- a/block-tlb/src/BinTree.kt +++ b/block-tlb/src/BinTree.kt @@ -2,14 +2,13 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.tlb.TlbCodec import org.ton.tlb.TlbCombinator import org.ton.tlb.TlbObject import kotlin.jvm.JvmStatic -@Serializable + @JsonClassDiscriminator("@type") public sealed interface BinTree : Iterable, TlbObject { diff --git a/block-tlb/src/BinTreeFork.kt b/block-tlb/src/BinTreeFork.kt index bb9ae083..5241dd1b 100644 --- a/block-tlb/src/BinTreeFork.kt +++ b/block-tlb/src/BinTreeFork.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import kotlin.jvm.JvmStatic -@Serializable + @SerialName("bt_fork") public data class BinTreeFork( val left: CellRef>, diff --git a/block-tlb/src/BinTreeLeaf.kt b/block-tlb/src/BinTreeLeaf.kt index 61b2dce5..cbc031e4 100644 --- a/block-tlb/src/BinTreeLeaf.kt +++ b/block-tlb/src/BinTreeLeaf.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import kotlin.jvm.JvmStatic -@Serializable + @SerialName("bt_leaf") public data class BinTreeLeaf( val leaf: X diff --git a/block-tlb/src/BlkMasterInfo.kt b/block-tlb/src/BlkMasterInfo.kt index 37df0e03..bbe4bdd4 100644 --- a/block-tlb/src/BlkMasterInfo.kt +++ b/block-tlb/src/BlkMasterInfo.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor @SerialName("master_info") -@Serializable + public data class BlkMasterInfo( val master: ExtBlkRef // master : ExtBlkRef ) : TlbObject { diff --git a/block-tlb/src/BlkPrevInfo.kt b/block-tlb/src/BlkPrevInfo.kt index 7604605a..b7c3a5f4 100644 --- a/block-tlb/src/BlkPrevInfo.kt +++ b/block-tlb/src/BlkPrevInfo.kt @@ -2,14 +2,13 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.tlb.TlbCodec import org.ton.tlb.TlbObject import kotlin.jvm.JvmStatic @JsonClassDiscriminator("@type") -@Serializable + public sealed interface BlkPrevInfo : TlbObject { public companion object { @Suppress("UNCHECKED_CAST") diff --git a/block-tlb/src/Block.kt b/block-tlb/src/Block.kt index f78726f3..95615d90 100644 --- a/block-tlb/src/Block.kt +++ b/block-tlb/src/Block.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -9,7 +8,7 @@ import org.ton.tlb.* import org.ton.tlb.providers.TlbCombinatorProvider @SerialName("block") -@Serializable + public data class Block( @SerialName("global_id") val globalId: Int, // global_id:int32 diff --git a/block-tlb/src/BlockCreateStats.kt b/block-tlb/src/BlockCreateStats.kt index 28c03bc8..45e4323b 100644 --- a/block-tlb/src/BlockCreateStats.kt +++ b/block-tlb/src/BlockCreateStats.kt @@ -2,13 +2,12 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.tlb.TlbCombinator import org.ton.tlb.TlbObject import org.ton.tlb.providers.TlbCombinatorProvider -@Serializable + @JsonClassDiscriminator("@type") public sealed interface BlockCreateStats : TlbObject { public companion object : TlbCombinatorProvider by BlockCreateStatsTlbCombinator diff --git a/block-tlb/src/BlockCreateStatsExt.kt b/block-tlb/src/BlockCreateStatsExt.kt index 4b0f81eb..caa11b31 100644 --- a/block-tlb/src/BlockCreateStatsExt.kt +++ b/block-tlb/src/BlockCreateStatsExt.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -13,7 +12,7 @@ import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + @SerialName("block_create_stats_ext") public data class BlockCreateStatsExt( val counters: HashmapAugE diff --git a/block-tlb/src/BlockCreateStatsRegular.kt b/block-tlb/src/BlockCreateStatsRegular.kt index 56a91b23..dd46aa87 100644 --- a/block-tlb/src/BlockCreateStatsRegular.kt +++ b/block-tlb/src/BlockCreateStatsRegular.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -12,7 +11,7 @@ import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + @SerialName("block_create_stats") public data class BlockCreateStatsRegular( val counters: HashMapE diff --git a/block-tlb/src/BlockExtra.kt b/block-tlb/src/BlockExtra.kt index 1992bb7d..69c9a93b 100644 --- a/block-tlb/src/BlockExtra.kt +++ b/block-tlb/src/BlockExtra.kt @@ -1,16 +1,16 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.hashmap.HashmapAugE import org.ton.tlb.* +import org.ton.tlb.TlbConstructor @SerialName("block_extra") -@Serializable + public data class BlockExtra( @SerialName("in_msg_descr") val inMsgDescr: CellRef>, @SerialName("out_msg_descr") val outMsgDescr: CellRef>, diff --git a/block-tlb/src/BlockInfo.kt b/block-tlb/src/BlockInfo.kt index 408a447b..482f2d79 100644 --- a/block-tlb/src/BlockInfo.kt +++ b/block-tlb/src/BlockInfo.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor @SerialName("block_info") -@Serializable + public data class BlockInfo( val version: UInt, // version : uint32 @SerialName("not_master") val notMaster: Boolean, // not_master : ## 1 diff --git a/block-tlb/src/BouncePhase.kt b/block-tlb/src/BouncePhase.kt new file mode 100644 index 00000000..6e0e3162 --- /dev/null +++ b/block-tlb/src/BouncePhase.kt @@ -0,0 +1,102 @@ +package org.ton.block + +import org.ton.cell.CellBuilder +import org.ton.cell.CellSlice +import org.ton.tlb.TlbCodec +import org.ton.tlb.loadTlb +import org.ton.tlb.storeTlb + +/** + * Bounce phase info. + * + * At this phase, some funds are returned to the sender. + * + * @see [TransactionInfo] + */ +public sealed interface BouncePhase { + public val forwardFees: Coins + + /** + * Skipped bounce phase info. + */ + public data class NoFunds( + /** + * The total number of unique cells (bits / refs) of the bounced message. + */ + val msgSize: StorageUsedShort, + + /** + * Required amount of coins to send the bounced message. + */ + override val forwardFees: Coins + ) : BouncePhase + + /** + * Bounce phase was executed. + */ + public data class Executed( + /** + * The total number of unique cells (bits / refs) of the bounced message. + */ + val msgSize: StorageUsedShort = StorageUsedShort.ZERO, + + /** + * The part of fees for the validators. + */ + val forwardFeesCollected: Coins = Coins.ZERO, + + /** + * Message forwarding fee. + */ + override val forwardFees: Coins = Coins.ZERO, + ) : BouncePhase + + public companion object : TlbCodec by BouncePhaseCodec +} + +private object BouncePhaseCodec : TlbCodec { + private val ZERO = BouncePhase.Executed() + + override fun storeTlb(builder: CellBuilder, value: BouncePhase) { + when (value) { + is BouncePhase.Executed -> { // tr_phase_bounce_ok$1 + builder.storeBoolean(true) + builder.storeTlb(StorageUsedShort, value.msgSize) // msg_size:StorageUsed + builder.storeTlb(Coins, value.forwardFeesCollected) // msg_fees:Coins + builder.storeTlb(Coins, value.forwardFees) // fwd_fees:Coins + } + + is BouncePhase.NoFunds -> { // tr_phase_bounce_nofunds$01 + builder.storeUInt(0b01, 2) + builder.storeTlb(StorageUsedShort, value.msgSize) // msg_size:StorageUsed + builder.storeTlb(Coins, value.forwardFees) // req_fwd_fees:Coins + } + } + } + + override fun loadTlb(slice: CellSlice): BouncePhase { + when (val tag = slice.preloadUInt(2).toInt()) { + 0b00 -> { + slice.skipBits(2) + return ZERO + } + + 0b01 -> { // tr_phase_bounce_nofunds$01 + slice.skipBits(2) + val msgSize = slice.loadTlb(StorageUsedShort) + val forwardFees = slice.loadTlb(Coins) + return BouncePhase.NoFunds(msgSize, forwardFees) + } + + 0b10, 0b11 -> { // tr_phase_bounce_ok$1 + slice.skipBits(1) + val msgSize = slice.loadTlb(StorageUsedShort) + val forwardFees = slice.loadTlb(Coins) + return BouncePhase.Executed(msgSize, forwardFees) + } + + else -> throw IllegalArgumentException("Invalid bounce phase tag: ${tag.toString(2)}") + } + } + +} \ No newline at end of file diff --git a/block-tlb/src/Certificate.kt b/block-tlb/src/Certificate.kt index 652446ba..71a775be 100644 --- a/block-tlb/src/Certificate.kt +++ b/block-tlb/src/Certificate.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -10,7 +9,7 @@ import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + @SerialName("certificate") public data class Certificate( val temp_key: SigPubKey, diff --git a/block-tlb/src/CertificateEnv.kt b/block-tlb/src/CertificateEnv.kt index 2527329f..86cf2576 100644 --- a/block-tlb/src/CertificateEnv.kt +++ b/block-tlb/src/CertificateEnv.kt @@ -1,9 +1,8 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -@Serializable + @SerialName("certificate_env") public data class CertificateEnv( val certificate: Certificate diff --git a/block-tlb/src/ChainedSignature.kt b/block-tlb/src/ChainedSignature.kt index 3fa8245d..604f2a8e 100644 --- a/block-tlb/src/ChainedSignature.kt +++ b/block-tlb/src/ChainedSignature.kt @@ -1,14 +1,13 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.* import org.ton.tlb.TlbConstructor import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + @SerialName("chained_signature") public data class ChainedSignature( val signed_crt: SignedCertificate, diff --git a/block-tlb/src/Coins.kt b/block-tlb/src/Coins.kt index 235d6900..5ce2ac0e 100644 --- a/block-tlb/src/Coins.kt +++ b/block-tlb/src/Coins.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bigint.BigInt import org.ton.bigint.pow import org.ton.bigint.times @@ -10,13 +9,21 @@ import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider import kotlin.jvm.JvmName import kotlin.jvm.JvmStatic import kotlin.math.pow +/** + * Variable-length 120-bit integer. Used for native currencies. + * + * Stored as 4 bits of `len` (0..=15), followed by `len` bytes. + * + * @see [CurrencyCollection] + */ @SerialName("nanocoins") -@Serializable + public data class Coins( @get:JvmName("amount") val amount: VarUInteger = VarUInteger(0) @@ -28,7 +35,7 @@ public data class Coins( field("amount", amount) } - override fun toString(): String = toString(decimals = DECIMALS) + override fun toString(): String = amount.value.toString() public fun toString(decimals: Int): String = amount.value.toString().let { @@ -44,6 +51,8 @@ public data class Coins( public operator fun dec(): Coins = Coins(amount - VarUInteger(1, 1.toBigInt())) public companion object : TlbConstructorProvider by CoinsTlbConstructor { + public val ZERO: Coins = Coins(0) + private const val DECIMALS = 9 @JvmStatic @@ -54,6 +63,7 @@ public data class Coins( Coins(VarUInteger(coins.toBigInt() * 10.toBigInt().pow(decimals))) @JvmStatic + @Deprecated(message = "Double is very dangerous, scheduled to remove", level = DeprecationLevel.ERROR) public fun of(coins: Double, decimals: Int = DECIMALS): Coins = Coins( VarUInteger( diff --git a/block-tlb/src/CommonMsgInfo.kt b/block-tlb/src/CommonMsgInfo.kt index 6fc4a932..22ffc10f 100644 --- a/block-tlb/src/CommonMsgInfo.kt +++ b/block-tlb/src/CommonMsgInfo.kt @@ -2,7 +2,6 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.tlb.TlbCodec import org.ton.tlb.TlbCombinator @@ -10,7 +9,7 @@ import org.ton.tlb.TlbObject import kotlin.jvm.JvmStatic @JsonClassDiscriminator("@type") -@Serializable + public sealed interface CommonMsgInfo : TlbObject { public companion object : TlbCodec by CommonMsgInfoTlbCombinator { @JvmStatic @@ -24,3 +23,5 @@ private object CommonMsgInfoTlbCombinator : TlbCombinator( ExtInMsgInfo::class to ExtInMsgInfo, ExtOutMsgInfo::class to ExtOutMsgInfo ) + +public val CommonMsgInfo?.value: CurrencyCollection get() = (this as? IntMsgInfo)?.value ?: CurrencyCollection.ZERO diff --git a/block-tlb/src/CommonMsgInfoRelaxed.kt b/block-tlb/src/CommonMsgInfoRelaxed.kt index 5969cd53..fdbbb8aa 100644 --- a/block-tlb/src/CommonMsgInfoRelaxed.kt +++ b/block-tlb/src/CommonMsgInfoRelaxed.kt @@ -3,16 +3,16 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbCombinatorProvider @JsonClassDiscriminator("@type") -@Serializable + public sealed interface CommonMsgInfoRelaxed : TlbObject { @SerialName("int_msg_info") public data class IntMsgInfoRelaxed( @@ -21,7 +21,7 @@ public sealed interface CommonMsgInfoRelaxed : TlbObject { val bounced: Boolean = false, val src: MsgAddress = MsgAddressExt(), val dest: MsgAddressInt = AddrStd(), - val value: CurrencyCollection = CurrencyCollection(), + val value: CurrencyCollection = CurrencyCollection.ZERO, val ihrFee: Coins = Coins(), val fwdFee: Coins = Coins(), val createdLt: ULong = 0u, @@ -30,7 +30,7 @@ public sealed interface CommonMsgInfoRelaxed : TlbObject { public constructor(dest: MsgAddressInt, bounce: Boolean, value: Coins) : this( dest = dest, bounce = bounce, - value = CurrencyCollection(value, ExtraCurrencyCollection()) + value = CurrencyCollection(value, ExtraCurrencyCollection.EMPTY) ) public constructor(dest: MsgAddressInt, bounce: Boolean, value: CurrencyCollection) : this( diff --git a/block-tlb/src/TrComputePhase.kt b/block-tlb/src/ComputePhase.kt similarity index 54% rename from block-tlb/src/TrComputePhase.kt rename to block-tlb/src/ComputePhase.kt index cd1e3af4..54ae734f 100644 --- a/block-tlb/src/TrComputePhase.kt +++ b/block-tlb/src/ComputePhase.kt @@ -2,20 +2,19 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.tlb.TlbCombinator import org.ton.tlb.TlbObject import org.ton.tlb.providers.TlbCombinatorProvider -@Serializable + @JsonClassDiscriminator("@type") -public sealed interface TrComputePhase : TlbObject { - public companion object : TlbCombinatorProvider by TrComputePhaseTlbCombinator +public sealed interface ComputePhase : TlbObject { + public companion object : TlbCombinatorProvider by TrComputePhaseTlbCombinator } -private object TrComputePhaseTlbCombinator : TlbCombinator( - TrComputePhase::class, +private object TrComputePhaseTlbCombinator : TlbCombinator( + ComputePhase::class, TrPhaseComputeSkipped::class to TrPhaseComputeSkipped, TrPhaseComputeVm::class to TrPhaseComputeVm, ) diff --git a/block-tlb/src/ComputeSkipReason.kt b/block-tlb/src/ComputeSkipReason.kt index 5b614d15..c1e21713 100644 --- a/block-tlb/src/ComputeSkipReason.kt +++ b/block-tlb/src/ComputeSkipReason.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.tlb.TlbCodec @@ -10,7 +9,7 @@ import org.ton.tlb.TlbConstructor import org.ton.tlb.TlbStorer import kotlin.jvm.JvmStatic -@Serializable + public enum class ComputeSkipReason { @SerialName("cskip_no_state") NO_STATE { diff --git a/block-tlb/src/ConfigParams.kt b/block-tlb/src/ConfigParams.kt index a47d1490..2d1eff99 100644 --- a/block-tlb/src/ConfigParams.kt +++ b/block-tlb/src/ConfigParams.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.Cell import org.ton.cell.CellBuilder @@ -9,10 +8,11 @@ import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.hashmap.HmEdge import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.constructor.tlbCodec import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + public data class ConfigParams( @SerialName("config_addr") val configAddr: BitString, val config: CellRef> diff --git a/block-tlb/src/Counters.kt b/block-tlb/src/Counters.kt index 8bd277f6..b7e56bf8 100644 --- a/block-tlb/src/Counters.kt +++ b/block-tlb/src/Counters.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -10,7 +9,7 @@ import org.ton.tlb.TlbObject import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("counters") public data class Counters( @SerialName("last_updated") val lastUpdated: UInt, // last_updated : uint32 diff --git a/block-tlb/src/CreatorStats.kt b/block-tlb/src/CreatorStats.kt index 3c3a6fc8..fc517654 100644 --- a/block-tlb/src/CreatorStats.kt +++ b/block-tlb/src/CreatorStats.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("creator_info") public data class CreatorStats( @SerialName("mc_blocks") val mcBlocks: Counters, diff --git a/block-tlb/src/TrCreditPhase.kt b/block-tlb/src/CreditPhase.kt similarity index 73% rename from block-tlb/src/TrCreditPhase.kt rename to block-tlb/src/CreditPhase.kt index 9f8da580..d70f29e3 100644 --- a/block-tlb/src/TrCreditPhase.kt +++ b/block-tlb/src/CreditPhase.kt @@ -1,16 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@SerialName("tr_phase_credit") -@Serializable -public data class TrCreditPhase( +public data class CreditPhase( @SerialName("due_fees_collected") val dueFeesCollected: Maybe, val credit: CurrencyCollection ) : TlbObject { @@ -23,17 +21,17 @@ public data class TrCreditPhase( override fun toString(): String = print().toString() - public companion object : TlbConstructorProvider by TrCreditPhaseTlbConstructor + public companion object : TlbConstructorProvider by TrCreditPhaseTlbConstructor } -private object TrCreditPhaseTlbConstructor : TlbConstructor( +private object TrCreditPhaseTlbConstructor : TlbConstructor( schema = "tr_phase_credit\$_ due_fees_collected:(Maybe Coins) credit:CurrencyCollection = TrCreditPhase;" ) { val maybeCoins = Maybe.tlbCodec(Coins) override fun storeTlb( cellBuilder: CellBuilder, - value: TrCreditPhase + value: CreditPhase ) = cellBuilder { storeTlb(maybeCoins, value.dueFeesCollected) storeTlb(CurrencyCollection, value.credit) @@ -41,9 +39,9 @@ private object TrCreditPhaseTlbConstructor : TlbConstructor( override fun loadTlb( cellSlice: CellSlice - ): TrCreditPhase = cellSlice { + ): CreditPhase = cellSlice { val dueFeesCollected = loadTlb(maybeCoins) val credit = loadTlb(CurrencyCollection) - TrCreditPhase(dueFeesCollected, credit) + CreditPhase(dueFeesCollected, credit) } } diff --git a/block-tlb/src/CryptoSignature.kt b/block-tlb/src/CryptoSignature.kt index 339c42c6..27905c46 100644 --- a/block-tlb/src/CryptoSignature.kt +++ b/block-tlb/src/CryptoSignature.kt @@ -2,12 +2,11 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.tlb.TlbCombinator import org.ton.tlb.providers.TlbCombinatorProvider -@Serializable + @JsonClassDiscriminator("@type") public sealed interface CryptoSignature { public companion object : TlbCombinatorProvider by CryptoSignatureTlbCombinator diff --git a/block-tlb/src/CryptoSignaturePair.kt b/block-tlb/src/CryptoSignaturePair.kt index 6e4cfda3..97c45c5d 100644 --- a/block-tlb/src/CryptoSignaturePair.kt +++ b/block-tlb/src/CryptoSignaturePair.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -11,7 +10,7 @@ import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + @SerialName("sig_pair") public data class CryptoSignaturePair( val node_id_short: BitString, diff --git a/block-tlb/src/CryptoSignatureSimple.kt b/block-tlb/src/CryptoSignatureSimple.kt index 4eff3e6d..e41b3c3f 100644 --- a/block-tlb/src/CryptoSignatureSimple.kt +++ b/block-tlb/src/CryptoSignatureSimple.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -9,7 +8,7 @@ import org.ton.cell.invoke import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("ed25519_signature") public data class CryptoSignatureSimple( val r: BitString, diff --git a/block-tlb/src/CurrencyCollection.kt b/block-tlb/src/CurrencyCollection.kt index ad36d168..3727692e 100644 --- a/block-tlb/src/CurrencyCollection.kt +++ b/block-tlb/src/CurrencyCollection.kt @@ -1,50 +1,86 @@ package org.ton.block -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice -import org.ton.cell.invoke -import org.ton.tlb.* +import org.ton.kotlin.cell.CellContext +import org.ton.kotlin.currency.VarUInt248 +import org.ton.kotlin.dict.Dictionary +import org.ton.tlb.TlbConstructor +import org.ton.tlb.TlbObject +import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider -import kotlin.jvm.JvmName -@SerialName("currencies") -@Serializable +/** + * Amounts collection. + */ public data class CurrencyCollection( - @get:JvmName("coins") - val coins: Coins, // coins: Coins + /** + * Amount in native currency. + */ + val coins: Coins = Coins.ZERO, - @get:JvmName("other") - val other: ExtraCurrencyCollection // other: ExtraCurrencyCollection + /** + * Amounts in other currencies. + */ + val other: ExtraCurrencyCollection = ExtraCurrencyCollection.EMPTY ) : TlbObject { - public constructor() : this(Coins(), ExtraCurrencyCollection()) + public constructor() : this(Coins.ZERO, ExtraCurrencyCollection.EMPTY) + + public constructor(coins: Coins) : this(coins, ExtraCurrencyCollection.EMPTY) + + public constructor(coins: Coins, other: Map) : this(coins, ExtraCurrencyCollection(other)) + + public constructor(coins: Coins, other: Dictionary) : this(coins, ExtraCurrencyCollection(other)) + + public constructor(other: Map) : this(Coins.ZERO, ExtraCurrencyCollection(other)) + + public constructor(other: Dictionary) : this(Coins.ZERO, ExtraCurrencyCollection(other)) + + public operator fun get(id: Int): VarUInt248? = other[id] override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer.type("currencies") { field("coins", coins) field("other", other) } - override fun toString(): String = print().toString() + override fun toString(): String = + if (other.isEmpty()) { + coins.toString() + } else buildString { + append("(") + append(coins) + other.forEach { (key, value) -> + append("+") + append(value) + append(".$") + append(key) + } + append(")") + } - public companion object : TlbConstructorProvider by CurrencyCollectionTlbConstructor + public companion object : TlbConstructorProvider by CurrencyCollectionTlbConstructor { + public val ZERO: CurrencyCollection = CurrencyCollection(Coins.ZERO, ExtraCurrencyCollection.EMPTY) + } } private object CurrencyCollectionTlbConstructor : TlbConstructor( schema = "currencies\$_ coins:Coins other:ExtraCurrencyCollection = CurrencyCollection;" ) { override fun storeTlb( - cellBuilder: CellBuilder, value: CurrencyCollection - ) = cellBuilder { - storeTlb(Coins, value.coins) - storeTlb(ExtraCurrencyCollection, value.other) + builder: CellBuilder, + value: CurrencyCollection, + context: CellContext + ) { + Coins.storeTlb(builder, value.coins, context) + ExtraCurrencyCollection.storeTlb(builder, value.other, context) } override fun loadTlb( - cellSlice: CellSlice - ): CurrencyCollection = cellSlice { - val coins = loadTlb(Coins) - val other = loadTlb(ExtraCurrencyCollection) - CurrencyCollection(coins, other) + slice: CellSlice, + context: CellContext + ): CurrencyCollection { + val coins = Coins.loadTlb(slice, context) + val other = ExtraCurrencyCollection.loadTlb(slice, context) + return CurrencyCollection(coins, other) } } diff --git a/block-tlb/src/DepthBalanceInfo.kt b/block-tlb/src/DepthBalanceInfo.kt index ffdae3a1..8280b07c 100644 --- a/block-tlb/src/DepthBalanceInfo.kt +++ b/block-tlb/src/DepthBalanceInfo.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("depth_balance") public data class DepthBalanceInfo( @SerialName("split_depth") val splitDepth: Int, diff --git a/block-tlb/src/DnsAdnlAddress.kt b/block-tlb/src/DnsAdnlAddress.kt index 69b77245..84f0c9dc 100644 --- a/block-tlb/src/DnsAdnlAddress.kt +++ b/block-tlb/src/DnsAdnlAddress.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.tlb.loadTlb @@ -9,7 +8,7 @@ import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb @SerialName("dns_adnl_address") -@Serializable + public data class DnsAdnlAddress( val adnl_addr: BitString, val flags: BitString, diff --git a/block-tlb/src/DnsNextResolver.kt b/block-tlb/src/DnsNextResolver.kt index ef9d7d44..716cfaea 100644 --- a/block-tlb/src/DnsNextResolver.kt +++ b/block-tlb/src/DnsNextResolver.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.tlb.TlbConstructor @@ -10,7 +9,7 @@ import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb @SerialName("dns_next_resolver") -@Serializable + public data class DnsNextResolver( val resolver: MsgAddressInt ) : DnsRecord { diff --git a/block-tlb/src/DnsText.kt b/block-tlb/src/DnsText.kt index 46421ce5..cd785eee 100644 --- a/block-tlb/src/DnsText.kt +++ b/block-tlb/src/DnsText.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.tlb.TlbConstructor @@ -9,7 +8,7 @@ import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + public class DnsText( @SerialName("_") public val value: Text diff --git a/block-tlb/src/Either.kt b/block-tlb/src/Either.kt index c0b454d1..aff5e9d1 100644 --- a/block-tlb/src/Either.kt +++ b/block-tlb/src/Either.kt @@ -3,20 +3,20 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import kotlin.jvm.JvmStatic @Suppress("NOTHING_TO_INLINE") public inline fun Pair.toEither(): Either = Either.of(first, second) @JsonClassDiscriminator("@type") -@Serializable + public sealed interface Either : TlbObject { public val x: X? public val y: Y? @@ -24,7 +24,7 @@ public sealed interface Either : TlbObject { public fun toPair(): Pair = x to y @SerialName("left") - @Serializable + public class Left( public val value: X ) : Either { @@ -53,7 +53,7 @@ public sealed interface Either : TlbObject { } @SerialName("right") - @Serializable + public class Right( public val value: Y ) : Either { diff --git a/block-tlb/src/EnqueuedMsg.kt b/block-tlb/src/EnqueuedMsg.kt index 3e9f7f4c..3c6bc3f1 100644 --- a/block-tlb/src/EnqueuedMsg.kt +++ b/block-tlb/src/EnqueuedMsg.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + public data class EnqueuedMsg( @SerialName("enqueued_lt") val enqueuedLt: ULong, @SerialName("out_msg") val outMsg: CellRef diff --git a/block-tlb/src/ExtBlkRef.kt b/block-tlb/src/ExtBlkRef.kt index 5de223c8..321626a8 100644 --- a/block-tlb/src/ExtBlkRef.kt +++ b/block-tlb/src/ExtBlkRef.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -12,7 +11,7 @@ import org.ton.tlb.TlbObject import org.ton.tlb.TlbPrettyPrinter @SerialName("ext_blk_ref") -@Serializable + public data class ExtBlkRef( @SerialName("end_lt") val endLt: ULong, // end_lt : uint64 @SerialName("seq_no") val seqNo: UInt, // seq_no : uint32 diff --git a/block-tlb/src/ExtInMsgInfo.kt b/block-tlb/src/ExtInMsgInfo.kt index 22978306..375eaa7b 100644 --- a/block-tlb/src/ExtInMsgInfo.kt +++ b/block-tlb/src/ExtInMsgInfo.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -11,16 +10,23 @@ import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + @SerialName("ext_in_msg_info") public data class ExtInMsgInfo( val src: MsgAddressExt, val dest: MsgAddressInt, @SerialName("import_fee") val importFee: Coins ) : CommonMsgInfo { + public constructor(dest: MsgAddressInt) : this(null, dest) + + public constructor( + src: AddrExtern?, + dest: MsgAddressInt, + ) : this(src ?: AddrNone, dest, Coins.ZERO) + public constructor( dest: MsgAddressInt, - importFee: Coins = Coins() + importFee: Coins = Coins.ZERO ) : this(AddrNone, dest, importFee) override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { @@ -56,3 +62,6 @@ private object ExtInMsgInfoTlbConstructor : TlbConstructor( ExtInMsgInfo(src, dest, importFee) } } + +//1000100000000000101100100010011101000110010110110101100001101000110011000110001100000001100110100101000100111000001000000001100001101000101110011010101010010001010001001101000110001000100011111110101011100010101111110101101101101010101000011100111011111001110010011001111 +//1000100000000001011010100101010000101101011101000110111001101010101000000011101111100011001100110010111010101010000111001111110110101001100010000010111010101001110111001010000000111011110110110001010100001000001000010001000110011100100001001111000101101100110110111100100000000111011100001111111111010011011110101011010110100100011010111101110000101001100110100011111001001110000010000110010111100100010001111001111010001101110101010011111000010101100110110101011111111011010010100011111011010100001000001101110000011101110110011100001010001111110111010101010010000110101110011100001100100110001100001100111000111110101101001001001000010000111100000101111001111001100000100100011010111100110011101000101011110101000110001100101010100110000110111001001010001000111010110100000010010000001010000000000000000000000000000000000000011 \ No newline at end of file diff --git a/block-tlb/src/ExtOutMsgInfo.kt b/block-tlb/src/ExtOutMsgInfo.kt index 76dd80f0..54da2571 100644 --- a/block-tlb/src/ExtOutMsgInfo.kt +++ b/block-tlb/src/ExtOutMsgInfo.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -12,7 +11,7 @@ import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb @SerialName("ext_out_msg_info") -@Serializable + public data class ExtOutMsgInfo( val src: MsgAddressInt, val dest: MsgAddressExt, diff --git a/block-tlb/src/ExtraCurrencyCollection.kt b/block-tlb/src/ExtraCurrencyCollection.kt index 869d991c..6646cf2e 100644 --- a/block-tlb/src/ExtraCurrencyCollection.kt +++ b/block-tlb/src/ExtraCurrencyCollection.kt @@ -1,48 +1,70 @@ package org.ton.block -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice -import org.ton.cell.invoke -import org.ton.hashmap.HashMapE -import org.ton.tlb.* +import org.ton.kotlin.cell.CellContext +import org.ton.kotlin.currency.VarUInt248 +import org.ton.kotlin.dict.Dictionary +import org.ton.kotlin.dict.DictionaryKeyCodec +import org.ton.kotlin.dict.RawDictionary +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -import kotlin.jvm.JvmName - -@Serializable -@SerialName("extra_currencies") -public data class ExtraCurrencyCollection( - @get:JvmName("dict") - val dict: HashMapE = HashMapE.of() -) : TlbObject { - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter { - return printer.type("extra_currencies") { - field("dict", dict) - } + +/** + * Dictionary with amounts for multiple currencies. + * + * @see [CurrencyCollection] + */ +public class ExtraCurrencyCollection : Dictionary { + public constructor() : super(null, DictionaryKeyCodec.INT32, VarUInt248) + + public constructor(map: Map, context: CellContext = CellContext.EMPTY) : super( + map, DictionaryKeyCodec.INT32, VarUInt248, context + ) + + public constructor(cell: Cell?, context: CellContext = CellContext.EMPTY) : super( + cell, DictionaryKeyCodec.INT32, VarUInt248, context + ) + + public constructor(rawDictionary: RawDictionary, context: CellContext = CellContext.EMPTY) : super( + rawDictionary, DictionaryKeyCodec.INT32, VarUInt248, context + ) + + public constructor(dictionary: Dictionary, context: CellContext = CellContext.EMPTY) : super( + dictionary.dict.root, DictionaryKeyCodec.INT32, VarUInt248, context + ) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + if (!super.equals(other)) return false + return true } - override fun toString(): String = print().toString() + override fun toString(): String = this.asSequence().joinToString { (key, value) -> "$key=$value" } - public companion object : TlbConstructorProvider by ExtraCurrencyCollectionTlbConstructor + public companion object : TlbConstructorProvider by ExtraCurrencyCollectionTlbConstructor { + public val EMPTY: ExtraCurrencyCollection = ExtraCurrencyCollection(null) + } } private object ExtraCurrencyCollectionTlbConstructor : TlbConstructor( schema = "extra_currencies\$_ dict:(HashmapE 32 (VarUInteger 32)) = ExtraCurrencyCollection;" ) { - private val hashMapE32Codec = HashMapE.tlbCodec(32, VarUInteger.tlbCodec(32)) - override fun storeTlb( - cellBuilder: CellBuilder, - value: ExtraCurrencyCollection - ) = cellBuilder { - storeTlb(hashMapE32Codec, value.dict) + builder: CellBuilder, + value: ExtraCurrencyCollection, + context: CellContext + ) { + builder.storeNullableRef(value.cell) } override fun loadTlb( - cellSlice: CellSlice - ): ExtraCurrencyCollection = cellSlice { - val dict = loadTlb(hashMapE32Codec) - ExtraCurrencyCollection(dict) + slice: CellSlice, + context: CellContext + ): ExtraCurrencyCollection { + val cell = slice.loadNullableRef() + return ExtraCurrencyCollection(cell, context) } } diff --git a/block-tlb/src/FutureSplitMerge.kt b/block-tlb/src/FutureSplitMerge.kt index d0710cc7..ef98d992 100644 --- a/block-tlb/src/FutureSplitMerge.kt +++ b/block-tlb/src/FutureSplitMerge.kt @@ -3,7 +3,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -15,10 +14,10 @@ import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbCombinatorProvider import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @JsonClassDiscriminator("@type") public sealed interface FutureSplitMerge : TlbObject { - @Serializable + @SerialName("fsm_none") public object FsmNone : FutureSplitMerge, TlbConstructorProvider by FutureSplitMergeNoneTlbConstructor { @@ -27,7 +26,7 @@ public sealed interface FutureSplitMerge : TlbObject { override fun toString(): String = print().toString() } - @Serializable + @SerialName("fsm_merge") public data class FsmMerge( val mergeUtime: UInt, @@ -45,7 +44,7 @@ public sealed interface FutureSplitMerge : TlbObject { public companion object : TlbConstructorProvider by FutureSplitMergeMergeTlbConstructor } - @Serializable + @SerialName("fsm_split") public data class FsmSplit( val splitUtime: UInt, diff --git a/block-tlb/src/GlobalVersion.kt b/block-tlb/src/GlobalVersion.kt index e87cf696..7349c4f6 100644 --- a/block-tlb/src/GlobalVersion.kt +++ b/block-tlb/src/GlobalVersion.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor @SerialName("capabilities") -@Serializable + public data class GlobalVersion( val version: UInt, // version : uint32 val capabilities: ULong // capabilities : uint64 diff --git a/block-tlb/src/HashUpdate.kt b/block-tlb/src/HashUpdate.kt index 132dc7bd..3a0edf58 100644 --- a/block-tlb/src/HashUpdate.kt +++ b/block-tlb/src/HashUpdate.kt @@ -3,7 +3,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers import org.ton.bitstring.BitString import org.ton.cell.CellBuilder @@ -11,8 +10,9 @@ import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.crypto.HexByteArraySerializer import org.ton.tlb.* +import org.ton.tlb.TlbConstructor + -@Serializable @SerialName("update_hashes") public data class HashUpdate( @SerialName("old_hash") val oldHash: BitString, // old_hash : bits256 diff --git a/block-tlb/src/IhrPendingSince.kt b/block-tlb/src/IhrPendingSince.kt index a988b2c2..065139e5 100644 --- a/block-tlb/src/IhrPendingSince.kt +++ b/block-tlb/src/IhrPendingSince.kt @@ -1,14 +1,13 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("ihr_pending") public data class IhrPendingSince( val import_lt: ULong diff --git a/block-tlb/src/ImportFees.kt b/block-tlb/src/ImportFees.kt index 8f2bcbf0..03106311 100644 --- a/block-tlb/src/ImportFees.kt +++ b/block-tlb/src/ImportFees.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("import_fees") public data class ImportFees( val feesCollected: Coins, diff --git a/block-tlb/src/InMsg.kt b/block-tlb/src/InMsg.kt index 6c4bf975..750bc929 100644 --- a/block-tlb/src/InMsg.kt +++ b/block-tlb/src/InMsg.kt @@ -2,14 +2,13 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.tlb.TlbCombinator import org.ton.tlb.TlbObject import org.ton.tlb.providers.TlbCombinatorProvider @JsonClassDiscriminator("@type") -@Serializable + public sealed interface InMsg : TlbObject { public companion object : TlbCombinatorProvider by InMsgTlbCombinator } diff --git a/block-tlb/src/IntMsgInfo.kt b/block-tlb/src/IntMsgInfo.kt index e2b4de58..33ec18ef 100644 --- a/block-tlb/src/IntMsgInfo.kt +++ b/block-tlb/src/IntMsgInfo.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -12,7 +11,7 @@ import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb @SerialName("int_msg_info") -@Serializable + public data class IntMsgInfo( @SerialName("ihr_disabled") val ihrDisabled: Boolean, val bounce: Boolean, diff --git a/block-tlb/src/IntermediateAddress.kt b/block-tlb/src/IntermediateAddress.kt index 5a3d7fa2..4e00a344 100644 --- a/block-tlb/src/IntermediateAddress.kt +++ b/block-tlb/src/IntermediateAddress.kt @@ -2,13 +2,12 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.tlb.TlbCombinator import org.ton.tlb.TlbObject import org.ton.tlb.providers.TlbCombinatorProvider -@Serializable + @JsonClassDiscriminator("@type") public sealed interface IntermediateAddress : TlbObject { public companion object : TlbCombinatorProvider by IntermediateAddressTlbCombinator diff --git a/block-tlb/src/IntermediateAddressExt.kt b/block-tlb/src/IntermediateAddressExt.kt index fb62c978..a412ec6b 100644 --- a/block-tlb/src/IntermediateAddressExt.kt +++ b/block-tlb/src/IntermediateAddressExt.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -9,7 +8,7 @@ import org.ton.tlb.TlbConstructor import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("interm_addr_ext") public data class IntermediateAddressExt( @SerialName("workchain_id") val workchainId: Int, diff --git a/block-tlb/src/IntermediateAddressRegular.kt b/block-tlb/src/IntermediateAddressRegular.kt index 2fb68d90..121a3f8a 100644 --- a/block-tlb/src/IntermediateAddressRegular.kt +++ b/block-tlb/src/IntermediateAddressRegular.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -9,7 +8,7 @@ import org.ton.tlb.TlbConstructor import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("interm_addr_regular") public data class IntermediateAddressRegular( @SerialName("use_dest_bits") val useDestBits: Int diff --git a/block-tlb/src/IntermediateAddressSimple.kt b/block-tlb/src/IntermediateAddressSimple.kt index 70788f59..3b78cbfa 100644 --- a/block-tlb/src/IntermediateAddressSimple.kt +++ b/block-tlb/src/IntermediateAddressSimple.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -9,7 +8,7 @@ import org.ton.tlb.TlbConstructor import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("interm_addr_simple") public data class IntermediateAddressSimple( @SerialName("workchain_id") val workchainId: Int, diff --git a/block-tlb/src/KeyExtBlkRef.kt b/block-tlb/src/KeyExtBlkRef.kt index f4bd4e27..40f36016 100644 --- a/block-tlb/src/KeyExtBlkRef.kt +++ b/block-tlb/src/KeyExtBlkRef.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + public data class KeyExtBlkRef( val key: Boolean, // key: Bool @SerialName("blk_ref") val blkRef: ExtBlkRef // blk_ref: ExtBlkRef diff --git a/block-tlb/src/KeyMaxLt.kt b/block-tlb/src/KeyMaxLt.kt index 48804f92..5d7ecfcf 100644 --- a/block-tlb/src/KeyMaxLt.kt +++ b/block-tlb/src/KeyMaxLt.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -10,7 +9,7 @@ import org.ton.tlb.TlbObject import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + public data class KeyMaxLt( val key: Boolean, @SerialName("max_end_lt") val maxEndLt: ULong, diff --git a/block-tlb/src/LibDescr.kt b/block-tlb/src/LibDescr.kt index 6ee02f94..5552a474 100644 --- a/block-tlb/src/LibDescr.kt +++ b/block-tlb/src/LibDescr.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -13,7 +12,7 @@ import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + @SerialName("shared_lib_descr") public data class LibDescr( val lib: Cell, diff --git a/block-tlb/src/LibRef.kt b/block-tlb/src/LibRef.kt index 00fc704c..a2fb0dbb 100644 --- a/block-tlb/src/LibRef.kt +++ b/block-tlb/src/LibRef.kt @@ -2,9 +2,8 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator -@Serializable + @JsonClassDiscriminator("@type") public sealed interface LibRef diff --git a/block-tlb/src/LibRefHash.kt b/block-tlb/src/LibRefHash.kt index b95e6988..4c1888c2 100644 --- a/block-tlb/src/LibRefHash.kt +++ b/block-tlb/src/LibRefHash.kt @@ -1,10 +1,9 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString -@Serializable + @SerialName("libref_hash") public data class LibRefHash( val lib_hash: BitString diff --git a/block-tlb/src/LibRefRef.kt b/block-tlb/src/LibRefRef.kt index cfacd4b9..bbd27fd6 100644 --- a/block-tlb/src/LibRefRef.kt +++ b/block-tlb/src/LibRefRef.kt @@ -1,10 +1,9 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.Cell -@Serializable + @SerialName("libref_ref") public data class LibRefRef( val library: Cell diff --git a/block-tlb/src/Maybe.kt b/block-tlb/src/Maybe.kt index 8201d55f..a224ffe4 100644 --- a/block-tlb/src/Maybe.kt +++ b/block-tlb/src/Maybe.kt @@ -3,20 +3,20 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import kotlin.jvm.JvmStatic @Suppress("NOTHING_TO_INLINE") public inline fun X?.toMaybe(): Maybe = Maybe.of(this) @JsonClassDiscriminator("@type") -@Serializable + public sealed interface Maybe : TlbObject { public val value: X? @@ -35,7 +35,7 @@ public sealed interface Maybe : TlbObject { } @SerialName("nothing") -@Serializable + public class Nothing : Maybe { override val value: X? = null override fun hashCode(): Int = 0 @@ -48,7 +48,7 @@ public class Nothing : Maybe { } @SerialName("just") -@Serializable + public data class Just( override val value: X ) : Maybe { diff --git a/block-tlb/src/McBlockExtra.kt b/block-tlb/src/McBlockExtra.kt index 7f4cb81a..4675502f 100644 --- a/block-tlb/src/McBlockExtra.kt +++ b/block-tlb/src/McBlockExtra.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -9,11 +8,12 @@ import org.ton.cell.invoke import org.ton.hashmap.HashMapE import org.ton.hashmap.HashmapAugE import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.constructor.tlbCodec import org.ton.tlb.providers.TlbCombinatorProvider import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("masterchain_block_extra") public data class McBlockExtra( @SerialName("key_block") val keyBlock: Boolean, @@ -37,7 +37,7 @@ public data class McBlockExtra( public companion object : TlbCombinatorProvider by McBlockExtraTlbConstructor.asTlbCombinator() } -@Serializable + public data class McBlockExtraAux( @SerialName("prev_blk_signatures") val prevBlkSignatures: HashMapE, @SerialName("recover_create_msg") val recoverCreateMsg: Maybe>, diff --git a/block-tlb/src/McStateExtra.kt b/block-tlb/src/McStateExtra.kt index bce315dd..8d4edd5b 100644 --- a/block-tlb/src/McStateExtra.kt +++ b/block-tlb/src/McStateExtra.kt @@ -1,15 +1,15 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbCombinatorProvider import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("masterchain_state_extra") public data class McStateExtra( @SerialName("shard_hashes") val shardHashes: ShardHashes, // shard_hashes: ShardHashes @@ -31,7 +31,7 @@ public data class McStateExtra( public companion object : TlbCombinatorProvider by McStateExtraTlbConstructor.asTlbCombinator() } -@Serializable + public data class McStateExtraAux( val flags: Int, // flags : ## 16 @SerialName("validator_info") val validatorInfo: ValidatorInfo, // validator_info : ValidatorInfo diff --git a/block-tlb/src/MerkleProof.kt b/block-tlb/src/MerkleProof.kt index c531eb0d..af844b0e 100644 --- a/block-tlb/src/MerkleProof.kt +++ b/block-tlb/src/MerkleProof.kt @@ -1,13 +1,12 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.Cell import org.ton.cell.CellType import org.ton.tlb.CellRef -@Serializable + @SerialName("merkle_proof") public data class MerkleProof( val virtualHash: BitString, diff --git a/block-tlb/src/MerkleUpdate.kt b/block-tlb/src/MerkleUpdate.kt index 19cedea3..0c5ea66d 100644 --- a/block-tlb/src/MerkleUpdate.kt +++ b/block-tlb/src/MerkleUpdate.kt @@ -1,16 +1,16 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import kotlin.jvm.JvmStatic @SerialName("!merkle_update") -@Serializable + public data class MerkleUpdate( @SerialName("old_hash") val oldHash: BitString, @SerialName("new_hash") val newHash: BitString, diff --git a/block-tlb/src/Message.kt b/block-tlb/src/Message.kt index 25d4196e..55be3e44 100644 --- a/block-tlb/src/Message.kt +++ b/block-tlb/src/Message.kt @@ -1,21 +1,34 @@ package org.ton.block -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke +import org.ton.kotlin.message.MessageLayout import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.constructor.AnyTlbConstructor import kotlin.jvm.JvmStatic -@Serializable + public data class Message( val info: CommonMsgInfo, val init: Maybe>>, val body: Either> ) : TlbObject { + public constructor( + info: CommonMsgInfo, + init: StateInit?, + body: X, + bodyCodec: TlbCodec, + layout: MessageLayout + ) : this( + info = info, + init = layout.eitherInit(init).toMaybe(), + body = layout.eitherBody(body, bodyCodec), + ) + override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter { return printer.type("message") { field("info", info) diff --git a/block-tlb/src/MessageRelaxed.kt b/block-tlb/src/MessageRelaxed.kt index 6d01898b..d1b8f38c 100644 --- a/block-tlb/src/MessageRelaxed.kt +++ b/block-tlb/src/MessageRelaxed.kt @@ -1,20 +1,33 @@ package org.ton.block -import kotlinx.serialization.Serializable import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke +import org.ton.kotlin.message.MessageLayout import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.constructor.tlbCodec import kotlin.jvm.JvmStatic -@Serializable + public data class MessageRelaxed( val info: CommonMsgInfoRelaxed, val init: Maybe>>, val body: Either> ) : TlbObject { + public constructor( + info: CommonMsgInfoRelaxed, + init: StateInit?, + body: X, + bodyCodec: TlbCodec, + layout: MessageLayout + ) : this( + info = info, + init = layout.eitherInit(init).toMaybe(), + body = layout.eitherBody(body, bodyCodec), + ) + override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { type("message") { field("info", info) diff --git a/block-tlb/src/MsgAddress.kt b/block-tlb/src/MsgAddress.kt index e125cd7f..261d365d 100644 --- a/block-tlb/src/MsgAddress.kt +++ b/block-tlb/src/MsgAddress.kt @@ -1,12 +1,12 @@ package org.ton.block -import kotlinx.serialization.Serializable +import org.ton.kotlin.cell.CellSizeable import org.ton.tlb.TlbCombinator import org.ton.tlb.TlbObject import org.ton.tlb.providers.TlbCombinatorProvider -@Serializable -public sealed interface MsgAddress : TlbObject { + +public sealed interface MsgAddress : TlbObject, CellSizeable { public companion object : TlbCombinatorProvider by MsgAddressTlbCombinator } diff --git a/block-tlb/src/MsgAddressExt.kt b/block-tlb/src/MsgAddressExt.kt index d978bfd7..4b56b17c 100644 --- a/block-tlb/src/MsgAddressExt.kt +++ b/block-tlb/src/MsgAddressExt.kt @@ -2,7 +2,6 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.bitstring.BitString import org.ton.bitstring.isNullOrEmpty @@ -15,7 +14,7 @@ public inline fun MsgAddressExt(externalAddress: BitString? = null): MsgAddressE public inline fun MsgAddressExt(externalAddress: ByteArray): MsgAddressExt = MsgAddressExt.of(externalAddress) @JsonClassDiscriminator("@type") -@Serializable + public sealed interface MsgAddressExt : MsgAddress { public companion object : TlbCodec by MsgAddressExtTlbCombinator { @JvmStatic diff --git a/block-tlb/src/MsgAddressInt.kt b/block-tlb/src/MsgAddressInt.kt index 43514bc5..9fd9cc9b 100644 --- a/block-tlb/src/MsgAddressInt.kt +++ b/block-tlb/src/MsgAddressInt.kt @@ -3,7 +3,6 @@ package org.ton.block import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.bitstring.BitString import org.ton.tlb.TlbCodec @@ -15,11 +14,13 @@ public inline fun MsgAddressInt(address: String): MsgAddressInt = MsgAddressInt. @OptIn(ExperimentalSerializationApi::class) @JsonClassDiscriminator("@type") -@Serializable + public sealed interface MsgAddressInt : MsgAddress { public val workchainId: Int public val address: BitString + public fun toAddrStd(): AddrStd + public companion object : TlbCodec by MsgAddressIntTlbCombinator { @JvmStatic public fun tlbCodec(): TlbCombinator = MsgAddressIntTlbCombinator diff --git a/block-tlb/src/MsgDiscardFin.kt b/block-tlb/src/MsgDiscardFin.kt index a724e9dd..dd58af84 100644 --- a/block-tlb/src/MsgDiscardFin.kt +++ b/block-tlb/src/MsgDiscardFin.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_discard_fin") public data class MsgDiscardFin( val inMsg: CellRef, diff --git a/block-tlb/src/MsgDiscardTr.kt b/block-tlb/src/MsgDiscardTr.kt index fe3db691..c2b895e3 100644 --- a/block-tlb/src/MsgDiscardTr.kt +++ b/block-tlb/src/MsgDiscardTr.kt @@ -1,15 +1,15 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_discard_tr") public data class MsgDiscardTr( @SerialName("in_msg") val inMsg: CellRef, diff --git a/block-tlb/src/MsgEnvelope.kt b/block-tlb/src/MsgEnvelope.kt index f7549845..96b013d6 100644 --- a/block-tlb/src/MsgEnvelope.kt +++ b/block-tlb/src/MsgEnvelope.kt @@ -1,15 +1,15 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbCombinatorProvider -@Serializable + @SerialName("msg_envelope") public data class MsgEnvelope( @SerialName("cur_addr") val curAddr: IntermediateAddress, diff --git a/block-tlb/src/MsgExportDeq.kt b/block-tlb/src/MsgExportDeq.kt index 243d14a2..00042a67 100644 --- a/block-tlb/src/MsgExportDeq.kt +++ b/block-tlb/src/MsgExportDeq.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_export_deq") public data class MsgExportDeq( val outMsg: CellRef, diff --git a/block-tlb/src/MsgExportDeqImm.kt b/block-tlb/src/MsgExportDeqImm.kt index 5fd39f22..be85f23d 100644 --- a/block-tlb/src/MsgExportDeqImm.kt +++ b/block-tlb/src/MsgExportDeqImm.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_export_deq_imm") public data class MsgExportDeqImm( val outMsg: CellRef, diff --git a/block-tlb/src/MsgExportDeqShort.kt b/block-tlb/src/MsgExportDeqShort.kt index 459b2017..88b46861 100644 --- a/block-tlb/src/MsgExportDeqShort.kt +++ b/block-tlb/src/MsgExportDeqShort.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -10,7 +9,7 @@ import org.ton.tlb.TlbConstructor import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_export_deq_short") public data class MsgExportDeqShort( val msgEnvHash: BitString, diff --git a/block-tlb/src/MsgExportExt.kt b/block-tlb/src/MsgExportExt.kt index b3d1f3b6..2b272e1b 100644 --- a/block-tlb/src/MsgExportExt.kt +++ b/block-tlb/src/MsgExportExt.kt @@ -1,15 +1,15 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_export_ext") public data class MsgExportExt( val msg: CellRef>, diff --git a/block-tlb/src/MsgExportImm.kt b/block-tlb/src/MsgExportImm.kt index 81d81cd5..0c327e2f 100644 --- a/block-tlb/src/MsgExportImm.kt +++ b/block-tlb/src/MsgExportImm.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_export_imm") public data class MsgExportImm( val outMsg: CellRef, diff --git a/block-tlb/src/MsgExportNew.kt b/block-tlb/src/MsgExportNew.kt index 04d35fac..4769b133 100644 --- a/block-tlb/src/MsgExportNew.kt +++ b/block-tlb/src/MsgExportNew.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_export_new") public data class MsgExportNew( val outMsg: CellRef, diff --git a/block-tlb/src/MsgExportTr.kt b/block-tlb/src/MsgExportTr.kt index 7b1d88b1..989487f7 100644 --- a/block-tlb/src/MsgExportTr.kt +++ b/block-tlb/src/MsgExportTr.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_export_tr") public data class MsgExportTr( val outMsg: CellRef, diff --git a/block-tlb/src/MsgExportTrReq.kt b/block-tlb/src/MsgExportTrReq.kt index fc2e6cda..0dd90cf0 100644 --- a/block-tlb/src/MsgExportTrReq.kt +++ b/block-tlb/src/MsgExportTrReq.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_export_tr_req") public data class MsgExportTrReq( val outMsg: CellRef, diff --git a/block-tlb/src/MsgImportExt.kt b/block-tlb/src/MsgImportExt.kt index 5dc891b1..7f33ed6c 100644 --- a/block-tlb/src/MsgImportExt.kt +++ b/block-tlb/src/MsgImportExt.kt @@ -3,15 +3,15 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_import_ext") public data class MsgImportExt( val msg: CellRef>, diff --git a/block-tlb/src/MsgImportFin.kt b/block-tlb/src/MsgImportFin.kt index c994876a..eccc1a8b 100644 --- a/block-tlb/src/MsgImportFin.kt +++ b/block-tlb/src/MsgImportFin.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_import_fin") public data class MsgImportFin( @SerialName("in_msg") val inMsg: CellRef, diff --git a/block-tlb/src/MsgImportIhr.kt b/block-tlb/src/MsgImportIhr.kt index 718ff05f..7b9efb58 100644 --- a/block-tlb/src/MsgImportIhr.kt +++ b/block-tlb/src/MsgImportIhr.kt @@ -1,15 +1,15 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_import_ihr") public data class MsgImportIhr( val msg: CellRef>, diff --git a/block-tlb/src/MsgImportImm.kt b/block-tlb/src/MsgImportImm.kt index 63e9bab1..570a08c4 100644 --- a/block-tlb/src/MsgImportImm.kt +++ b/block-tlb/src/MsgImportImm.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_import_imm") public data class MsgImportImm( @SerialName("in_msg") val inMsg: CellRef, diff --git a/block-tlb/src/MsgImportTr.kt b/block-tlb/src/MsgImportTr.kt index 0397123b..14bcbf07 100644 --- a/block-tlb/src/MsgImportTr.kt +++ b/block-tlb/src/MsgImportTr.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("msg_import_tr") public data class MsgImportTr( @SerialName("in_msg") val inMsg: CellRef, diff --git a/block-tlb/src/OldMcBlocksInfo.kt b/block-tlb/src/OldMcBlocksInfo.kt index e7529fa9..bf872ec9 100644 --- a/block-tlb/src/OldMcBlocksInfo.kt +++ b/block-tlb/src/OldMcBlocksInfo.kt @@ -1,15 +1,15 @@ package org.ton.block -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.hashmap.HashmapAugE +import org.ton.kotlin.cell.CellContext import org.ton.tlb.TlbCodec import org.ton.tlb.TlbObject import org.ton.tlb.TlbPrettyPrinter import kotlin.jvm.JvmInline -@Serializable + @JvmInline public value class OldMcBlocksInfo( public val value: HashmapAugE @@ -26,11 +26,11 @@ public value class OldMcBlocksInfo( private object OldMcBlocksInfoTlbCodec : TlbCodec { private val codec = HashmapAugE.tlbCodec(32, KeyExtBlkRef, KeyMaxLt) - override fun storeTlb(cellBuilder: CellBuilder, value: OldMcBlocksInfo) { - codec.storeTlb(cellBuilder, value.value) + override fun storeTlb(cellBuilder: CellBuilder, value: OldMcBlocksInfo, context: CellContext) { + codec.storeTlb(cellBuilder, value.value, context) } - override fun loadTlb(cellSlice: CellSlice): OldMcBlocksInfo { - return OldMcBlocksInfo(codec.loadTlb(cellSlice)) + override fun loadTlb(cellSlice: CellSlice, context: CellContext): OldMcBlocksInfo { + return OldMcBlocksInfo(codec.loadTlb(cellSlice, context)) } } diff --git a/block-tlb/src/OutAction.kt b/block-tlb/src/OutAction.kt index 62122275..3eaafd93 100644 --- a/block-tlb/src/OutAction.kt +++ b/block-tlb/src/OutAction.kt @@ -2,9 +2,8 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator -@Serializable + @JsonClassDiscriminator("@type") public sealed interface OutAction diff --git a/block-tlb/src/OutList.kt b/block-tlb/src/OutList.kt index 8af3df1b..ce99339e 100644 --- a/block-tlb/src/OutList.kt +++ b/block-tlb/src/OutList.kt @@ -2,9 +2,8 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator -@Serializable + @JsonClassDiscriminator("@type") public sealed interface OutList diff --git a/block-tlb/src/OutListEmpty.kt b/block-tlb/src/OutListEmpty.kt index 7e2ee8ce..c91b7997 100644 --- a/block-tlb/src/OutListEmpty.kt +++ b/block-tlb/src/OutListEmpty.kt @@ -1,8 +1,7 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -@Serializable + @SerialName("out_list_empty") public object OutListEmpty : OutList diff --git a/block-tlb/src/OutListLink.kt b/block-tlb/src/OutListLink.kt index 605385bb..a53e379a 100644 --- a/block-tlb/src/OutListLink.kt +++ b/block-tlb/src/OutListLink.kt @@ -1,9 +1,8 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -@Serializable + @SerialName("out_list") public data class OutListLink( val prev: OutList, diff --git a/block-tlb/src/OutListNode.kt b/block-tlb/src/OutListNode.kt index a7b50167..f1ad5f27 100644 --- a/block-tlb/src/OutListNode.kt +++ b/block-tlb/src/OutListNode.kt @@ -1,10 +1,9 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.Cell -@Serializable + @SerialName("out_list_node") public data class OutListNode( val prev: Cell, diff --git a/block-tlb/src/OutMsg.kt b/block-tlb/src/OutMsg.kt index 803c73ff..b41309c0 100644 --- a/block-tlb/src/OutMsg.kt +++ b/block-tlb/src/OutMsg.kt @@ -2,13 +2,12 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.tlb.TlbCombinator import org.ton.tlb.TlbObject import org.ton.tlb.providers.TlbCombinatorProvider -@Serializable + @JsonClassDiscriminator("@type") public sealed interface OutMsg : TlbObject { public companion object : TlbCombinatorProvider by OutMsgTlbCombinator diff --git a/block-tlb/src/OutMsgQueueInfo.kt b/block-tlb/src/OutMsgQueueInfo.kt index 7bf1c211..edc40519 100644 --- a/block-tlb/src/OutMsgQueueInfo.kt +++ b/block-tlb/src/OutMsgQueueInfo.kt @@ -1,17 +1,17 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.hashmap.HashMapE import org.ton.hashmap.HashmapAugE import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.constructor.tlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + public data class OutMsgQueueInfo( @SerialName("out_queue") val outQueue: HashmapAugE, // out_queue : OutMsgQueue @SerialName("proc_info") val procInfo: HashMapE, // proc_info : ProcessedInfo diff --git a/block-tlb/src/PrevBlkInfo.kt b/block-tlb/src/PrevBlkInfo.kt index 3a1c35f4..5b3d2d40 100644 --- a/block-tlb/src/PrevBlkInfo.kt +++ b/block-tlb/src/PrevBlkInfo.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -11,7 +10,7 @@ import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + @SerialName("prev_blk_info") public data class PrevBlkInfo( val prev: ExtBlkRef // prev : ExtBlkRef diff --git a/block-tlb/src/PrevBlksInfo.kt b/block-tlb/src/PrevBlksInfo.kt index 24d4e395..3191d6bf 100644 --- a/block-tlb/src/PrevBlksInfo.kt +++ b/block-tlb/src/PrevBlksInfo.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("prev_blks_info") public data class PrevBlksInfo( val prev1: CellRef, // prev1 : ^ExtBlkRef diff --git a/block-tlb/src/ProcessedUpto.kt b/block-tlb/src/ProcessedUpto.kt index 314025ef..a47e87c9 100644 --- a/block-tlb/src/ProcessedUpto.kt +++ b/block-tlb/src/ProcessedUpto.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -11,7 +10,7 @@ import org.ton.tlb.TlbObject import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("processed_upto") public data class ProcessedUpto( @SerialName("last_msg_lt") val lastMsgLt: ULong, diff --git a/block-tlb/src/ProtoHttp.kt b/block-tlb/src/ProtoHttp.kt index 77282e9c..8cfe1955 100644 --- a/block-tlb/src/ProtoHttp.kt +++ b/block-tlb/src/ProtoHttp.kt @@ -1,14 +1,13 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider @SerialName("proto_http") -@Serializable + public object ProtoHttp : Protocol, TlbConstructorProvider by ProtoHttpTlbConstructor private object ProtoHttpTlbConstructor : TlbConstructor( diff --git a/block-tlb/src/ProtoListNext.kt b/block-tlb/src/ProtoListNext.kt index 3e6d1d19..6fd553ba 100644 --- a/block-tlb/src/ProtoListNext.kt +++ b/block-tlb/src/ProtoListNext.kt @@ -1,13 +1,12 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb @SerialName("proto_list_next") -@Serializable + public data class ProtoListNext( val head: Protocol, val tail: ProtoList diff --git a/block-tlb/src/ProtoListNil.kt b/block-tlb/src/ProtoListNil.kt index 8afa2e88..b56e42e7 100644 --- a/block-tlb/src/ProtoListNil.kt +++ b/block-tlb/src/ProtoListNil.kt @@ -1,13 +1,12 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.tlb.providers.TlbConstructorProvider @SerialName("proto_list_nil") -@Serializable + public object ProtoListNil : ProtoList, TlbConstructorProvider by ProtoListNilTlbConstructor { override fun iterator(): Iterator = iterator {} } diff --git a/block-tlb/src/ShardAccount.kt b/block-tlb/src/ShardAccount.kt index 3a1e4183..afd28e30 100644 --- a/block-tlb/src/ShardAccount.kt +++ b/block-tlb/src/ShardAccount.kt @@ -1,21 +1,43 @@ package org.ton.block -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.bitstring.BitString +import kotlinx.io.bytestring.ByteString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke -import org.ton.tlb.* +import org.ton.kotlin.cell.CellContext +import org.ton.tlb.CellRef +import org.ton.tlb.TlbConstructor +import org.ton.tlb.TlbObject +import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider -@Serializable -@SerialName("account_descr") +/** + * Shard accounts entry. + */ public data class ShardAccount( - val account: CellRef, - @SerialName("last_trans_hash") val lastTransHash: BitString, - @SerialName("last_trans_lt") val lastTransLt: ULong + /** + * Optional reference to account state. + */ + val account: CellRef, + + /** + * The exact hash of the last transaction. + */ + val lastTransHash: ByteString, + + /** + * The exact logical time of the last transaction. + */ + val lastTransLt: Long ) : TlbObject { + + /** + * Load account data from cell. + */ + public fun loadAccount(context: CellContext = CellContext.EMPTY): Account? { + return account.load(context) + } + override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer.type("account_descr") { field("account", account) field("last_trans_hash", lastTransHash) @@ -24,6 +46,23 @@ public data class ShardAccount( override fun toString(): String = print().toString() + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + other as ShardAccount + if (lastTransLt != other.lastTransLt) return false + if (account != other.account) return false + if (lastTransHash != other.lastTransHash) return false + return true + } + + override fun hashCode(): Int { + var result = lastTransLt.hashCode() + result = 31 * result + account.hashCode() + result = 31 * result + lastTransHash.hashCode() + return result + } + public companion object : TlbConstructorProvider by ShardAccountTlbConstructor } @@ -34,17 +73,17 @@ private object ShardAccountTlbConstructor : TlbConstructor( cellBuilder: CellBuilder, value: ShardAccount ) = cellBuilder { - storeRef(Account, value.account) - storeBits(value.lastTransHash) - storeUInt64(value.lastTransLt) + storeRef(value.account.cell) + storeBytes(value.lastTransHash.toByteArray()) + storeULong(value.lastTransLt.toULong()) } override fun loadTlb( cellSlice: CellSlice ): ShardAccount = cellSlice { - val account = loadRef(Account) - val lastTransHash = loadBits(256) - val lastTransLt = loadUInt64() + val account = CellRef(loadRef(), Account) + val lastTransHash = loadByteString(32) + val lastTransLt = loadULong().toLong() ShardAccount(account, lastTransHash, lastTransLt) } } diff --git a/block-tlb/src/ShardAccounts.kt b/block-tlb/src/ShardAccounts.kt index 35f01d65..e6a14513 100644 --- a/block-tlb/src/ShardAccounts.kt +++ b/block-tlb/src/ShardAccounts.kt @@ -1,15 +1,15 @@ package org.ton.block -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.hashmap.HashmapAugE +import org.ton.kotlin.cell.CellContext import org.ton.tlb.TlbCodec import org.ton.tlb.TlbObject import org.ton.tlb.TlbPrettyPrinter import kotlin.jvm.JvmInline -@Serializable + @JvmInline public value class ShardAccounts( public val x: HashmapAugE @@ -26,11 +26,11 @@ public value class ShardAccounts( private object ShardAccountsTlbCodec : TlbCodec { private val codec = HashmapAugE.tlbCodec(256, ShardAccount, DepthBalanceInfo) - override fun storeTlb(cellBuilder: CellBuilder, value: ShardAccounts) { - codec.storeTlb(cellBuilder, value.x) + override fun storeTlb(cellBuilder: CellBuilder, value: ShardAccounts, context: CellContext) { + codec.storeTlb(cellBuilder, value.x, context) } - override fun loadTlb(cellSlice: CellSlice): ShardAccounts { - return ShardAccounts(codec.loadTlb(cellSlice)) + override fun loadTlb(cellSlice: CellSlice, context: CellContext): ShardAccounts { + return ShardAccounts(codec.loadTlb(cellSlice, context)) } } diff --git a/block-tlb/src/ShardDescr.kt b/block-tlb/src/ShardDescr.kt index 2e5ab501..dbf2d0cc 100644 --- a/block-tlb/src/ShardDescr.kt +++ b/block-tlb/src/ShardDescr.kt @@ -1,15 +1,15 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbCombinatorProvider import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + public sealed interface ShardDescr : TlbObject { public companion object : TlbCombinatorProvider by ShardDescrTlbCombinator } @@ -20,7 +20,7 @@ private object ShardDescrTlbCombinator : TlbCombinator( ShardDescrNew::class to ShardDescrNew, ) -@Serializable + @SerialName("shard_descr_old") public data class ShardDescrOld( @SerialName("seq_no") val seqNo: UInt, @@ -77,7 +77,7 @@ public data class ShardDescrOld( public companion object : TlbConstructorProvider by ShardDescrOldTlbConstructor } -@Serializable + public data class ShardDescrAux( @SerialName("fees_collected") val feesCollected: CurrencyCollection, @SerialName("funds_created") val fundsCreated: CurrencyCollection @@ -94,7 +94,7 @@ public data class ShardDescrAux( public companion object : TlbConstructorProvider by ShardDescrAuxTlbConstructor } -@Serializable + public data class ShardDescrNew( @SerialName("seq_no") val seqNo: UInt, @SerialName("reg_mc_seqno") val regMcSeqno: UInt, diff --git a/block-tlb/src/ShardFeeCreated.kt b/block-tlb/src/ShardFeeCreated.kt index e893752b..33ecd3da 100644 --- a/block-tlb/src/ShardFeeCreated.kt +++ b/block-tlb/src/ShardFeeCreated.kt @@ -1,13 +1,13 @@ package org.ton.block -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + public data class ShardFeeCreated( val fees: CurrencyCollection, val create: CurrencyCollection diff --git a/block-tlb/src/ShardHashes.kt b/block-tlb/src/ShardHashes.kt index 9b8dee83..af371a48 100644 --- a/block-tlb/src/ShardHashes.kt +++ b/block-tlb/src/ShardHashes.kt @@ -1,16 +1,16 @@ package org.ton.block -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.hashmap.HashMapE +import org.ton.kotlin.cell.CellContext import org.ton.tlb.CellRef import org.ton.tlb.TlbCodec import org.ton.tlb.TlbObject import org.ton.tlb.TlbPrettyPrinter import kotlin.jvm.JvmInline -@Serializable + @JvmInline public value class ShardHashes( public val value: HashMapE>> @@ -26,11 +26,11 @@ public value class ShardHashes( private object ShardHashesTlbCodec : TlbCodec { private val codec = HashMapE.tlbCodec(32, CellRef.tlbCodec(BinTree.tlbCodec(ShardDescr))) - override fun storeTlb(cellBuilder: CellBuilder, value: ShardHashes) { - codec.storeTlb(cellBuilder, value.value) + override fun storeTlb(cellBuilder: CellBuilder, value: ShardHashes, context: CellContext) { + codec.storeTlb(cellBuilder, value.value, context) } - override fun loadTlb(cellSlice: CellSlice): ShardHashes { - return ShardHashes(codec.loadTlb(cellSlice)) + override fun loadTlb(cellSlice: CellSlice, context: CellContext): ShardHashes { + return ShardHashes(codec.loadTlb(cellSlice, context)) } } diff --git a/block-tlb/src/ShardIdent.kt b/block-tlb/src/ShardIdent.kt index 0d9e71c7..466a770c 100644 --- a/block-tlb/src/ShardIdent.kt +++ b/block-tlb/src/ShardIdent.kt @@ -1,14 +1,14 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor @SerialName("shard_ident") -@Serializable + public data class ShardIdent( @SerialName("shard_pfx_bits") val shardPfxBits: Int, // shard_pfx_bits : #<= 60 @SerialName("workchain_id") val workchainId: Int, // workchain_id : int32 diff --git a/block-tlb/src/ShardState.kt b/block-tlb/src/ShardState.kt index 5b37295d..58171254 100644 --- a/block-tlb/src/ShardState.kt +++ b/block-tlb/src/ShardState.kt @@ -2,13 +2,12 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.tlb.TlbCombinator import org.ton.tlb.TlbObject import org.ton.tlb.providers.TlbCombinatorProvider -@Serializable + @JsonClassDiscriminator("@type") public sealed interface ShardState : TlbObject { public companion object : TlbCombinatorProvider by ShardStateTlbCombinator diff --git a/block-tlb/src/ShardStateUnsplit.kt b/block-tlb/src/ShardStateUnsplit.kt index a26880f8..99e13873 100644 --- a/block-tlb/src/ShardStateUnsplit.kt +++ b/block-tlb/src/ShardStateUnsplit.kt @@ -1,15 +1,15 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.hashmap.HashMapE import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("shard_state") public data class ShardStateUnsplit( @SerialName("global_id") val globalId: Int, // global_id : int32 @@ -47,7 +47,7 @@ public data class ShardStateUnsplit( public companion object : TlbConstructorProvider by ShardStateUnsplitTlbConstructor } -@Serializable + public data class ShardStateUnsplitAux( @SerialName("overload_history") val overloadHistory: ULong, // overload_history : uint64 @SerialName("underload_history") val underloadHistory: ULong, // underload_history : uint64 diff --git a/block-tlb/src/SigPubKey.kt b/block-tlb/src/SigPubKey.kt index c4e1ac6c..92906a3e 100644 --- a/block-tlb/src/SigPubKey.kt +++ b/block-tlb/src/SigPubKey.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -9,7 +8,7 @@ import org.ton.cell.invoke import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("ed25519_pubkey") public data class SigPubKey( val pubkey: BitString diff --git a/block-tlb/src/SignedCertificate.kt b/block-tlb/src/SignedCertificate.kt index 58b887cb..e6275df9 100644 --- a/block-tlb/src/SignedCertificate.kt +++ b/block-tlb/src/SignedCertificate.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -10,7 +9,7 @@ import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + @SerialName("signed_certificate") public data class SignedCertificate( val certificate: Certificate, diff --git a/block-tlb/src/SimpleLib.kt b/block-tlb/src/SimpleLib.kt index 90bc6fd5..2969d9c7 100644 --- a/block-tlb/src/SimpleLib.kt +++ b/block-tlb/src/SimpleLib.kt @@ -1,6 +1,5 @@ package org.ton.block -import kotlinx.serialization.Serializable import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -11,7 +10,7 @@ import org.ton.tlb.TlbObject import org.ton.tlb.TlbPrettyPrinter import kotlin.jvm.JvmStatic -@Serializable + public data class SimpleLib( val public: Boolean, val root: Cell diff --git a/block-tlb/src/SmartContractInfo.kt b/block-tlb/src/SmartContractInfo.kt index 62a19c1b..9889383a 100644 --- a/block-tlb/src/SmartContractInfo.kt +++ b/block-tlb/src/SmartContractInfo.kt @@ -1,10 +1,9 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString -@Serializable + @SerialName("smc_info") public data class SmartContractInfo( val actions: Int, diff --git a/block-tlb/src/SplitMergeInfo.kt b/block-tlb/src/SplitMergeInfo.kt index 7e9544c4..2fd246f0 100644 --- a/block-tlb/src/SplitMergeInfo.kt +++ b/block-tlb/src/SplitMergeInfo.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -11,7 +10,7 @@ import org.ton.tlb.TlbConstructor import org.ton.tlb.TlbObject import org.ton.tlb.TlbPrettyPrinter -@Serializable + @SerialName("split_merge_info") public data class SplitMergeInfo( val curShardPfxLen: Int, diff --git a/block-tlb/src/SplitState.kt b/block-tlb/src/SplitState.kt index d559d1d5..54fc843c 100644 --- a/block-tlb/src/SplitState.kt +++ b/block-tlb/src/SplitState.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.* import org.ton.tlb.TlbConstructor import org.ton.tlb.TlbPrettyPrinter @@ -9,7 +8,7 @@ import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + @SerialName("split_state") public data class SplitState( val left: ShardStateUnsplit, diff --git a/block-tlb/src/StateInit.kt b/block-tlb/src/StateInit.kt index c7cfaa89..05a163d4 100644 --- a/block-tlb/src/StateInit.kt +++ b/block-tlb/src/StateInit.kt @@ -1,19 +1,20 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.cell.Cell -import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice -import org.ton.cell.invoke +import org.ton.bitstring.BitString +import org.ton.cell.* import org.ton.hashmap.HashMapE +import org.ton.hashmap.HmeEmpty +import org.ton.kotlin.cell.CellSize +import org.ton.kotlin.cell.CellSizeable import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.constructor.AnyTlbConstructor import org.ton.tlb.constructor.UIntTlbConstructor import kotlin.jvm.JvmName import kotlin.jvm.JvmStatic -@Serializable + public data class StateInit( @SerialName("split_depth") @get:JvmName("splitDepth") @@ -30,7 +31,7 @@ public data class StateInit( @get:JvmName("library") val library: HashMapE -) : TlbObject { +) : TlbObject, CellSizeable { public constructor( code: Cell? = null, data: Cell? = null, @@ -45,6 +46,29 @@ public data class StateInit( library ) + override val cellSize: CellSize + get() = CellSize( + bits = (1 + if (splitDepth.value != null) 5 else 0) + (1 + if (special.value != null) 2 else 0) + 3, + refs = (if (code.value != null) 1 else 0) + (if (data.value != null) 1 else 0) + (if (library is HmeEmpty) 0 else 1) + ) + + private var hash: BitString = BitString.empty() + + public fun address(workchain: Int = 0): AddrStd { + var hash = hash + if (hash == BitString.empty()) { + hash = buildCell { + storeTlb(StateInitTlbConstructor, this@StateInit) + }.hash() + this.hash = hash + } + return AddrStd(workchain, hash) + } + + public fun toCell(): Cell = buildCell { + storeTlb(StateInitTlbConstructor, this@StateInit) + } + override fun toString(): String = print().toString() override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { diff --git a/block-tlb/src/StorageInfo.kt b/block-tlb/src/StorageInfo.kt index 40bbf50d..66f9f5b3 100644 --- a/block-tlb/src/StorageInfo.kt +++ b/block-tlb/src/StorageInfo.kt @@ -1,15 +1,15 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider import kotlin.jvm.JvmName -@Serializable + @SerialName("storage_info") public data class StorageInfo( @get:JvmName("used") diff --git a/block-tlb/src/TrStoragePhase.kt b/block-tlb/src/StoragePhase.kt similarity index 78% rename from block-tlb/src/TrStoragePhase.kt rename to block-tlb/src/StoragePhase.kt index 99cea308..cf4f8df3 100644 --- a/block-tlb/src/TrStoragePhase.kt +++ b/block-tlb/src/StoragePhase.kt @@ -1,16 +1,16 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("tr_phase_storage") -public data class TrStoragePhase( +public data class StoragePhase( @SerialName("storage_fees_collected") val storageFeesCollected: Coins, @SerialName("storage_fees_due") val storageFeesDue: Maybe, @SerialName("status_change") val statusChange: AccStatusChange @@ -25,10 +25,10 @@ public data class TrStoragePhase( } } - public companion object : TlbConstructorProvider by TrStoragePhaseTlbConstructor + public companion object : TlbConstructorProvider by TrStoragePhaseTlbConstructor } -private object TrStoragePhaseTlbConstructor : TlbConstructor( +private object TrStoragePhaseTlbConstructor : TlbConstructor( schema = "tr_phase_storage\$_ storage_fees_collected:Coins " + "storage_fees_due:(Maybe Coins) " + "status_change:AccStatusChange " + @@ -38,7 +38,7 @@ private object TrStoragePhaseTlbConstructor : TlbConstructor( override fun storeTlb( cellBuilder: CellBuilder, - value: TrStoragePhase + value: StoragePhase ) = cellBuilder { storeTlb(Coins, value.storageFeesCollected) storeTlb(maybeCoins, value.storageFeesDue) @@ -47,10 +47,10 @@ private object TrStoragePhaseTlbConstructor : TlbConstructor( override fun loadTlb( cellSlice: CellSlice - ): TrStoragePhase = cellSlice { + ): StoragePhase = cellSlice { val storageFeesCollected = loadTlb(Coins) val storageFeesDue = loadTlb(maybeCoins) val statusChange = loadTlb(AccStatusChange) - TrStoragePhase(storageFeesCollected, storageFeesDue, statusChange) + StoragePhase(storageFeesCollected, storageFeesDue, statusChange) } } diff --git a/block-tlb/src/StorageUsed.kt b/block-tlb/src/StorageUsed.kt index 2207d8dd..c7d7ffc7 100644 --- a/block-tlb/src/StorageUsed.kt +++ b/block-tlb/src/StorageUsed.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -9,7 +8,7 @@ import org.ton.tlb.* import org.ton.tlb.providers.TlbConstructorProvider @SerialName("storage_used") -@Serializable + public data class StorageUsed( val cells: VarUInteger, val bits: VarUInteger, diff --git a/block-tlb/src/StorageUsedShort.kt b/block-tlb/src/StorageUsedShort.kt index 6ed2f1e5..2ad09ce7 100644 --- a/block-tlb/src/StorageUsedShort.kt +++ b/block-tlb/src/StorageUsedShort.kt @@ -1,18 +1,15 @@ package org.ton.block -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@SerialName("storage_used_short") -@Serializable public data class StorageUsedShort( - val cells: VarUInteger, - val bits: VarUInteger + val cells: Long, + val bits: Long ) : TlbObject { override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter { return printer { @@ -25,7 +22,9 @@ public data class StorageUsedShort( override fun toString(): String = print().toString() - public companion object : TlbConstructorProvider by StorageUsedShortTlbConstructor + public companion object : TlbConstructorProvider by StorageUsedShortTlbConstructor { + public val ZERO: StorageUsedShort = StorageUsedShort(0, 0) + } } private object StorageUsedShortTlbConstructor : TlbConstructor( @@ -33,18 +32,19 @@ private object StorageUsedShortTlbConstructor : TlbConstructor ) { private val varUInteger7Codec = VarUInteger.tlbCodec(7) + @Suppress("DEPRECATION") override fun storeTlb( cellBuilder: CellBuilder, value: StorageUsedShort ) = cellBuilder { - storeTlb(varUInteger7Codec, value.cells) - storeTlb(varUInteger7Codec, value.bits) + storeTlb(varUInteger7Codec, VarUInteger(value.cells)) + storeTlb(varUInteger7Codec, VarUInteger(value.bits)) } override fun loadTlb( cellSlice: CellSlice ): StorageUsedShort = cellSlice { - val cells = loadTlb(varUInteger7Codec) - val bits = loadTlb(varUInteger7Codec) + val cells = loadTlb(varUInteger7Codec).value.toLong() + val bits = loadTlb(varUInteger7Codec).value.toLong() StorageUsedShort(cells, bits) } } diff --git a/block-tlb/src/Text.kt b/block-tlb/src/Text.kt index 6c5192d2..f1f09e53 100644 --- a/block-tlb/src/Text.kt +++ b/block-tlb/src/Text.kt @@ -1,6 +1,5 @@ package org.ton.block -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.tlb.TlbConstructor @@ -8,7 +7,7 @@ import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + public data class Text( val chunks: UByte, val rest: TextChunks diff --git a/block-tlb/src/TickTock.kt b/block-tlb/src/TickTock.kt index ca189a05..d274d473 100644 --- a/block-tlb/src/TickTock.kt +++ b/block-tlb/src/TickTock.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -14,7 +13,7 @@ import org.ton.tlb.providers.TlbConstructorProvider public inline fun Pair.toTickTock(): TickTock = TickTock(first, second) @SerialName("tick_tock") -@Serializable + public data class TickTock( val tick: Boolean, val tock: Boolean diff --git a/block-tlb/src/TrBouncePhase.kt b/block-tlb/src/TrBouncePhase.kt deleted file mode 100644 index 51c964ae..00000000 --- a/block-tlb/src/TrBouncePhase.kt +++ /dev/null @@ -1,22 +0,0 @@ -@file:Suppress("OPT_IN_USAGE") - -package org.ton.block - -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonClassDiscriminator -import org.ton.tlb.TlbCombinator -import org.ton.tlb.TlbObject -import org.ton.tlb.providers.TlbCombinatorProvider - -@JsonClassDiscriminator("@type") -@Serializable -public sealed interface TrBouncePhase : TlbObject { - public companion object : TlbCombinatorProvider by TrBouncePhaseTlbCombinator -} - -private object TrBouncePhaseTlbCombinator : TlbCombinator( - TrBouncePhase::class, - TrPhaseBounceNegFunds::class to TrPhaseBounceNegFunds, - TrPhaseBounceNoFunds::class to TrPhaseBounceNoFunds, - TrPhaseBounceOk::class to TrPhaseBounceOk, -) diff --git a/block-tlb/src/TrPhaseBounceNegFunds.kt b/block-tlb/src/TrPhaseBounceNegFunds.kt deleted file mode 100644 index 2df2daf3..00000000 --- a/block-tlb/src/TrPhaseBounceNegFunds.kt +++ /dev/null @@ -1,28 +0,0 @@ -package org.ton.block - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice -import org.ton.tlb.TlbConstructor -import org.ton.tlb.TlbPrettyPrinter -import org.ton.tlb.providers.TlbConstructorProvider - -@Serializable -@SerialName("tr_phase_bounce_negfunds") -public object TrPhaseBounceNegFunds : TrBouncePhase, - TlbConstructorProvider by TrPhaseBounceNegFundsTlbConstructor { - - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { - type("tr_phase_bounce_negfunds") - } - - override fun toString(): String = print().toString() -} - -private object TrPhaseBounceNegFundsTlbConstructor : TlbConstructor( - schema = "tr_phase_bounce_negfunds\$00 = TrBouncePhase;" -) { - override fun storeTlb(cellBuilder: CellBuilder, value: TrPhaseBounceNegFunds) = Unit - override fun loadTlb(cellSlice: CellSlice): TrPhaseBounceNegFunds = TrPhaseBounceNegFunds -} diff --git a/block-tlb/src/TrPhaseBounceNoFunds.kt b/block-tlb/src/TrPhaseBounceNoFunds.kt deleted file mode 100644 index 2bc5da6d..00000000 --- a/block-tlb/src/TrPhaseBounceNoFunds.kt +++ /dev/null @@ -1,50 +0,0 @@ -package org.ton.block - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice -import org.ton.cell.invoke -import org.ton.tlb.TlbConstructor -import org.ton.tlb.TlbPrettyPrinter -import org.ton.tlb.loadTlb -import org.ton.tlb.providers.TlbConstructorProvider -import org.ton.tlb.storeTlb - -@Serializable -@SerialName("tr_phase_bounce_nofunds") -public data class TrPhaseBounceNoFunds( - val msgSize: StorageUsedShort, - val reqFwdFees: Coins -) : TrBouncePhase { - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { - type("tr_phase_bounce_nofunds") { - field("msg_size", msgSize) - field("reqFwdFees", reqFwdFees) - } - } - - override fun toString(): String = print().toString() - - public companion object : TlbConstructorProvider by TrPhaseBounceNoFundsTlbConstructor -} - -private object TrPhaseBounceNoFundsTlbConstructor : TlbConstructor( - schema = "tr_phase_bounce_nofunds\$01 msg_size:StorageUsedShort req_fwd_fees:Coins = TrBouncePhase;" -) { - override fun storeTlb( - cellBuilder: CellBuilder, - value: TrPhaseBounceNoFunds - ) = cellBuilder { - storeTlb(StorageUsedShort, value.msgSize) - storeTlb(Coins, value.reqFwdFees) - } - - override fun loadTlb( - cellSlice: CellSlice - ): TrPhaseBounceNoFunds = cellSlice { - val msgSize = loadTlb(StorageUsedShort) - val coins = loadTlb(Coins) - TrPhaseBounceNoFunds(msgSize, coins) - } -} diff --git a/block-tlb/src/TrPhaseBounceOk.kt b/block-tlb/src/TrPhaseBounceOk.kt deleted file mode 100644 index a1764fc3..00000000 --- a/block-tlb/src/TrPhaseBounceOk.kt +++ /dev/null @@ -1,55 +0,0 @@ -package org.ton.block - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice -import org.ton.cell.invoke -import org.ton.tlb.TlbConstructor -import org.ton.tlb.TlbPrettyPrinter -import org.ton.tlb.loadTlb -import org.ton.tlb.providers.TlbConstructorProvider -import org.ton.tlb.storeTlb - -@Serializable -@SerialName("tr_phase_bounce_ok") -public data class TrPhaseBounceOk( - val msgSize: StorageUsedShort, - val msgFees: Coins, - val fwdFees: Coins -) : TrBouncePhase { - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { - type("tr_phase_bounce_ok") { - field("msg_size", msgSize) - field("msg_fees", msgFees) - field("fwd_fees", fwdFees) - } - } - - override fun toString(): String = print().toString() - - public companion object : TlbConstructorProvider by TrPhaseBounceOkTlbConstructor -} - -private object TrPhaseBounceOkTlbConstructor : TlbConstructor( - schema = "tr_phase_bounce_ok\$1 msg_size:StorageUsedShort msg_fees:Coins fwd_fees:Coins = TrBouncePhase;" -) { - - override fun storeTlb( - cellBuilder: CellBuilder, - value: TrPhaseBounceOk - ) = cellBuilder { - storeTlb(StorageUsedShort, value.msgSize) - storeTlb(Coins, value.msgFees) - storeTlb(Coins, value.fwdFees) - } - - override fun loadTlb( - cellSlice: CellSlice - ): TrPhaseBounceOk = cellSlice { - val msgSize = loadTlb(StorageUsedShort) - val msgFees = loadTlb(Coins) - val fwdFees = loadTlb(Coins) - TrPhaseBounceOk(msgSize, msgFees, fwdFees) - } -} diff --git a/block-tlb/src/TrPhaseComputeSkipped.kt b/block-tlb/src/TrPhaseComputeSkipped.kt index d727405c..15914d19 100644 --- a/block-tlb/src/TrPhaseComputeSkipped.kt +++ b/block-tlb/src/TrPhaseComputeSkipped.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -11,11 +10,11 @@ import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + @SerialName("tr_phase_compute_skipped") public data class TrPhaseComputeSkipped( val reason: ComputeSkipReason -) : TrComputePhase { +) : ComputePhase { override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { type("tr_phase_compute_skipped") { field("reason", reason) diff --git a/block-tlb/src/TrPhaseComputeVm.kt b/block-tlb/src/TrPhaseComputeVm.kt index 0567827b..30944a7a 100644 --- a/block-tlb/src/TrPhaseComputeVm.kt +++ b/block-tlb/src/TrPhaseComputeVm.kt @@ -1,16 +1,16 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.constructor.IntTlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("tr_phase_compute_vm") public data class TrPhaseComputeVm( val success: Boolean, @@ -18,7 +18,7 @@ public data class TrPhaseComputeVm( @SerialName("account_activated") val accountActivated: Boolean, @SerialName("gas_fees") val gasFees: Coins, val r1: CellRef -) : TrComputePhase { +) : ComputePhase { override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { type("tr_phase_compute_vm") { field("success", success) @@ -60,7 +60,7 @@ public object TrPhaseComputeVmTlbConstructor : TlbConstructor( } } -@Serializable + public data class TrComputePhaseAux( @SerialName("gas_used") val gasUsed: VarUInteger, @SerialName("gas_limit") val gasLimit: VarUInteger, diff --git a/block-tlb/src/TransMergeInstall.kt b/block-tlb/src/TransMergeInstall.kt deleted file mode 100644 index 14a93002..00000000 --- a/block-tlb/src/TransMergeInstall.kt +++ /dev/null @@ -1,81 +0,0 @@ -package org.ton.block - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice -import org.ton.cell.invoke -import org.ton.tlb.* -import org.ton.tlb.providers.TlbConstructorProvider - -@Serializable -@SerialName("trans_merge_install") -public data class TransMergeInstall( - @SerialName("split_info") val splitInfo: SplitMergeInfo, - @SerialName("prepare_transaction") val prepareTransaction: CellRef, - @SerialName("storage_ph") val storagePh: Maybe, - @SerialName("credit_ph") val creditPh: Maybe, - @SerialName("compute_ph") val computePh: TrComputePhase, - val action: Maybe>, - val aborted: Boolean, - val destroyed: Boolean -) : TransactionDescr { - public companion object : TlbConstructorProvider by TransMergeInstallTlbConstructor - - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { - type("trans_merge_install") { - field("split_info", splitInfo) - field("prepare_transaction", prepareTransaction) - field("storage_ph", storagePh) - field("credit_ph", creditPh) - field("compute_ph", computePh) - field("action", action) - field("aborted", aborted) - field("destroyed", destroyed) - } - } - - override fun toString(): String = print().toString() -} - -private object TransMergeInstallTlbConstructor : TlbConstructor( - schema = "trans_merge_install\$0111 split_info:SplitMergeInfo\n" + - " prepare_transaction:^Transaction\n" + - " storage_ph:(Maybe TrStoragePhase)\n" + - " credit_ph:(Maybe TrCreditPhase)\n" + - " compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)\n" + - " aborted:Bool destroyed:Bool\n" + - " = TransactionDescr;" -) { - val maybeTrStoragePhase = Maybe.tlbCodec(TrStoragePhase) - val maybeTrCreditPhase = Maybe.tlbCodec(TrCreditPhase) - val maybeTrActionPhase = Maybe.tlbCodec(CellRef(TrActionPhase)) - - override fun storeTlb( - cellBuilder: CellBuilder, - value: TransMergeInstall - ) = cellBuilder { - storeTlb(SplitMergeInfo, value.splitInfo) - storeRef(Transaction, value.prepareTransaction) - storeTlb(maybeTrStoragePhase, value.storagePh) - storeTlb(maybeTrCreditPhase, value.creditPh) - storeTlb(TrComputePhase, value.computePh) - storeTlb(maybeTrActionPhase, value.action) - storeBit(value.aborted) - storeBit(value.destroyed) - } - - override fun loadTlb( - cellSlice: CellSlice - ): TransMergeInstall = cellSlice { - val splitInfo = loadTlb(SplitMergeInfo) - val prepareTransaction = loadRef(Transaction) - val storagePh = loadTlb(maybeTrStoragePhase) - val creditPh = loadTlb(maybeTrCreditPhase) - val computePh = loadTlb(TrComputePhase) - val action = loadTlb(maybeTrActionPhase) - val aborted = loadBit() - val destroyed = loadBit() - TransMergeInstall(splitInfo, prepareTransaction, storagePh, creditPh, computePh, action, aborted, destroyed) - } -} diff --git a/block-tlb/src/TransMergePrepare.kt b/block-tlb/src/TransMergePrepare.kt deleted file mode 100644 index 1ff70415..00000000 --- a/block-tlb/src/TransMergePrepare.kt +++ /dev/null @@ -1,56 +0,0 @@ -package org.ton.block - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice -import org.ton.cell.invoke -import org.ton.tlb.TlbConstructor -import org.ton.tlb.TlbPrettyPrinter -import org.ton.tlb.loadTlb -import org.ton.tlb.providers.TlbConstructorProvider -import org.ton.tlb.storeTlb - -@Serializable -@SerialName("trans_merge_prepare") -public data class TransMergePrepare( - @SerialName("split_info") val splitInfo: SplitMergeInfo, - @SerialName("storage_ph") val storagePh: TrStoragePhase, - val aborted: Boolean -) : TransactionDescr { - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { - type("trans_merge_prepare") { - field("split_info", splitInfo) - field("storage_ph", storagePh) - field("aborted", aborted) - } - } - - override fun toString(): String = print().toString() - - public companion object : TlbConstructorProvider by TransMergePrepareTlbConstructor -} - -private object TransMergePrepareTlbConstructor : TlbConstructor( - schema = "trans_merge_prepare\$0110 split_info:SplitMergeInfo\n" + - " storage_ph:TrStoragePhase aborted:Bool\n" + - " = TransactionDescr;" -) { - override fun storeTlb( - cellBuilder: CellBuilder, - value: TransMergePrepare - ) = cellBuilder { - storeTlb(SplitMergeInfo, value.splitInfo) - storeTlb(TrStoragePhase, value.storagePh) - storeBit(value.aborted) - } - - override fun loadTlb( - cellSlice: CellSlice - ): TransMergePrepare = cellSlice { - val splitInfo = loadTlb(SplitMergeInfo) - val storagePh = loadTlb(TrStoragePhase) - val aborted = loadBit() - TransMergePrepare(splitInfo, storagePh, aborted) - } -} diff --git a/block-tlb/src/TransOrd.kt b/block-tlb/src/TransOrd.kt deleted file mode 100644 index cf386a0a..00000000 --- a/block-tlb/src/TransOrd.kt +++ /dev/null @@ -1,88 +0,0 @@ -package org.ton.block - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice -import org.ton.cell.invoke -import org.ton.tlb.* -import org.ton.tlb.providers.TlbConstructorProvider - -@SerialName("trans_ord") -@Serializable -public data class TransOrd( - @SerialName("credit_first") val creditFirst: Boolean, - @SerialName("storage_ph") val storagePh: Maybe, - @SerialName("credit_ph") val creditPh: Maybe, - @SerialName("compute_ph") val computePh: TrComputePhase, - val action: Maybe>, - val aborted: Boolean, - val bounce: Maybe, - val destroyed: Boolean -) : TransactionDescr { - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter { - return printer { - type("trans_ord") { - field("credit_first", creditFirst) - field("storage_ph", storagePh) - field("credit_ph", creditPh) - field("compute_ph", computePh) - field("action", action) - field("aborted", aborted) - field("bounce", bounce) - field("destroyed", destroyed) - } - } - } - - override fun toString(): String = print().toString() - - public companion object : TlbConstructorProvider by TransOrdTlbConstructor -} - -private object TransOrdTlbConstructor : TlbConstructor( - schema = "trans_ord\$0000 credit_first:Bool " + - "storage_ph:(Maybe TrStoragePhase) " + - "credit_ph:(Maybe TrCreditPhase) " + - "compute_ph:TrComputePhase " + - "action:(Maybe ^TrActionPhase) " + - "aborted:Bool " + - "bounce:(Maybe TrBouncePhase) " + - "destroyed:Bool " + - "= TransactionDescr;" -) { - val maybeTrStoragePhase = Maybe.tlbCodec(TrStoragePhase) - val maybeTrCreditPhase = Maybe.tlbCodec(TrCreditPhase) - val maybeTrActionPhase = Maybe.tlbCodec(CellRef.tlbCodec(TrActionPhase)) - val maybeTrBouncePhase = Maybe.tlbCodec(TrBouncePhase) - - override fun storeTlb( - cellBuilder: CellBuilder, - value: TransOrd - ) = cellBuilder { - storeBit(value.creditFirst) - storeTlb(maybeTrStoragePhase, value.storagePh) - storeTlb(maybeTrCreditPhase, value.creditPh) - storeTlb(TrComputePhase, value.computePh) - storeTlb(maybeTrActionPhase, value.action) - storeBit(value.aborted) - storeTlb(maybeTrBouncePhase, value.bounce) - storeBit(value.destroyed) - } - - override fun loadTlb( - cellSlice: CellSlice - ): TransOrd = cellSlice { - val creditFirst = loadBit() - val storagePh = loadTlb(maybeTrStoragePhase) - val creditPh = loadTlb(maybeTrCreditPhase) - val computePh = loadTlb(TrComputePhase) - val action = loadTlb(maybeTrActionPhase) - val aborted = loadBit() - val bounce = loadTlb(maybeTrBouncePhase) - val destroyed = loadBit() - TransOrd( - creditFirst, storagePh, creditPh, computePh, action, aborted, bounce, destroyed - ) - } -} diff --git a/block-tlb/src/TransSplitInstall.kt b/block-tlb/src/TransSplitInstall.kt deleted file mode 100644 index f054ae11..00000000 --- a/block-tlb/src/TransSplitInstall.kt +++ /dev/null @@ -1,55 +0,0 @@ -package org.ton.block - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice -import org.ton.cell.invoke -import org.ton.tlb.* -import org.ton.tlb.providers.TlbConstructorProvider - -@Serializable -@SerialName("trans_split_install") -public data class TransSplitInstall( - @SerialName("split_info") val splitInfo: SplitMergeInfo, - @SerialName("prepare_transaction") val prepareTransaction: CellRef, - val installed: Boolean -) : TransactionDescr { - public companion object : TlbConstructorProvider by TransSplitInstallTlbConstructor - - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter { - return printer { - type("trans_split_install") { - field("split_info", splitInfo) - field("prepare_transaction", prepareTransaction) - field("installed", installed) - } - } - } - - override fun toString(): String = print().toString() -} - -private object TransSplitInstallTlbConstructor : TlbConstructor( - schema = "trans_split_install\$0101 split_info:SplitMergeInfo\n" + - " prepare_transaction:^Transaction\n" + - " installed:Bool = TransactionDescr;" -) { - override fun storeTlb( - cellBuilder: CellBuilder, - value: TransSplitInstall - ) = cellBuilder { - storeTlb(SplitMergeInfo, value.splitInfo) - storeRef(Transaction, value.prepareTransaction) - storeBit(value.installed) - } - - override fun loadTlb( - cellSlice: CellSlice - ): TransSplitInstall = cellSlice { - val splitInfo = loadTlb(SplitMergeInfo) - val prepareTransaction = loadRef(Transaction) - val installed = loadBit() - TransSplitInstall(splitInfo, prepareTransaction, installed) - } -} diff --git a/block-tlb/src/TransSplitPrepare.kt b/block-tlb/src/TransSplitPrepare.kt deleted file mode 100644 index 4905e9f7..00000000 --- a/block-tlb/src/TransSplitPrepare.kt +++ /dev/null @@ -1,72 +0,0 @@ -package org.ton.block - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice -import org.ton.cell.invoke -import org.ton.tlb.* -import org.ton.tlb.providers.TlbConstructorProvider - -@Serializable -@SerialName("trans_split_prepare") -public data class TransSplitPrepare( - val splitInfo: SplitMergeInfo, - val storagePh: Maybe, - val computePh: TrComputePhase, - val action: Maybe>, - val aborted: Boolean, - val destroyed: Boolean -) : TransactionDescr { - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { - type("trans_split_prepare") { - field("split_info", splitInfo) - field("storage_ph", storagePh) - field("compute_ph", computePh) - field("action", action) - field("aborted", aborted) - field("destroyed", destroyed) - } - } - - override fun toString(): String = print().toString() - - public companion object : TlbConstructorProvider by TransSplitPrepareTlbConstructor -} - -private object TransSplitPrepareTlbConstructor : TlbConstructor( - schema = "trans_split_prepare\$0100 " + - " split_info:SplitMergeInfo\n" + - " storage_ph:(Maybe TrStoragePhase)\n" + - " compute_ph:TrComputePhase " + - " action:(Maybe ^TrActionPhase)\n" + - " aborted:Bool destroyed:Bool\n" + - " = TransactionDescr;" -) { - val maybeTrStoragePhase = Maybe(TrStoragePhase) - val maybeTrActionPhase = Maybe(CellRef(TrActionPhase)) - - override fun storeTlb( - cellBuilder: CellBuilder, - value: TransSplitPrepare - ) = cellBuilder { - storeTlb(SplitMergeInfo, value.splitInfo) - storeTlb(maybeTrStoragePhase, value.storagePh) - storeTlb(TrComputePhase, value.computePh) - storeTlb(maybeTrActionPhase, value.action) - storeBit(value.aborted) - storeBit(value.destroyed) - } - - override fun loadTlb( - cellSlice: CellSlice - ): TransSplitPrepare = cellSlice { - val splitInfo = loadTlb(SplitMergeInfo) - val storagePh = loadTlb(maybeTrStoragePhase) - val computePh = loadTlb(TrComputePhase) - val action = loadTlb(maybeTrActionPhase) - val aborted = loadBit() - val destroyed = loadBit() - TransSplitPrepare(splitInfo, storagePh, computePh, action, aborted, destroyed) - } -} diff --git a/block-tlb/src/TransStorage.kt b/block-tlb/src/TransStorage.kt deleted file mode 100644 index 2820a186..00000000 --- a/block-tlb/src/TransStorage.kt +++ /dev/null @@ -1,47 +0,0 @@ -package org.ton.block - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice -import org.ton.cell.invoke -import org.ton.tlb.TlbConstructor -import org.ton.tlb.TlbPrettyPrinter -import org.ton.tlb.loadTlb -import org.ton.tlb.providers.TlbConstructorProvider -import org.ton.tlb.storeTlb - -@Serializable -@SerialName("trans_storage") -public data class TransStorage( - @SerialName("storage_ph") val storagePh: TrStoragePhase -) : TransactionDescr { - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { - type("storage_ph") { - field("storage_ph", storagePh) - } - } - - override fun toString(): String = print().toString() - - public companion object : TlbConstructorProvider by TransStorageTlbConstructor -} - -private object TransStorageTlbConstructor : TlbConstructor( - schema = "trans_storage\$0001 storage_ph:TrStoragePhase = TransactionDescr;" -) { - - override fun storeTlb( - cellBuilder: CellBuilder, - value: TransStorage - ) = cellBuilder { - storeTlb(TrStoragePhase, value.storagePh) - } - - override fun loadTlb( - cellSlice: CellSlice - ): TransStorage = cellSlice { - val storagePh = loadTlb(TrStoragePhase) - TransStorage(storagePh) - } -} diff --git a/block-tlb/src/TransTickTock.kt b/block-tlb/src/TransTickTock.kt deleted file mode 100644 index f91ebf6b..00000000 --- a/block-tlb/src/TransTickTock.kt +++ /dev/null @@ -1,67 +0,0 @@ -package org.ton.block - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice -import org.ton.cell.invoke -import org.ton.tlb.* -import org.ton.tlb.providers.TlbConstructorProvider - -@Serializable -@SerialName("trans_tick_tock") -public data class TransTickTock( - @SerialName("is_tock") val isTock: Boolean, - @SerialName("storage_ph") val storagePh: TrStoragePhase, - @SerialName("compute_ph") val computePh: TrComputePhase, - val action: Maybe>, - val aborted: Boolean, - val destroyed: Boolean -) : TransactionDescr { - override fun toString(): String = print().toString() - - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { - type("trans_tick_tock") { - field("is_tock", isTock) - field("storage_ph", storagePh) - field("compute_ph", computePh) - field("action", action) - field("aborted", aborted) - field("destroyed", destroyed) - } - } - - public companion object : TlbConstructorProvider by TransTickTockTlbConstructor -} - -private object TransTickTockTlbConstructor : TlbConstructor( - schema = "trans_tick_tock\$001 is_tock:Bool storage_ph:TrStoragePhase\n" + - " compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)\n" + - " aborted:Bool destroyed:Bool = TransactionDescr;" -) { - val maybeTrActionPhase = Maybe.tlbCodec(CellRef.tlbCodec(TrActionPhase)) - - override fun storeTlb( - cellBuilder: CellBuilder, - value: TransTickTock - ) = cellBuilder { - storeBit(value.isTock) - storeTlb(TrStoragePhase, value.storagePh) - storeTlb(TrComputePhase, value.computePh) - storeTlb(maybeTrActionPhase, value.action) - storeBit(value.aborted) - storeBit(value.destroyed) - } - - override fun loadTlb( - cellSlice: CellSlice - ): TransTickTock = cellSlice { - val isTock = loadBit() - val storagePh = loadTlb(TrStoragePhase) - val computePh = loadTlb(TrComputePhase) - val action = loadTlb(maybeTrActionPhase) - val aborted = loadBit() - val destroyed = loadBit() - TransTickTock(isTock, storagePh, computePh, action, aborted, destroyed) - } -} diff --git a/block-tlb/src/Transaction.kt b/block-tlb/src/Transaction.kt index 66f9736e..0427cfc6 100644 --- a/block-tlb/src/Transaction.kt +++ b/block-tlb/src/Transaction.kt @@ -1,197 +1,162 @@ package org.ton.block -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.ton.bitstring.BitString -import org.ton.cell.Cell +import kotlinx.io.bytestring.ByteString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice -import org.ton.cell.invoke -import org.ton.hashmap.HashMapE -import org.ton.tlb.* -import org.ton.tlb.providers.TlbCombinatorProvider -import org.ton.tlb.providers.TlbConstructorProvider -import kotlin.jvm.JvmName - -@Serializable -@SerialName("transaction") +import org.ton.cell.loadRef +import org.ton.cell.storeRef +import org.ton.kotlin.cell.CellContext +import org.ton.kotlin.dict.Dictionary +import org.ton.kotlin.dict.DictionaryKeyCodec +import org.ton.tlb.CellRef +import org.ton.tlb.TlbCodec +import org.ton.tlb.constructor.RemainingTlbCodec + +/** + * Blockchain transaction. + */ public data class Transaction( - @SerialName("account_addr") - @get:JvmName("accountAddr") - val accountAddr: BitString, // account_addr : bits256 - - @SerialName("lt") - @get:JvmName("lt") - val lt: ULong, // lt : uint64 - - @SerialName("prev_trans_hash") - @get:JvmName("prevTransHash") - val prevTransHash: BitString, // prev_trans_hash : bits256 - - @SerialName("prev_trans_lt") - @get:JvmName("prevTransLt") - val prevTransLt: ULong, // prev_trans_lt : uint64 - - @SerialName("now") - @get:JvmName("now") - val now: UInt, // now : uint32 - - @SerialName("outmsg_cnt") - @get:JvmName("outMsgCnt") - val outMsgCnt: Int, // outmsg_cnt : uint15 - - @SerialName("orig_status") - @get:JvmName("origStatus") - val origStatus: AccountStatus, // orig_status : AccountStatus - - @SerialName("end_status") - @get:JvmName("endStatus") - val endStatus: AccountStatus, // end_status : AccountStatus - - @get:JvmName("r1") - val r1: CellRef, // r1 : Aux - - @SerialName("total_fees") - @get:JvmName("totalFees") - val totalFees: CurrencyCollection, // total_fees : CurrencyCollection - - @SerialName("state_update") - @get:JvmName("stateUpdate") - val stateUpdate: CellRef, // state_update : ^HashUpdate - - @SerialName("description") - @get:JvmName("description") - val description: CellRef // description : ^TransactionDescr -) : TlbObject { + /** + * Account on which this transaction was produced. + */ + val account: ByteString, + + /** + * Logical time when the transaction was created. + */ + val lt: Long, + + /** + * The hash of the previous transaction on the same account. + */ + val prevTransactionHash: ByteString, + + /** + * The logical time of the previous transaction on the same account. + */ + val prevTransactionLt: Long, + + /** + * Unix timestamp in seconds when the transaction was created. + */ + val now: Long, + + /** + * The number of outgoing messages. + */ + val outMsgCount: Int, + + /** + * Account status before this transaction. + */ + val originalStatus: AccountStatus, + + /** + * Account status after this transaction. + */ + val endStatus: AccountStatus, + + /** + * Optional incoming message. + */ + val inMsg: CellRef>?, + + /** + * Outgoing messages. + */ + val outMsg: Dictionary>>, + + /** + * Total transaction fees (including extra fwd fees). + */ + val totalFees: CurrencyCollection, + + /** + * Account state hashes. + */ + val hashUpdate: CellRef, + + /** + * Detailed transaction info. + */ + val info: CellRef +) { init { - require(accountAddr.size == 256) { "expected accountAddr.size == 256, actual: ${accountAddr.size}" } - require(prevTransHash.size == 256) { "expected prevTransHash.size == 256, actual: ${accountAddr.size}" } + require(account.size == 32) { "Account size should be 32 bytes" } + require(prevTransactionHash.size == 32) { "Prev transaction hash should be 32 bytes" } } - public fun toCell(): Cell = CellBuilder.createCell { - storeTlb(Transaction, this@Transaction) + public fun loadInMessage(context: CellContext = CellContext.EMPTY): Message? { + return inMsg?.load(context) } - public fun hash(): BitString = toCell().hash() - - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { - type("transaction") { - field("account_addr", accountAddr) - field("lt", lt) - field("prev_trans_hash", prevTransHash) - field("prev_trans_lt", prevTransLt) - field("now", now) - field("outmsg_cnt", outMsgCnt) - field("orig_status", origStatus) - field("end_status", endStatus) - field(r1) - field("total_fees", totalFees) - field("state_update", stateUpdate) - field("description", description) - } + public fun loadInfo(context: CellContext = CellContext.EMPTY): TransactionInfo { + return info.load(context) } - override fun toString(): String = print().toString() - - public companion object : TlbCombinatorProvider by TransactionTlConstructor.asTlbCombinator() + public companion object : TlbCodec by TransactionCodec } -@Serializable -public data class TransactionAux( - @SerialName("in_msg") - @get:JvmName("inMsg") - val inMsg: Maybe>>, - - @SerialName("out_msgs") - @get:JvmName("outMsgs") - val outMsgs: HashMapE>>, -) : TlbObject { - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter { - return printer.type { - field("in_msg", inMsg) - field("out_msgs", outMsgs) +private object TransactionCodec : TlbCodec { + private val int15keyCodec = DictionaryKeyCodec.int(15) + private val refMessageCodec = CellRef.tlbCodec(Message.tlbCodec(RemainingTlbCodec)) + + override fun storeTlb(builder: CellBuilder, value: Transaction, context: CellContext) { + builder.storeUInt(0b0111, 4) + builder.storeByteString(value.account) + builder.storeLong(value.lt) + builder.storeByteString(value.prevTransactionHash) + builder.storeLong(value.prevTransactionLt) + builder.storeLong(value.now, 32) + builder.storeUInt(value.outMsgCount, 15) + AccountStatus.storeTlb(builder, value.originalStatus, context) + AccountStatus.storeTlb(builder, value.endStatus, context) + builder.storeRef(context) { + storeNullableRef(value.inMsg?.cell) + storeNullableRef(value.outMsg.cell) } + CurrencyCollection.storeTlb(builder, value.totalFees, context) + builder.storeRef(value.hashUpdate.cell) + builder.storeRef(value.info.cell) } - override fun toString(): String = print().toString() - - public companion object : TlbConstructorProvider by TransactionAuxTlbConstructor -} - -private object TransactionTlConstructor : TlbConstructor( - schema = "transaction\$0111 " + - " account_addr:bits256 " + - " lt:uint64 " + - " prev_trans_hash:bits256 " + - " prev_trans_lt:uint64 " + - " now:uint32 " + - " outmsg_cnt:uint15 " + - " orig_status:AccountStatus " + - " end_status:AccountStatus " + - " ^[ in_msg:(Maybe ^(Message Any)) out_msgs:(HashmapE 15 ^(Message Any)) ] " + - " total_fees:CurrencyCollection state_update:^(HASH_UPDATE Account) " + - " description:^TransactionDescr = Transaction;" -) { - override fun loadTlb(cellSlice: CellSlice): Transaction = cellSlice { - val accountAddr = loadBits(256) - val lt = loadUInt64() - val prevTransHash = loadBits(256) - val prevTransLt = loadUInt64() - val now = loadUInt32() - val outmsgCnt = loadUInt(15).toInt() - val origStatus = loadTlb(AccountStatus) - val endStatus = loadTlb(AccountStatus) - val r1 = loadRef(TransactionAux) - val totalFees = loadTlb(CurrencyCollection) - val stateUpdate = loadRef(HashUpdate) - val description = loadRef(TransactionDescr) - Transaction( - accountAddr, + override fun loadTlb(slice: CellSlice, context: CellContext): Transaction { + val tag = slice.loadUInt(4).toInt() + require(tag == 0b0111) { + "Invalid transaction tag: $tag" + } + val account = slice.loadByteString(32) + val lt = slice.loadLong() + val prevTransactionHash = slice.loadByteString(32) + val prevTransactionLt = slice.loadLong() + val now = slice.loadLong(32) + val outMsgCount = slice.loadUInt(15).toInt() + val originalStatus = AccountStatus.loadTlb(slice, context) + val endStatus = AccountStatus.loadTlb(slice, context) + val inMsg: CellRef>? + val outMsg: Dictionary>> + slice.loadRef(context) { + inMsg = loadNullableRef()?.let { ref -> CellRef(ref, Message.tlbCodec(RemainingTlbCodec)) } + outMsg = Dictionary(loadNullableRef(), int15keyCodec, refMessageCodec, context) + } + val totalFees = CurrencyCollection.loadTlb(slice, context) + val hashUpdate = CellRef(slice.loadRef(), HashUpdate) + val info = CellRef(slice.loadRef(), TransactionInfo) + return Transaction( + account, lt, - prevTransHash, - prevTransLt, + prevTransactionHash, + prevTransactionLt, now, - outmsgCnt, - origStatus, + outMsgCount, + originalStatus, endStatus, - r1, + inMsg, + outMsg, totalFees, - stateUpdate, - description + hashUpdate, + info ) } - - override fun storeTlb(cellBuilder: CellBuilder, value: Transaction) = cellBuilder { - storeBits(value.accountAddr) - storeUInt64(value.lt) - storeBits(value.prevTransHash) - storeUInt64(value.prevTransLt) - storeUInt32(value.now) - storeUInt(value.outMsgCnt, 15) - storeTlb(AccountStatus, value.origStatus) - storeTlb(AccountStatus, value.endStatus) - storeRef(TransactionAux, value.r1) - storeTlb(CurrencyCollection, value.totalFees) - storeRef(HashUpdate, value.stateUpdate) - storeRef(TransactionDescr, value.description) - } } -private object TransactionAuxTlbConstructor : TlbConstructor( - schema = "\$_ in_msg:(Maybe ^(Message Any)) out_msgs:(HashmapE 15 ^(Message Any)) " -) { - val maybeMessage = Maybe.tlbCodec(CellRef.tlbCodec(Message.Any)) - val outMsgs = HashMapE.tlbCodec(15, CellRef.tlbCodec(Message.Any)) - - override fun storeTlb(cellBuilder: CellBuilder, value: TransactionAux) = cellBuilder { - storeTlb(maybeMessage, value.inMsg) - storeTlb(outMsgs, value.outMsgs) - } - - override fun loadTlb(cellSlice: CellSlice): TransactionAux = cellSlice { - TransactionAux( - inMsg = loadTlb(maybeMessage), - outMsgs = loadTlb(outMsgs) - ) - } -} diff --git a/block-tlb/src/TransactionDescr.kt b/block-tlb/src/TransactionDescr.kt deleted file mode 100644 index 1500d4d6..00000000 --- a/block-tlb/src/TransactionDescr.kt +++ /dev/null @@ -1,26 +0,0 @@ -@file:Suppress("OPT_IN_USAGE") - -package org.ton.block - -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonClassDiscriminator -import org.ton.tlb.TlbCombinator -import org.ton.tlb.TlbObject -import org.ton.tlb.providers.TlbCombinatorProvider - -@JsonClassDiscriminator("@type") -@Serializable -public sealed interface TransactionDescr : TlbObject { - public companion object : TlbCombinatorProvider by TransactionDescrTlbCombinator -} - -private object TransactionDescrTlbCombinator : TlbCombinator( - TransactionDescr::class, - TransOrd::class to TransOrd.tlbConstructor(), - TransStorage::class to TransStorage.tlbConstructor(), - TransTickTock::class to TransTickTock.tlbConstructor(), - TransMergeInstall::class to TransMergeInstall.tlbConstructor(), - TransMergePrepare::class to TransMergePrepare.tlbConstructor(), - TransSplitInstall::class to TransSplitInstall.tlbConstructor(), - TransSplitPrepare::class to TransSplitPrepare.tlbConstructor(), -) diff --git a/block-tlb/src/TransactionInfo.kt b/block-tlb/src/TransactionInfo.kt new file mode 100644 index 00000000..c506797f --- /dev/null +++ b/block-tlb/src/TransactionInfo.kt @@ -0,0 +1,378 @@ +@file:Suppress("OPT_IN_USAGE") + +package org.ton.block + +import org.ton.cell.CellBuilder +import org.ton.cell.CellSlice +import org.ton.cell.storeRef +import org.ton.tlb.* + +/** + * Detailed transaction info. + * + * @see [Transaction] + */ +public sealed interface TransactionInfo { + /** + * Storage phase info. + */ + public val storagePhase: StoragePhase? + + /** + * Credit phase info. + */ + public val creditPhase: CreditPhase? + + /** + * Compute phase info. + */ + public val computePhase: ComputePhase? + + /** + * Action phase info. + */ + public val actionPhase: ActionPhase? + + /** + * Bounce phase info. + * + * Only present in [Ordinary] transaction and if the incoming [Message] had `bounce: true` and + * the compute phase failed. + */ + public val bouncePhase: BouncePhase? + + /** + * Ordinary transaction info. + */ + public data class Ordinary( + /** + * Whether the credit phase was executed first + * + * (usually set when incoming message has `bounce: false`). + */ + val isCreditFirst: Boolean, + + /** + * Storage phase info. + * + * Skipped if the account did not exist prior to execution. + */ + override val storagePhase: StoragePhase?, + + /** + * Credit phase info. + * + * Skipped if the incoming message is external. + */ + override val creditPhase: CreditPhase?, + + /** + * Compute phase info. + */ + override val computePhase: ComputePhase, + + /** + * Action phase info. + * + * Skipped if the transaction was aborted at the compute phase. + */ + override val actionPhase: ActionPhase?, + + /** + * Whether the transaction was reverted. + */ + val isAborted: Boolean, + + /** + * Bounce phase info. + * + * Only present if the incoming message had `bounce: true` and + * the compute phase failed. + */ + override val bouncePhase: BouncePhase?, + + /** + * Whether the account was destroyed during this transaction. + */ + val isDestroyed: Boolean + ) : TransactionInfo + + /** + * Tick-Tock transaction info + */ + public data class TickTock( + val isTock: Boolean, + + /** + * Storage phase info. + */ + override val storagePhase: StoragePhase, + + /** + * Compute phase info. + */ + override val computePhase: ComputePhase, + + /** + * Action phase info. + * + * Skipped if the transaction was aborted at the compute phase. + */ + override val actionPhase: ActionPhase?, + + /** + * Whether the transaction was reverted. + */ + val isAborted: Boolean, + + /** + * Whether the account was destroyed during this transaction. + */ + val isDestroyed: Boolean + ) : TransactionInfo { + val isTick: Boolean get() = !isTock + override val creditPhase: CreditPhase? get() = null + override val bouncePhase: BouncePhase? get() = null + } + + /** + * Storage transaction info + * + * **Currently, not implemented in TON Blockchain** + */ + @Deprecated("Not implemented in TON Blockchain") + public data class Storage( + /** + * Storage phase info. + */ + override val storagePhase: StoragePhase, + ) : TransactionInfo { + override val creditPhase: CreditPhase? get() = null + override val computePhase: ComputePhase? get() = null + override val actionPhase: ActionPhase? get() = null + override val bouncePhase: BouncePhase? get() = null + } + + /** + * Split prepare transaction info. + * + * **Currently, not implemented in TON Blockchain** + */ + @Deprecated("Not implemented in TON Blockchain") + public data class SplitPrepare( + val splitInfo: SplitMergeInfo, + override val storagePhase: StoragePhase?, + override val computePhase: ComputePhase, + override val actionPhase: ActionPhase?, + val isAborted: Boolean, + val isDestroyed: Boolean + ) : TransactionInfo { + override val creditPhase: CreditPhase? get() = null + override val bouncePhase: BouncePhase? get() = null + } + + /** + * Split install transaction info. + * + * **Currently, not implemented in TON Blockchain** + */ + @Deprecated("Not implemented in TON Blockchain") + public data class SplitInstall( + val splitInfo: SplitMergeInfo, + val prepareTransaction: CellRef, + val isInstalled: Boolean, + ) : TransactionInfo { + override val storagePhase: StoragePhase? get() = null + override val creditPhase: CreditPhase? get() = null + override val computePhase: ComputePhase? get() = null + override val actionPhase: ActionPhase? get() = null + override val bouncePhase: BouncePhase? get() = null + } + + /** + * Merge-prepare transaction info. + * + * **Currently, not implemented in TON Blockchain** + */ + @Deprecated("Not implemented in TON Blockchain") + public data class MergePrepare( + val splitInfo: SplitMergeInfo, + override val storagePhase: StoragePhase, + val isAborted: Boolean, + ) : TransactionInfo { + override val creditPhase: CreditPhase? get() = null + override val computePhase: ComputePhase? get() = null + override val actionPhase: ActionPhase? get() = null + override val bouncePhase: BouncePhase? get() = null + } + + /** + * Merge-install transaction info. + * + * **Currently, not implemented in TON Blockchain** + */ + @Deprecated("Not implemented in TON Blockchain") + public data class MergeInstall( + val splitInfo: SplitMergeInfo, + val prepareTransaction: CellRef, + override val storagePhase: StoragePhase?, + override val creditPhase: CreditPhase?, + override val computePhase: ComputePhase, + override val actionPhase: ActionPhase?, + val isAborted: Boolean, + val isDestroyed: Boolean + ) : TransactionInfo { + override val bouncePhase: BouncePhase? get() = null + } + + public companion object : TlbCodec by TransactionInfoCodec +} + +private object TransactionInfoCodec : TlbCodec { + private val maybeStoragePhase = StoragePhase.asNullable() + private val maybeCreditPhase = CreditPhase.asNullable() + private val maybeRefActionPhase = CellRef.tlbCodec(ActionPhase).asNullable() + private val maybeBouncePhase = BouncePhase.asNullable() + + @Suppress("DEPRECATION") + override fun storeTlb(builder: CellBuilder, value: TransactionInfo) { + when (value) { + is TransactionInfo.Ordinary -> { // trans_ord$0000 + builder.storeUInt(0b0000, 4) + builder.storeBoolean(value.isCreditFirst) + builder.storeTlb(maybeStoragePhase, value.storagePhase) + builder.storeTlb(maybeCreditPhase, value.creditPhase) + builder.storeTlb(ComputePhase, value.computePhase) + val actionPhase = value.actionPhase + if (actionPhase != null) { + builder.storeBoolean(true) + builder.storeRef { + storeTlb(ActionPhase, actionPhase) + } + } else { + builder.storeBoolean(false) + } + builder.storeBoolean(value.isAborted) + builder.storeTlb(maybeBouncePhase, value.bouncePhase) + builder.storeBoolean(value.isDestroyed) + } + + is TransactionInfo.TickTock -> TODO() + is TransactionInfo.MergeInstall -> TODO() + is TransactionInfo.MergePrepare -> TODO() + is TransactionInfo.SplitInstall -> TODO() + is TransactionInfo.SplitPrepare -> TODO() + is TransactionInfo.Storage -> TODO() + } + } + + @Suppress("DEPRECATION") + override fun loadTlb(slice: CellSlice): TransactionInfo { + when (val tag = getTag(slice)) { + 0b0000 -> { // trans_ord$0000 + slice.bitsPosition += 4 + val isCreditFirst = slice.loadBoolean() + val storagePhase = slice.loadTlb(maybeStoragePhase) + val creditPhase = slice.loadTlb(maybeCreditPhase) + val computePhase = slice.loadTlb(ComputePhase) + val actionPhase = slice.loadTlb(maybeRefActionPhase)?.load() + val isAborted = slice.loadBoolean() + val bouncePhase = slice.loadTlb(maybeBouncePhase) + println("bounce: $bouncePhase") + val isDestroyed = slice.loadBoolean() + return TransactionInfo.Ordinary( + isCreditFirst, + storagePhase, + creditPhase, + computePhase, + actionPhase, + isAborted, + bouncePhase, + isDestroyed + ) + } + + 0b0001 -> { // trans_storage$0001 + slice.bitsPosition += 4 + val storagePhase = slice.loadTlb(StoragePhase) + return TransactionInfo.Storage(storagePhase) + } + + 0b0010 -> { // trans_tick_tock$001 + slice.bitsPosition += 3 + val isTock = slice.loadBoolean() + val storagePhase = slice.loadTlb(StoragePhase) + val computePhase = slice.loadTlb(ComputePhase) + val actionPhase = slice.loadTlb(maybeRefActionPhase)?.load() + val isAborted = slice.loadBoolean() + val isDestroyed = slice.loadBoolean() + return TransactionInfo.TickTock(isTock, storagePhase, computePhase, actionPhase, isAborted, isDestroyed) + } + + 0b0100 -> { // trans_split_prepare$0100 + slice.bitsPosition += 4 + val splitInfo = slice.loadTlb(SplitMergeInfo) + val storagePhase = slice.loadTlb(maybeStoragePhase) + val computePhase = slice.loadTlb(ComputePhase) + val actionPhase = slice.loadTlb(maybeRefActionPhase)?.load() + val isAborted = slice.loadBoolean() + val isDestroyed = slice.loadBoolean() + return TransactionInfo.SplitPrepare( + splitInfo, + storagePhase, + computePhase, + actionPhase, + isAborted, + isDestroyed + ) + } + + 0b0101 -> { // trans_split_install$0101 + slice.bitsPosition += 4 + val splitInfo = slice.loadTlb(SplitMergeInfo) + val prepareTransaction = CellRef(slice.loadRef(), Transaction) + val isInstalled = slice.loadBoolean() + return TransactionInfo.SplitInstall(splitInfo, prepareTransaction, isInstalled) + } + + 0b0110 -> { // trans_merge_prepare$0110 + slice.bitsPosition += 4 + val splitInfo = slice.loadTlb(SplitMergeInfo) + val storagePhase = slice.loadTlb(StoragePhase) + val isAborted = slice.loadBoolean() + return TransactionInfo.MergePrepare(splitInfo, storagePhase, isAborted) + } + + 0b0111 -> { // trans_merge_install$0111 + slice.bitsPosition += 4 + val splitInfo = slice.loadTlb(SplitMergeInfo) + val prepareTransaction = CellRef(slice.loadRef(), Transaction) + val storagePhase = slice.loadTlb(maybeStoragePhase) + val creditPhase = slice.loadTlb(maybeCreditPhase) + val computePhase = slice.loadTlb(ComputePhase) + val actionPhase = slice.loadTlb(maybeRefActionPhase)?.load() + val isAborted = slice.loadBoolean() + val isDestroyed = slice.loadBoolean() + return TransactionInfo.MergeInstall( + splitInfo, + prepareTransaction, + storagePhase, + creditPhase, + computePhase, + actionPhase, + isAborted, + isDestroyed + ) + } + + else -> throw IllegalArgumentException("Invalid transaction info tag: $tag") + } + } + + private fun getTag(slice: CellSlice): Int = slice.bitSelect(4, 0xF7) + + private fun CellSlice.bitSelect(bitCount: Int, mask: Int): Int { + val n = preloadUInt(bitCount).toInt() + return (mask and ((0b10 shl n) - 1)).countOneBits() - 1 + } +} \ No newline at end of file diff --git a/block-tlb/src/ValidatorBaseInfo.kt b/block-tlb/src/ValidatorBaseInfo.kt index be475d6d..83617768 100644 --- a/block-tlb/src/ValidatorBaseInfo.kt +++ b/block-tlb/src/ValidatorBaseInfo.kt @@ -1,9 +1,8 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -@Serializable + @SerialName("validator_base_info") public data class ValidatorBaseInfo( val validator_list_hash_short: Long, diff --git a/block-tlb/src/ValidatorInfo.kt b/block-tlb/src/ValidatorInfo.kt index 451cea12..5d871799 100644 --- a/block-tlb/src/ValidatorInfo.kt +++ b/block-tlb/src/ValidatorInfo.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -10,7 +9,7 @@ import org.ton.tlb.TlbObject import org.ton.tlb.TlbPrettyPrinter import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("validator_info") public data class ValidatorInfo( @SerialName("validator_list_hash_short") val validatorListHashShort: UInt, diff --git a/block-tlb/src/ValueFlow.kt b/block-tlb/src/ValueFlow.kt index 4187c348..92d10004 100644 --- a/block-tlb/src/ValueFlow.kt +++ b/block-tlb/src/ValueFlow.kt @@ -1,11 +1,11 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.* import org.ton.tlb.* +import org.ton.tlb.TlbConstructor + -@Serializable @SerialName("value_flow") public data class ValueFlow( @SerialName("from_prev_blk") val fromPrevBlk: CurrencyCollection, diff --git a/block-tlb/src/VarInteger.kt b/block-tlb/src/VarInteger.kt index 3649abc3..c1e801f6 100644 --- a/block-tlb/src/VarInteger.kt +++ b/block-tlb/src/VarInteger.kt @@ -1,9 +1,7 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bigint.BigInt -import org.ton.bigint.BigIntSerializer import org.ton.bigint.bitLength import org.ton.bigint.toBigInt import org.ton.cell.CellBuilder @@ -13,10 +11,9 @@ import org.ton.tlb.TlbConstructor import kotlin.jvm.JvmStatic @SerialName("var_int") -@Serializable + public data class VarInteger( val len: Int, - @Serializable(BigIntSerializer::class) val value: BigInt ) : Number() { @Deprecated("Use explicit constructor instead. In feature TLB classes will be auto-generated by TLB parser") diff --git a/block-tlb/src/VarUInteger.kt b/block-tlb/src/VarUInteger.kt index 6e19eb18..fa8e3b15 100644 --- a/block-tlb/src/VarUInteger.kt +++ b/block-tlb/src/VarUInteger.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bigint.* import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -14,12 +13,11 @@ import kotlin.jvm.JvmName import kotlin.jvm.JvmStatic @SerialName("var_uint") -@Serializable + public data class VarUInteger( @get:JvmName("len") val len: Int, - @Serializable(BigIntSerializer::class) @get:JvmName("value") val value: BigInt ) : TlbObject { diff --git a/block-tlb/src/VmCellSlice.kt b/block-tlb/src/VmCellSlice.kt index 17ff8a87..2abe1289 100644 --- a/block-tlb/src/VmCellSlice.kt +++ b/block-tlb/src/VmCellSlice.kt @@ -1,13 +1,12 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.* import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider @SerialName("vm_stk_slice") -@Serializable + public data class VmCellSlice( override val cell: Cell, override val stBits: Int, diff --git a/block-tlb/src/VmCont.kt b/block-tlb/src/VmCont.kt index 62d434e8..f80904e8 100644 --- a/block-tlb/src/VmCont.kt +++ b/block-tlb/src/VmCont.kt @@ -3,33 +3,33 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.* +import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbCombinatorProvider @JsonClassDiscriminator("@type") -@Serializable + public sealed interface VmCont { @SerialName("vmc_until") - @Serializable + public data class Until( val body: CellRef, val after: CellRef ) : VmCont @SerialName("vmc_again") - @Serializable + public data class Again( val body: CellRef ) : VmCont @SerialName("vmc_while_cond") - @Serializable + public data class WhileCond( val cond: CellRef, val body: CellRef, @@ -37,7 +37,7 @@ public sealed interface VmCont { ) : VmCont @SerialName("vmc_while_body") - @Serializable + public data class WhileBody( val cond: CellRef, val body: CellRef, @@ -45,7 +45,7 @@ public sealed interface VmCont { ) : VmCont @SerialName("vmc_pushint") - @Serializable + public data class PushInt( val value: Int, val next: CellRef diff --git a/block-tlb/src/VmContEnvelope.kt b/block-tlb/src/VmContEnvelope.kt index 834f8650..cf30454e 100644 --- a/block-tlb/src/VmContEnvelope.kt +++ b/block-tlb/src/VmContEnvelope.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -12,7 +11,7 @@ import org.ton.tlb.storeTlb import kotlin.jvm.JvmStatic @SerialName("vmc_envelope") -@Serializable + public data class VmContEnvelope( val cdata: VmControlData, val next: CellRef diff --git a/block-tlb/src/VmContQuit.kt b/block-tlb/src/VmContQuit.kt index e55c22e0..76d35f57 100644 --- a/block-tlb/src/VmContQuit.kt +++ b/block-tlb/src/VmContQuit.kt @@ -1,14 +1,13 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke import org.ton.tlb.TlbConstructor @SerialName("vmc_quit") -@Serializable + public data class VmContQuit( val exit_code: Int ) : VmCont { diff --git a/block-tlb/src/VmContQuitExc.kt b/block-tlb/src/VmContQuitExc.kt index c590a864..d42641f6 100644 --- a/block-tlb/src/VmContQuitExc.kt +++ b/block-tlb/src/VmContQuitExc.kt @@ -1,13 +1,12 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.tlb.TlbConstructor @SerialName("vmc_quit_exc") -@Serializable + public object VmContQuitExc : VmCont { public fun tlbConstructor(): TlbConstructor = VmContQuitExcTlbConstructor } diff --git a/block-tlb/src/VmContRepeat.kt b/block-tlb/src/VmContRepeat.kt index a881f005..0e9782d0 100644 --- a/block-tlb/src/VmContRepeat.kt +++ b/block-tlb/src/VmContRepeat.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -11,7 +10,7 @@ import org.ton.tlb.loadTlb import org.ton.tlb.storeTlb @SerialName("vmc_repeat") -@Serializable + public data class VmContRepeat( val count: Long, val body: CellRef, diff --git a/block-tlb/src/VmContStd.kt b/block-tlb/src/VmContStd.kt index bf3125a8..6339a862 100644 --- a/block-tlb/src/VmContStd.kt +++ b/block-tlb/src/VmContStd.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -12,7 +11,7 @@ import org.ton.tlb.storeTlb import kotlin.jvm.JvmStatic @SerialName("vmc_std") -@Serializable + public data class VmContStd( val cdata: VmControlData, val code: VmCellSlice diff --git a/block-tlb/src/VmControlData.kt b/block-tlb/src/VmControlData.kt index 6793371f..aa8cde2b 100644 --- a/block-tlb/src/VmControlData.kt +++ b/block-tlb/src/VmControlData.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -14,7 +13,7 @@ import org.ton.tlb.storeTlb import kotlin.jvm.JvmStatic @SerialName("vm_ctl_data") -@Serializable + public class VmControlData( public val nargs: Maybe, public val stack: Maybe, diff --git a/block-tlb/src/VmGasLimits.kt b/block-tlb/src/VmGasLimits.kt index a2791581..afe3c371 100644 --- a/block-tlb/src/VmGasLimits.kt +++ b/block-tlb/src/VmGasLimits.kt @@ -3,10 +3,9 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable @SerialName("gas_limits") -@Serializable + public data class VmGasLimits( val remaining: Long, val max_limit: Long, diff --git a/block-tlb/src/VmLibraries.kt b/block-tlb/src/VmLibraries.kt index 6ac1f3ec..393d2a46 100644 --- a/block-tlb/src/VmLibraries.kt +++ b/block-tlb/src/VmLibraries.kt @@ -1,10 +1,9 @@ package org.ton.block -import kotlinx.serialization.Serializable import org.ton.cell.Cell import org.ton.hashmap.HashMapE -@Serializable + public data class VmLibraries( val libraries: HashMapE ) diff --git a/block-tlb/src/VmSaveList.kt b/block-tlb/src/VmSaveList.kt index 9883ae3e..482f5f2d 100644 --- a/block-tlb/src/VmSaveList.kt +++ b/block-tlb/src/VmSaveList.kt @@ -1,6 +1,5 @@ package org.ton.block -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -11,7 +10,7 @@ import org.ton.tlb.loadTlb import org.ton.tlb.storeTlb import kotlin.jvm.JvmStatic -@Serializable + public data class VmSaveList( val cregs: HashMapE ) { diff --git a/block-tlb/src/VmStack.kt b/block-tlb/src/VmStack.kt index 41142b57..1dbac618 100644 --- a/block-tlb/src/VmStack.kt +++ b/block-tlb/src/VmStack.kt @@ -3,7 +3,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bigint.BigInt import org.ton.cell.Cell import org.ton.cell.CellBuilder @@ -81,7 +80,7 @@ public interface MutableVmStack : VmStack { } @SerialName("vm_stack") -@Serializable + public data class VmStackImpl( override val depth: Int, override val stack: VmStackList diff --git a/block-tlb/src/VmStackBuilder.kt b/block-tlb/src/VmStackBuilder.kt index 768ddd83..3f606a29 100644 --- a/block-tlb/src/VmStackBuilder.kt +++ b/block-tlb/src/VmStackBuilder.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -9,7 +8,7 @@ import org.ton.cell.invoke import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("vm_stk_builder") public class VmStackBuilder( public val cell: Cell diff --git a/block-tlb/src/VmStackCell.kt b/block-tlb/src/VmStackCell.kt index 1c26d34b..534e260b 100644 --- a/block-tlb/src/VmStackCell.kt +++ b/block-tlb/src/VmStackCell.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice @@ -9,7 +8,7 @@ import org.ton.cell.invoke import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider -@Serializable + @SerialName("vm_stk_cell") public data class VmStackCell( val cell: Cell diff --git a/block-tlb/src/VmStackCont.kt b/block-tlb/src/VmStackCont.kt index afdacdb8..b5fb80cb 100644 --- a/block-tlb/src/VmStackCont.kt +++ b/block-tlb/src/VmStackCont.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -10,7 +9,7 @@ import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + @SerialName("vm_stk_cont") public data class VmStackCont( val cont: VmCont diff --git a/block-tlb/src/VmStackInt.kt b/block-tlb/src/VmStackInt.kt index 2a7e704d..81bd17f2 100644 --- a/block-tlb/src/VmStackInt.kt +++ b/block-tlb/src/VmStackInt.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bigint.* import org.ton.block.VmStackNan.VmStackNanException import org.ton.cell.CellBuilder @@ -11,9 +10,8 @@ import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider @SerialName("vm_stk_int") -@Serializable + public data class VmStackInt( - @Serializable(BigIntSerializer::class) val value: BigInt ) : VmStackValue, VmStackNumber { public constructor(int: Int) : this(int.toBigInt()) diff --git a/block-tlb/src/VmStackList.kt b/block-tlb/src/VmStackList.kt index a75e4c70..bc81d07e 100644 --- a/block-tlb/src/VmStackList.kt +++ b/block-tlb/src/VmStackList.kt @@ -3,7 +3,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.cell.* import org.ton.tlb.TlbCodec @@ -16,10 +15,10 @@ public inline fun VmStackList(vararg stackValues: VmStackValue): VmStackList = V public inline fun VmStackList(stackValues: Iterable): VmStackList = VmStackList.of(stackValues) @JsonClassDiscriminator("@type") -@Serializable + public sealed interface VmStackList : Iterable { @SerialName("vm_stk_cons") - @Serializable + public data class Cons( val rest: VmStackList, val tos: VmStackValue @@ -29,7 +28,7 @@ public sealed interface VmStackList : Iterable { } @SerialName("vm_stk_nil") - @Serializable + public object Nil : VmStackList { private val iterator = ListIterator(this) override fun iterator(): Iterator = iterator diff --git a/block-tlb/src/VmStackNull.kt b/block-tlb/src/VmStackNull.kt index 5456e4bf..81c26224 100644 --- a/block-tlb/src/VmStackNull.kt +++ b/block-tlb/src/VmStackNull.kt @@ -1,14 +1,13 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider @SerialName("vm_stk_null") -@Serializable + public object VmStackNull : VmStackValue, TlbConstructorProvider by VmStackValueNullConstructor { override fun toString(): String = "vm_stk_null" } diff --git a/block-tlb/src/VmStackSlice.kt b/block-tlb/src/VmStackSlice.kt index e5c14e38..bab69822 100644 --- a/block-tlb/src/VmStackSlice.kt +++ b/block-tlb/src/VmStackSlice.kt @@ -10,12 +10,8 @@ public sealed interface VmStackSlice : VmStackValue { public val stRef: Int public val endRef: Int - public fun toCellSlice(): CellSlice = cell.beginParse().run { - skipBits(stBits) - loadRefs(stRef) - CellSlice.of( - loadBits(endBits - stBits), - loadRefs(endRef - stRef) - ) + public fun toCellSlice(): CellSlice = cell.beginParse().apply { + bitsPosition += stBits + refsPosition += stRef } } diff --git a/block-tlb/src/VmStackTinyInt.kt b/block-tlb/src/VmStackTinyInt.kt index f1ca976f..f128265d 100644 --- a/block-tlb/src/VmStackTinyInt.kt +++ b/block-tlb/src/VmStackTinyInt.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.bigint.* import org.ton.block.VmStackNan.VmStackNanException import org.ton.cell.CellBuilder @@ -12,7 +11,7 @@ import org.ton.tlb.providers.TlbConstructorProvider import kotlin.math.abs @SerialName("vm_stk_tinyint") -@Serializable + public data class VmStackTinyInt( val value: Long ) : VmStackValue, VmStackNumber { diff --git a/block-tlb/src/VmStackTuple.kt b/block-tlb/src/VmStackTuple.kt index 4947e997..14e149f1 100644 --- a/block-tlb/src/VmStackTuple.kt +++ b/block-tlb/src/VmStackTuple.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -10,7 +9,7 @@ import org.ton.tlb.loadTlb import org.ton.tlb.providers.TlbConstructorProvider import org.ton.tlb.storeTlb -@Serializable + @SerialName("vm_stk_tuple") public class VmStackTuple( public val len: Int, diff --git a/block-tlb/src/VmStackValue.kt b/block-tlb/src/VmStackValue.kt index dc6307ad..cbea8cba 100644 --- a/block-tlb/src/VmStackValue.kt +++ b/block-tlb/src/VmStackValue.kt @@ -2,7 +2,6 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.bigint.BigInt import org.ton.cell.Cell @@ -24,7 +23,7 @@ public inline fun VmStackValue(cont: VmCont): VmStackCont = VmStackValue.of(cont public inline fun VmStackValue(tuple: VmTuple): VmStackTuple = VmStackValue.of(tuple) @JsonClassDiscriminator("@type") -@Serializable + public sealed interface VmStackValue { public companion object : TlbCombinatorProvider by VmStackValueTlbCombinator { @JvmStatic diff --git a/block-tlb/src/VmTuple.kt b/block-tlb/src/VmTuple.kt index 3a7a88a0..fff44f66 100644 --- a/block-tlb/src/VmTuple.kt +++ b/block-tlb/src/VmTuple.kt @@ -2,13 +2,12 @@ package org.ton.block -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.tlb.TlbCodec import kotlin.jvm.JvmStatic @JsonClassDiscriminator("@type") -@Serializable + public sealed interface VmTuple { public fun depth(): Int diff --git a/block-tlb/src/VmTupleNil.kt b/block-tlb/src/VmTupleNil.kt index ce48e996..72c3f1b3 100644 --- a/block-tlb/src/VmTupleNil.kt +++ b/block-tlb/src/VmTupleNil.kt @@ -1,14 +1,13 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.tlb.TlbConstructor import org.ton.tlb.providers.TlbConstructorProvider @SerialName("vm_tuple_nil") -@Serializable + public object VmTupleNil : VmTuple, TlbConstructorProvider by VmTupleNilTlbConstructor { override fun depth(): Int = 0 diff --git a/block-tlb/src/VmTupleRef.kt b/block-tlb/src/VmTupleRef.kt index b8d888fa..e385008e 100644 --- a/block-tlb/src/VmTupleRef.kt +++ b/block-tlb/src/VmTupleRef.kt @@ -3,7 +3,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.cell.* import org.ton.tlb.TlbCodec @@ -17,7 +16,7 @@ public inline fun VmTupleRef(entry: VmStackValue): VmTupleRef = VmTupleRef.of(en public inline fun VmTupleRef(ref: VmTuple): VmTupleRef = VmTupleRef.of(ref) @JsonClassDiscriminator("@type") -@Serializable + public sealed interface VmTupleRef { public fun depth(): Int @@ -42,7 +41,7 @@ public sealed interface VmTupleRef { } @SerialName("vm_tupref_nil") -@Serializable + public object VmTupleRefNil : VmTupleRef { override fun depth(): Int = 0 @@ -50,7 +49,7 @@ public object VmTupleRefNil : VmTupleRef { } @SerialName("vm_tupref_single") -@Serializable + public data class VmTupleRefSingle( val entry: VmStackValue ) : VmTupleRef { @@ -60,7 +59,7 @@ public data class VmTupleRefSingle( } @SerialName("vm_tupref_any") -@Serializable + public data class VmTupleRefAny( val ref: VmTuple ) : VmTupleRef { diff --git a/block-tlb/src/VmTupleTcons.kt b/block-tlb/src/VmTupleTcons.kt index 8f3749b1..2c237462 100644 --- a/block-tlb/src/VmTupleTcons.kt +++ b/block-tlb/src/VmTupleTcons.kt @@ -1,7 +1,6 @@ package org.ton.block import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.invoke @@ -11,7 +10,7 @@ import org.ton.tlb.storeTlb import kotlin.jvm.JvmStatic @SerialName("vm_tuple_tcons") -@Serializable + public data class VmTupleTcons( val head: VmTupleRef, val tail: VmStackValue diff --git a/block-tlb/src/currency/VarUInt248.kt b/block-tlb/src/currency/VarUInt248.kt new file mode 100644 index 00000000..27c52b92 --- /dev/null +++ b/block-tlb/src/currency/VarUInt248.kt @@ -0,0 +1,68 @@ +@file:Suppress("PackageDirectoryMismatch") + +package org.ton.kotlin.currency + +import org.ton.bigint.BigInt +import org.ton.bigint.bitLength +import org.ton.bigint.sign +import org.ton.bigint.toBigInt +import org.ton.cell.CellBuilder +import org.ton.cell.CellSlice +import org.ton.tlb.TlbCodec + +/** + * Variable-length 248-bit integer. Used for extra currencies. + * + * Stored as 5 bits of `len` (0..=31), followed by `len` bytes. + * + * @see [org.ton.block.ExtraCurrencyCollection] + */ +public data class VarUInt248( + public val amount: BigInt +) : Number(), Comparable { + init { + require(amount.sign != -1) { "Amount must be less than zero." } + require(amount.bitLength <= 248) { "Amount overflow" } + } + + public constructor(amount: Long) : this(amount.toBigInt()) + + public constructor(amount: String, radix: Int) : this(BigInt(amount, radix)) + + override fun toDouble(): Double = amount.toDouble() + override fun toFloat(): Float = amount.toFloat() + override fun toLong(): Long = amount.toLong() + override fun toInt(): Int = amount.toInt() + override fun toShort(): Short = amount.toShort() + override fun toByte(): Byte = amount.toByte() + + override fun compareTo(other: VarUInt248): Int { + return amount.compareTo(other.amount) + } + + override fun toString(): String = amount.toString() + + public companion object : TlbCodec by VarUInt248Codec { + public val ZERO: VarUInt248 = VarUInt248(0.toBigInt()) + public val ONE: VarUInt248 = VarUInt248(1.toBigInt()) + public val TWO: VarUInt248 = VarUInt248(2.toBigInt()) + public val TEN: VarUInt248 = VarUInt248(10.toBigInt()) + + // public val MAX: VarUInt248 = VarUInt248((1.toBigInt() shl 248).minus(1.toBigInt())) + public val MIN: VarUInt248 = ZERO + } +} + +private object VarUInt248Codec : TlbCodec { + override fun storeTlb(builder: CellBuilder, value: VarUInt248) { + val len = (value.amount.bitLength + 7) ushr 3 + builder.storeUInt(len, 5) + builder.storeUInt(value.amount, len * 8) + } + + override fun loadTlb(slice: CellSlice): VarUInt248 { + val len = slice.loadUInt(5).toInt() + val value = slice.loadUInt(len * 8) + return VarUInt248(value) + } +} \ No newline at end of file diff --git a/block-tlb/src/message/MessageLayout.kt b/block-tlb/src/message/MessageLayout.kt new file mode 100644 index 00000000..10ab9550 --- /dev/null +++ b/block-tlb/src/message/MessageLayout.kt @@ -0,0 +1,109 @@ +@file:Suppress("PackageDirectoryMismatch") + +package org.ton.kotlin.message + +import org.ton.block.* +import org.ton.block.Either.Left +import org.ton.block.Either.Right +import org.ton.cell.CellBuilder +import org.ton.cell.CellSlice +import org.ton.kotlin.cell.CellContext +import org.ton.tlb.CellRef +import org.ton.tlb.TlbCodec +import org.ton.tlb.TlbStorer +import org.ton.tlb.storeTlb + +/** + * Message payload layout. + */ +public data class MessageLayout( + /** + * Whether to store state init in a child cell. + */ + val initToCell: Boolean, + + /** + * Whether to store payload as a child cell. + */ + val bodyToCell: Boolean, +) { + public fun eitherInit(init: StateInit?): Either>? { + if (init == null) return null + return if (initToCell) { + Right(CellRef(init, StateInit)) + } else { + Left(init) + } + } + + public fun eitherBody(body: T, bodyCodec: TlbCodec): Either> { + return if (bodyToCell) Right(CellRef(body, bodyCodec)) else Left(body) + } + + public companion object { + /** + * Plain message layout (init and body stored in the root cell). + */ + public val PLAIN: MessageLayout = MessageLayout(initToCell = false, bodyToCell = false) + + private val LAYOUTS = arrayOf( + PLAIN, + MessageLayout(initToCell = false, bodyToCell = true), + MessageLayout(initToCell = true, bodyToCell = false), + ) + + public fun compute( + info: CommonMsgInfoRelaxed, + init: StateInit?, + body: T, + bodyStorer: TlbStorer + ): MessageLayout { + val bodyCodec = object : TlbCodec { + override fun storeTlb(builder: CellBuilder, value: T, context: CellContext) = + bodyStorer.storeTlb(builder, value, context) + + override fun loadTlb(slice: CellSlice, context: CellContext): T = throw UnsupportedOperationException() + } + val messageCodec = MessageRelaxed.tlbCodec(bodyCodec) + val builder = CellBuilder() + for (layout in LAYOUTS) { + builder.reset() + val result = runCatching { + builder.storeTlb(messageCodec, MessageRelaxed(info, init, body, bodyCodec, layout)) + check(builder.remainingBits >= 0 && builder.refs.size <= 4) + } + if (result.isSuccess) { + return layout + } + } + return MessageLayout(initToCell = true, bodyToCell = true) + } + + public fun compute( + info: CommonMsgInfo, + init: StateInit?, + body: T, + bodyStorer: TlbStorer + ): MessageLayout { + val bodyCodec = object : TlbCodec { + override fun storeTlb(builder: CellBuilder, value: T, context: CellContext) = + bodyStorer.storeTlb(builder, value, context) + + override fun loadTlb(slice: CellSlice): T = throw UnsupportedOperationException() + } + val messageCodec = Message.tlbCodec(bodyCodec) + val builder = CellBuilder() + for (layout in LAYOUTS) { + builder.reset() + val result = runCatching { + builder.storeTlb(messageCodec, Message(info, init, body, bodyCodec, layout)) + check(builder.remainingBits >= 0 && builder.refs.size <= 4) + } + if (result.isSuccess) { + return layout + } + } + return MessageLayout(initToCell = true, bodyToCell = true) + } + } +} \ No newline at end of file diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index 45da1463..dd1f4dc8 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -9,5 +9,5 @@ repositories { dependencies { implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20") -// implementation("io.github.gradle-nexus:publish-plugin:2.0.0-rc-1") + implementation("com.vanniktech:gradle-maven-publish-plugin:0.28.0") } diff --git a/build-logic/src/main/kotlin/publish.gradle.kts b/build-logic/src/main/kotlin/publish.gradle.kts index 1662a578..c683ef68 100644 --- a/build-logic/src/main/kotlin/publish.gradle.kts +++ b/build-logic/src/main/kotlin/publish.gradle.kts @@ -1,109 +1,36 @@ -import org.gradle.jvm.tasks.Jar -import java.net.URI +import com.vanniktech.maven.publish.SonatypeHost plugins { - `maven-publish` - signing -} - -publishing { - val javadocJar = project.configureEmptyJavadocArtifact() - publications.withType(MavenPublication::class).all { - pom.configureMavenCentralMetadata(project) - signPublicationIfKeyPresent(project, this) - artifact(javadocJar) - } - - tasks.withType().configureEach { - dependsOn(tasks.withType()) - } -} - -// Pom configuration -infix fun Property.by(value: T) { - set(value) -} - -fun MavenPom.configureMavenCentralMetadata(project: Project) { - name by project.name - description by "Kotlin/Multiplatform SDK for The Open Network" - url by "https://github.com/ton-community/ton-kotlin" - - licenses { - license { - name by "The Apache Software License, Version 2.0" - url by "https://www.apache.org/licenses/LICENSE-2.0.txt" - distribution by "repo" + id("com.vanniktech.maven.publish") +} + +mavenPublishing { + pom { + name = project.name + description = "Kotlin/Multiplatform SDK for The Open Network" + inceptionYear = "2025" + url = "https://github.com/ton-community/ton-kotlin" + + licenses { + license { + name = "The Apache Software License, Version 2.0" + url = "https://www.apache.org/licenses/LICENSE-2.0.txt" + distribution = "repo" + } } - } - developers { - developer { - id by "andreypfau" - name by "Andrey Pfau" - email by "andreypfau@ton.org" + developers { + developer { + id = "andreypfau" + name = "Andrey Pfau" + email = "andreypfau@ton.org" + } } - } - - scm { - url by "https://github.com/ton-community/ton-kotlin" - } -} - -fun MavenPublication.mavenCentralArtifacts(project: Project, sources: SourceDirectorySet) { - val sourcesJar by project.tasks.creating(Jar::class) { - archiveClassifier.set("sources") - from(sources) - } - val javadocJar by project.tasks.creating(Jar::class) { - archiveClassifier.set("javadoc") - // contents are deliberately left empty - } - artifact(sourcesJar) - artifact(javadocJar) -} - - -fun mavenRepositoryUri(): URI { - val repositoryId: String? = System.getenv("SONATYPE_REPOSITORY_ID") - return if (repositoryId == null) { - URI("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") - } else { - URI("https://s01.oss.sonatype.org/service/local/staging/deployByRepositoryId/$repositoryId") - } -} - -fun RepositoryHandler.configureMavenPublication(project: Project) { - maven { - url = mavenRepositoryUri() - credentials { - username = project.getSensitiveProperty("OSSRH_USERNAME") - password = project.getSensitiveProperty("OSSRH_PASSWORD") - } - } - - mavenLocal() -} - -fun Project.configureEmptyJavadocArtifact(): Jar { - val javadocJar by project.tasks.creating(Jar::class) { - archiveClassifier.set("javadoc") - // contents are deliberately left empty - } - return javadocJar -} - -fun signPublicationIfKeyPresent(project: Project, publication: MavenPublication) { - val signingKey = project.getSensitiveProperty("SIGNING_SECRET_KEY") - val signingKeyPassphrase = project.getSensitiveProperty("SIGNING_PASSWORD") - if (!signingKey.isNullOrBlank()) { - project.extensions.configure("signing") { - useInMemoryPgpKeys(signingKey, signingKeyPassphrase) - sign(publication) + scm { + url = "https://github.com/ton-community/ton-kotlin" } } -} -fun Project.getSensitiveProperty(name: String): String? { - return project.findProperty(name) as? String ?: System.getenv(name) + publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) + signAllPublications() } diff --git a/build.gradle.kts b/build.gradle.kts index 1a47037b..7a81ee91 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,14 +4,13 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile plugins { kotlin("multiplatform") apply false kotlin("plugin.serialization") apply false - id("io.github.gradle-nexus.publish-plugin") version "2.0.0-rc-1" alias(libs.plugins.bcv) } allprojects { group = "org.ton" - version = "0.3.2" + version = "0.4.1" repositories { mavenCentral() @@ -37,16 +36,16 @@ subprojects { } } -nexusPublishing { - repositories { - sonatype { - nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) - snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) - username.set(System.getenv("OSSRH_USERNAME")) - password.set(System.getenv("OSSRH_PASSWORD")) - } - } -} +//nexusPublishing { +// repositories { +// sonatype { +// nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) +// snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) +// username.set(System.getenv("OSSRH_USERNAME")) +// password.set(System.getenv("OSSRH_PASSWORD")) +// } +// } +//} //val isCI = System.getenv("CI") == "true" //val isSnapshot = System.getenv("TON_KOTLIN_SNAPSHOT") == "true" //val disableNativeTarget = System.getenv("TON_KOTLIN_DISABLE_NATIVE_TARGET") == "true" diff --git a/contract/src/CellString.kt b/contract/src/CellString.kt index 526ce3d8..328db33d 100644 --- a/contract/src/CellString.kt +++ b/contract/src/CellString.kt @@ -6,6 +6,7 @@ import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.storeRef +import org.ton.kotlin.cell.CellContext import org.ton.tlb.TlbConstructor import kotlin.math.min @@ -23,7 +24,7 @@ public object CellStringTlbConstructor : TlbConstructor( return ByteString(*result.toByteArray()) } - override fun storeTlb(cellBuilder: CellBuilder, value: ByteString) { + override fun storeTlb(cellBuilder: CellBuilder, value: ByteString, context: CellContext) { require(value.size <= MAX_BYTES) { "String is too long" } @@ -40,8 +41,8 @@ public object CellStringTlbConstructor : TlbConstructor( cellBuilder.storeBytes(value.toByteArray()) } else { cellBuilder.storeBytes(value.substring(0, head / 8).toByteArray()) - cellBuilder.storeRef { - storeTlb(this, value.substring(head / 8, value.size)) + cellBuilder.storeRef(context) { + storeTlb(this, value.substring(head / 8, value.size), context) } } } diff --git a/contract/src/wallet/WalletMessage.kt b/contract/src/wallet/WalletMessage.kt index 7b36c51c..5dcb2701 100644 --- a/contract/src/wallet/WalletMessage.kt +++ b/contract/src/wallet/WalletMessage.kt @@ -17,10 +17,6 @@ public interface WalletMessage { public fun of(mode: Int, msg: CellRef>): WalletMessage = WalletMessageImpl(mode, msg) - @JvmStatic - public fun of(mode: Int, msg: MessageRelaxed): WalletMessage = - of(mode, CellRef(msg)) - @JvmStatic public fun tlbCodec(x: TlbCodec): TlbCodec> = WalletMessageTlbConstructor(x) @@ -30,9 +26,6 @@ public interface WalletMessage { public inline fun WalletMessage(mode: Int, msg: CellRef>): WalletMessage = WalletMessage.of(mode, msg) -public inline fun WalletMessage(mode: Int, msg: MessageRelaxed): WalletMessage = - WalletMessage.of(mode, msg) - private data class WalletMessageImpl( override val mode: Int, override val msg: CellRef> diff --git a/contract/src/wallet/WalletTransfer.kt b/contract/src/wallet/WalletTransfer.kt index 8b3c916c..de29e49a 100644 --- a/contract/src/wallet/WalletTransfer.kt +++ b/contract/src/wallet/WalletTransfer.kt @@ -3,7 +3,9 @@ package org.ton.contract.wallet import org.ton.api.pub.PublicKey import org.ton.block.* import org.ton.cell.Cell +import org.ton.kotlin.message.MessageLayout import org.ton.tlb.CellRef +import org.ton.tlb.constructor.AnyTlbConstructor import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.jvm.JvmStatic @@ -14,19 +16,57 @@ public data class WalletTransfer internal constructor( val coins: CurrencyCollection, val sendMode: Int, val messageData: MessageData -) +) { + val msgInfo: CommonMsgInfoRelaxed = when (destination) { + is MsgAddressInt -> { + CommonMsgInfoRelaxed.IntMsgInfoRelaxed( + ihrDisabled = true, + bounce = bounceable, + bounced = false, + src = AddrNone, + dest = destination, + value = coins, + ihrFee = Coins(), + fwdFee = Coins(), + createdLt = 0u, + createdAt = 0u + ) + } + + is MsgAddressExt -> { + CommonMsgInfoRelaxed.ExtOutMsgInfoRelaxed( + src = AddrNone, + dest = destination, + createdLt = 0u, + createdAt = 0u + ) + } + } + + public fun toMessageRelaxed(layout: MessageLayout? = null): MessageRelaxed { + val init = messageData.stateInit?.value + val body = messageData.body + return MessageRelaxed( + info = msgInfo, + init = init, + body = body, + bodyCodec = AnyTlbConstructor, + layout = layout ?: MessageLayout.compute(msgInfo, init, body, AnyTlbConstructor) + ) + } +} public class WalletTransferBuilder { public lateinit var destination: MsgAddressInt public var bounceable: Boolean = true - public var currencyCollection: CurrencyCollection = CurrencyCollection(Coins(), ExtraCurrencyCollection()) + public var currencyCollection: CurrencyCollection = CurrencyCollection.ZERO public var coins: Coins get() = currencyCollection.coins set(value) { currencyCollection = currencyCollection.copy(coins = value) } public var sendMode: Int = 3 - public var messageData: MessageData = MessageData.Raw(Cell.empty(), null) + public var messageData: MessageData = MessageData.Raw(Cell.empty(), null, MessageLayout.PLAIN) public fun build(): WalletTransfer = WalletTransfer(destination, bounceable, currencyCollection, sendMode, messageData) @@ -40,25 +80,28 @@ public inline fun WalletTransfer(builderAction: WalletTransferBuilder.() -> Unit public sealed interface MessageData { public val body: Cell public val stateInit: CellRef? + public val layout: MessageLayout? public data class Raw( public override val body: Cell, - public override val stateInit: CellRef? + public override val stateInit: CellRef?, + override val layout: MessageLayout?, ) : MessageData public data class Text( - public val text: CellRef + public val text: CellRef, + override val layout: MessageLayout? = null ) : MessageData { public constructor(text: MessageText) : this(CellRef(text, MessageText)) - override val body: Cell get() = text.toCell(MessageText) + override val body: Cell get() = text.cell override val stateInit: CellRef? get() = null } public companion object { @JvmStatic public fun raw(body: Cell, stateInit: CellRef? = null): Raw = - Raw(body, stateInit) + Raw(body, stateInit, null) @JvmStatic public fun text(text: String): Text = Text( diff --git a/contract/src/wallet/WalletV3Contract.kt b/contract/src/wallet/WalletV3Contract.kt index a58b8ec7..d495609f 100644 --- a/contract/src/wallet/WalletV3Contract.kt +++ b/contract/src/wallet/WalletV3Contract.kt @@ -15,7 +15,6 @@ import org.ton.lite.client.LiteClient import org.ton.tlb.CellRef import org.ton.tlb.TlbConstructor import org.ton.tlb.constructor.AnyTlbConstructor -import org.ton.tlb.storeRef import org.ton.tlb.storeTlb public class WalletV3R2Contract( @@ -24,7 +23,8 @@ public class WalletV3R2Contract( ) : WalletContract { public suspend fun getWalletData(): WalletV3R2Data { val data = - ((liteClient.getAccountState(address).account.value as? AccountInfo)?.storage?.state as? AccountActive)?.value?.data?.value?.value?.beginParse() + ((liteClient.getAccountState(address).account.load())?.state as? AccountActive)?.value?.data?.value?.load() + ?.beginParse() require(data != null) { throw AccountNotInitializedException(address) } return WalletV3R2Data.loadTlb(data) } @@ -48,7 +48,7 @@ public class WalletV3R2Contract( walletId, privateKey.publicKey() ) - ).value else null + ).load() else null val message = transferMessage( address = address, stateInit = stateInit, @@ -101,8 +101,10 @@ public class WalletV3R2Contract( val dataCell = buildCell { storeTlb(WalletV3R2Data, data) } + val stateCell = StateInit(CODE, dataCell).toCell() + return CellRef( - StateInit(CODE, dataCell), + stateCell, StateInit ) } @@ -122,7 +124,12 @@ public class WalletV3R2Contract( importFee = Coins() ) val maybeStateInit = - Maybe.of(stateInit?.let { Either.of>(null, CellRef(it)) }) + Maybe.of(stateInit?.let { + Either.of>( + null, + CellRef(value = it, StateInit) + ) + }) val transferBody = createTransferMessageBody( privateKey, walletId, @@ -130,7 +137,7 @@ public class WalletV3R2Contract( seqno, *transfers ) - val body = Either.of>(null, CellRef(transferBody)) + val body = Either.of>(null, CellRef(value = transferBody, AnyTlbConstructor)) return Message( info = info, init = maybeStateInit, @@ -154,10 +161,10 @@ public class WalletV3R2Contract( if (gift.sendMode > -1) { sendMode = gift.sendMode } - val intMsg = CellRef(createIntMsg(gift)) + val intMsg = CellRef(gift.toMessageRelaxed(), MessageRelaxed.tlbCodec(AnyTlbConstructor)) storeUInt(sendMode, 8) - storeRef(MessageRelaxed.tlbCodec(AnyTlbConstructor), intMsg) + storeRef(intMsg.cell) } } val signature = BitString(privateKey.sign(unsignedBody.hash().toByteArray())) @@ -168,47 +175,5 @@ public class WalletV3R2Contract( storeRefs(unsignedBody.refs) } } - - private fun createIntMsg(gift: WalletTransfer): MessageRelaxed { - val info = when (val dest = gift.destination) { - is MsgAddressInt -> { - CommonMsgInfoRelaxed.IntMsgInfoRelaxed( - ihrDisabled = true, - bounce = gift.bounceable, - bounced = false, - src = AddrNone, - dest = dest, - value = gift.coins, - ihrFee = Coins(), - fwdFee = Coins(), - createdLt = 0u, - createdAt = 0u - ) - } - is MsgAddressExt -> { - CommonMsgInfoRelaxed.ExtOutMsgInfoRelaxed( - src = AddrNone, - dest = dest, - createdLt = 0u, - createdAt = 0u - ) - } - } - - val init = Maybe.of(gift.messageData.stateInit?.let { - Either.of>(null, it) - }) - val bodyCell = gift.messageData.body - val body = if (bodyCell.isEmpty()) { - Either.of>(Cell.empty(), null) - } else { - Either.of>(null, CellRef(bodyCell)) - } - return MessageRelaxed( - info = info, - init = init, - body = body, - ) - } } } diff --git a/contract/src/wallet/WalletV4R2Contract.kt b/contract/src/wallet/WalletV4R2Contract.kt index c4c1441f..8ba35273 100644 --- a/contract/src/wallet/WalletV4R2Contract.kt +++ b/contract/src/wallet/WalletV4R2Contract.kt @@ -14,8 +14,11 @@ import org.ton.contract.exception.AccountNotInitializedException import org.ton.contract.wallet.WalletContract.Companion.DEFAULT_WALLET_ID import org.ton.hashmap.HashMapE import org.ton.lite.client.LiteClient -import org.ton.tlb.* +import org.ton.tlb.CellRef +import org.ton.tlb.TlbConstructor import org.ton.tlb.constructor.AnyTlbConstructor +import org.ton.tlb.loadTlb +import org.ton.tlb.storeTlb import kotlin.io.encoding.Base64 public class WalletV4R2Contract( @@ -24,7 +27,7 @@ public class WalletV4R2Contract( ) : WalletContract { public suspend fun getWalletData(): Data { val data = - ((liteClient.getAccountState(address).account.value as? AccountInfo)?.storage?.state as? AccountActive)?.value?.data?.value?.value?.beginParse() + ((liteClient.getAccountState(address).account.value as? Account)?.storage?.state as? AccountActive)?.value?.data?.value?.value?.beginParse() require(data != null) { throw AccountNotInitializedException(address) } return Data.loadTlb(data) } @@ -143,7 +146,12 @@ public class WalletV4R2Contract( importFee = Coins() ) val maybeStateInit = - Maybe.of(stateInit?.let { Either.of>(null, CellRef(it)) }) + Maybe.of(stateInit?.let { + Either.of>( + null, + CellRef(value = it, StateInit) + ) + }) val transferBody = createTransferMessageBody( privateKey, walletId, @@ -151,7 +159,7 @@ public class WalletV4R2Contract( seqno, *transfers ) - val body = Either.of>(null, CellRef(transferBody)) + val body = Either.of>(null, CellRef(value = transferBody, AnyTlbConstructor)) return Message( info = info, init = maybeStateInit, @@ -176,10 +184,10 @@ public class WalletV4R2Contract( if (gift.sendMode > -1) { sendMode = gift.sendMode } - val intMsg = CellRef(createIntMsg(gift)) + val intMsg = CellRef(gift.toMessageRelaxed(), MessageRelaxed.tlbCodec(AnyTlbConstructor)) storeUInt(sendMode, 8) - storeRef(MessageRelaxed.tlbCodec(AnyTlbConstructor), intMsg) + storeRef(intMsg.cell) } } val signature = BitString(privateKey.sign(unsignedBody.hash().toByteArray())) @@ -190,48 +198,5 @@ public class WalletV4R2Contract( storeRefs(unsignedBody.refs) } } - - private fun createIntMsg(gift: WalletTransfer): MessageRelaxed { - val info = when (val dest = gift.destination) { - is MsgAddressInt -> { - CommonMsgInfoRelaxed.IntMsgInfoRelaxed( - ihrDisabled = true, - bounce = gift.bounceable, - bounced = false, - src = AddrNone, - dest = dest, - value = gift.coins, - ihrFee = Coins(), - fwdFee = Coins(), - createdLt = 0u, - createdAt = 0u - ) - } - - is MsgAddressExt -> { - CommonMsgInfoRelaxed.ExtOutMsgInfoRelaxed( - src = AddrNone, - dest = dest, - createdLt = 0u, - createdAt = 0u - ) - } - } - - val init = Maybe.of(gift.messageData.stateInit?.let { - Either.of>(null, it) - }) - val bodyCell = gift.messageData.body - val body = if (bodyCell.isEmpty()) { - Either.of>(Cell.empty(), null) - } else { - Either.of>(null, CellRef(bodyCell)) - } - return MessageRelaxed( - info = info, - init = init, - body = body, - ) - } } } diff --git a/contract/test/wallet/GlobalConfig.kt b/contract/test/wallet/GlobalConfig.kt new file mode 100644 index 00000000..b2259990 --- /dev/null +++ b/contract/test/wallet/GlobalConfig.kt @@ -0,0 +1,339 @@ +package org.ton.contract.wallet + +import kotlinx.serialization.json.Json +import org.ton.api.liteclient.config.LiteClientConfigGlobal + +val TESTNET_GLOBAL_CONFIG_JSON = """ +{ + "liteservers": [ + { + "ip": 822907680, + "port": 27842, + "provided":"Beavis", + "id": { + "@type": "pub.ed25519", + "key": "sU7QavX2F964iI9oToP9gffQpCQIoOLppeqL/pdPvpM=" + } + }, + { + "ip": -1468571697, + "port": 27787, + "provided":"Beavis", + "id": { + "@type": "pub.ed25519", + "key": "Y/QVf6G5VDiKTZOKitbFVm067WsuocTN8Vg036A4zGk=" + } + }, + { + "ip": -1468575011, + "port": 51088, + "provided":"Beavis", + "id": { + "@type": "pub.ed25519", + "key": "Sy5ghr3EahQd/1rDayzZXt5+inlfF+7kLfkZDJcU/ek=" + } + }, + { + "ip": 1844203537, + "port": 37537, + "provided":"Neo", + "id": { + "@type": "pub.ed25519", + "key": "K1F7zEe0ETf+SwkefLS56hJE8x42sjCVsBJJuaY7nEA=" + } + }, + { + "ip": 1844203589, + "port": 34411, + "provided":"Neo", + "id": { + "@type": "pub.ed25519", + "key": "pOpRRpIxDuMRm1qFUPpvVjD62vo8azkO0npw4FPcW/I=" + } + }, + { + "ip": 1047529523, + "port": 37649, + "provided":"Neo", + "id": { + "@type": "pub.ed25519", + "key": "pRf2sAa7d+Chl8gDclWOMtthtxjKnLYeAIzk869mMvA=" + } + }, + { + "ip": 1592601963, + "port": 13833, + "id": { + "@type": "pub.ed25519", + "key": "QpVqQiv1u3nCHuBR3cg3fT6NqaFLlnLGbEgtBRukDpU=" + } + }, + { + "ip": 1162057690, + "port": 35939, + "id": { + "@type": "pub.ed25519", + "key": "97y55AkdzXWyyVuOAn+WX6p66XTNs2hEGG0jFUOkCIo=" + } + }, + { + "ip": -1304477830, + "port": 20700, + "id": { + "@type": "pub.ed25519", + "key": "dGLlRRai3K9FGkI0dhABmFHMv+92QEVrvmTrFf5fbqA=" + } + }, + { + "ip": 1959453117, + "port": 20700, + "id": { + "@type": "pub.ed25519", + "key": "24RL7iVI20qcG+j//URfd/XFeEG9qtezW2wqaYQgVKw=" + } + }, + { + "ip": -809760973, + "port": 20700, + "id": { + "@type": "pub.ed25519", + "key": "vunMV7K35yPlTQPx/Fqk6s+4/h5lpcbP+ao0Cy3M2hw=" + } + }, + { + "ip": 1097633201, + "port": 17439, + "id": { + "@type": "pub.ed25519", + "key": "0MIADpLH4VQn+INHfm0FxGiuZZAA8JfTujRqQugkkA8=" + } + }, + { + "ip": 1091956407, + "port": 16351, + "id": { + "@type": "pub.ed25519", + "key": "Mf/JGvcWAvcrN3oheze8RF/ps6p7oL6ifrIzFmGQFQ8=" + } + } + ], + "dht": { + "a": 3, + "k": 3, + "static_nodes": { + "nodes": [ + { + "@type": "dht.node", + "id": { + "@type": "pub.ed25519", + "key": "K2AWu8leN2RjYmhMpYAaGX/F6nGVk9oZw9c09RX3yyc=" + }, + "addr_list": { + "@type": "adnl.addressList", + "addrs": [ + { + "@type": "adnl.address.udp", + "ip": 1592601963, + "port": 38723 + } + ], + "version": 0, + "reinit_date": 0, + "priority": 0, + "expire_at": 0 + }, + "version": -1, + "signature": "21g16jxnqbb2ENAijrZFccHqLQcmmpkAI1HA46DaPvnVYvMkATFNEyHTy2R1T1jgU5M7CCLGJN+MxhwZfl/ZDA==" + }, + { + "@type": "dht.node", + "id": { + "@type": "pub.ed25519", + "key": "fVIJzD9ATMilaPd847eFs6PtGSB67C+D9b4R+nf1+/s=" + }, + "addr_list": { + "@type": "adnl.addressList", + "addrs": [ + { + "@type": "adnl.address.udp", + "ip": 1097649206, + "port": 29081 + } + ], + "version": 0, + "reinit_date": 0, + "priority": 0, + "expire_at": 0 + }, + "version": -1, + "signature": "wH0HEVT6yAfZZAoD5bF6J3EZWdSFwBGl1ZpOfhxZ0Bp2u52tv8OzjeH8tlZ+geMLTG50Csn5nxSKP1tswTWwBg==" + }, + { + "@type": "dht.node", + "id": { + "@type": "pub.ed25519", + "key": "gu+woR+x7PoRmaMqAP7oeOjK2V4U0NU8ofdacWZ34aY=" + }, + "addr_list": { + "@type": "adnl.addressList", + "addrs": [ + { + "@type": "adnl.address.udp", + "ip": 1162057690, + "port": 41578 + } + ], + "version": 0, + "reinit_date": 0, + "priority": 0, + "expire_at": 0 + }, + "version": -1, + "signature": "0PwDLXpN3IbRQuOTLkZBjkbT6+IkeUcvlhWrUY9us3IfSehmCfQjScR9mkVYsQ6cQHF+JeaFmqzV4GAiUcgjAg==" + }, + { + "@type": "dht.node", + "id": { + "@type": "pub.ed25519", + "key": "WC4BO1eZ916FnLBSKmt07Pn5NP4D3/1wary1VjaCLaY=" + }, + "addr_list": { + "@type": "adnl.addressList", + "addrs": [ + { + "@type": "adnl.address.udp", + "ip": -1304477830, + "port": 9670 + } + ], + "version": 0, + "reinit_date": 0, + "priority": 0, + "expire_at": 0 + }, + "version": -1, + "signature": "cvpzkGeuEuKV+d92qIVkln9ngm8qeDnmYtK5rq8uSet0392hAZcIv2IniDzTw0rN42NaOHL9A4KEelwKu1N2Ag==" + }, + { + "@type": "dht.node", + "id": { + "@type": "pub.ed25519", + "key": "nC8dcxV+EV2i0ARvub94IFJKKZUYACfY4xFj1NaG7Pw=" + }, + "addr_list": { + "@type": "adnl.addressList", + "addrs": [ + { + "@type": "adnl.address.udp", + "ip": 1959453117, + "port": 63625 + } + ], + "version": 0, + "reinit_date": 0, + "priority": 0, + "expire_at": 0 + }, + "version": -1, + "signature": "AHF6joNvQhyFFE0itV4OMA9n3Q8CEHVKapCLqazP7QJ4arsn4pdVkRYiGFEyQkngx+cm8izU4gB0JIaxF6PiBg==" + }, + { + "@type": "dht.node", + "id": { + "@type": "pub.ed25519", + "key": "dqsRZLzTg/P7uxUlQpgl4VyTBNYBRMc4js3mnRiolBk=" + }, + "addr_list": { + "@type": "adnl.addressList", + "addrs": [ + { + "@type": "adnl.address.udp", + "ip": -809760973, + "port": 40398 + } + ], + "version": 0, + "reinit_date": 0, + "priority": 0, + "expire_at": 0 + }, + "version": -1, + "signature": "mJxLrAv5RamN5B9mDz6MhQwFjF92D3drJ5efOSZryDaazil0AR4bRHh4vxzZlYiPhi/X/NyG6WwNvKBz+1ntBw==" + }, + { + "@type": "dht.node", + "id": { + "@type": "pub.ed25519", + "key": "fO6cFYRCRrD+yQzOJdHcNWpRFwu+qLhQnddLq0gGbTs=" + }, + "addr_list": { + "@type": "adnl.addressList", + "addrs": [ + { + "@type": "adnl.address.udp", + "ip": 1097633201, + "port": 7201 + } + ], + "version": 0, + "reinit_date": 0, + "priority": 0, + "expire_at": 0 + }, + "version": -1, + "signature": "o/rhtiUL3rvA08TKBcCn0DCiSjsNQdAv41aw7VVUig7ubaqJzYMv1cW3qMjxvsXn1BOugIheJm7voA1/brbtCg==" + } + ], + "@type": "dht.nodes" + }, + "@type": "dht.config.global" + }, + "@type": "config.global", + "validator": { + "zero_state": { + "file_hash": "Z+IKwYS54DmmJmesw/nAD5DzWadnOCMzee+kdgSYDOg=", + "seqno": 0, + "root_hash": "gj+B8wb/AmlPk1z1AhVI484rhrUpgSr2oSFIh56VoSg=", + "workchain": -1, + "shard": -9223372036854775808 + }, + "@type": "validator.config.global", + "init_block": { + "workchain": -1, + "shard": -9223372036854775808, + "seqno": 17908219, + "root_hash": "y6qWqhCnLgzWHjUFmXysaiOljuK5xVoCRMLzUwGInVM=", + "file_hash": "Y/GziXxwuYte0AM4WT7tTWsCx+6rcfLpGmRaEQwhUKI=" + }, + "hardforks": [ + { + "file_hash": "jF3RTD+OyOoP+OI9oIjdV6M8EaOh9E+8+c3m5JkPYdg=", + "seqno": 5141579, + "root_hash": "6JSqIYIkW7y8IorxfbQBoXiuY3kXjcoYgQOxTJpjXXA=", + "workchain": -1, + "shard": -9223372036854775808 + }, + { + "file_hash": "WrNoMrn5UIVPDV/ug/VPjYatvde8TPvz5v1VYHCLPh8=", + "seqno": 5172980, + "root_hash": "054VCNNtUEwYGoRe1zjH+9b1q21/MeM+3fOo76Vcjes=", + "workchain": -1, + "shard": -9223372036854775808 + }, + { + "file_hash": "xRaxgUwgTXYFb16YnR+Q+VVsczLl6jmYwvzhQ/ncrh4=", + "seqno": 5176527, + "root_hash": "SoPLqMe9Dz26YJPOGDOHApTSe5i0kXFtRmRh/zPMGuI=", + "workchain": -1, + "shard": -9223372036854775808 + } + ] + } +} +""".trimIndent() + +private val JSON = + Json { ignoreUnknownKeys = true } + +val TESTNET_GLOBAL_CONFIG: LiteClientConfigGlobal = + JSON.decodeFromString(TESTNET_GLOBAL_CONFIG_JSON) diff --git a/contract/test/wallet/LiteClient.kt b/contract/test/wallet/LiteClient.kt index 94653222..e5fe557b 100644 --- a/contract/test/wallet/LiteClient.kt +++ b/contract/test/wallet/LiteClient.kt @@ -1,24 +1,9 @@ package org.ton.contract.wallet -import io.ktor.util.* import kotlinx.coroutines.Dispatchers -import org.ton.api.liteclient.config.LiteClientConfigGlobal -import org.ton.api.liteserver.LiteServerDesc -import org.ton.api.pub.PublicKeyEd25519 import org.ton.lite.client.LiteClient -import org.ton.tl.asByteString fun liteClientTestnet() = LiteClient( - liteClientConfigGlobal = LiteClientConfigGlobal( - liteServers = listOf( - LiteServerDesc( - id = PublicKeyEd25519( - "B07X5mudyWG3zZu+Ad69+A3jHFkp+0mTrnX5sw+s3ZU=".decodeBase64Bytes().asByteString() - ), - ip = -1178753158, - port = 15400 - ) - ) - ), + liteClientConfigGlobal = TESTNET_GLOBAL_CONFIG, coroutineContext = Dispatchers.Default ) diff --git a/contract/test/wallet/WalletV4Example.kt b/contract/test/wallet/WalletV4Example.kt index 45dbdf37..60947038 100644 --- a/contract/test/wallet/WalletV4Example.kt +++ b/contract/test/wallet/WalletV4Example.kt @@ -4,14 +4,13 @@ import io.github.andreypfau.kotlinx.crypto.sha2.sha256 import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import org.ton.api.pk.PrivateKeyEd25519 -import org.ton.block.AccountInfo +import org.ton.block.Account import org.ton.block.AddrStd import org.ton.block.Coins -import kotlin.test.Ignore import kotlin.test.Test class WalletV4Example { - @Ignore + // @Ignore @Test fun walletExample(): Unit = runBlocking { val liteClient = liteClientTestnet() @@ -25,7 +24,7 @@ class WalletV4Example { println("Wallet Address: $testnetNonBounceAddr") var accountState = liteClient.getAccountState(contract.address) - val account = accountState.account.value as? AccountInfo + val account = accountState.account.value as? Account if (account == null) { println("Account $testnetNonBounceAddr not initialized") return@runBlocking diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts new file mode 100644 index 00000000..499b6597 --- /dev/null +++ b/examples/build.gradle.kts @@ -0,0 +1,36 @@ +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension + +plugins { + kotlin("multiplatform") +} + +kotlin { + jvm() + configureSourceSetsLayout() + + sourceSets { + commonMain { + dependencies { + api(projects.tonKotlinLiteclient) + api(projects.tonKotlinContract) + } + } + } +} + +fun KotlinMultiplatformExtension.configureSourceSetsLayout() { + sourceSets { + all { + if (name.endsWith("Main")) { + val suffix = if (name.startsWith("common")) "" else "@${name.removeSuffix("Main")}" + kotlin.srcDir("src$suffix") + resources.srcDir("resources$suffix") + } + if (name.endsWith("Test")) { + val suffix = if (name.startsWith("common")) "" else "@${name.removeSuffix("Test")}" + kotlin.srcDir("test$suffix") + resources.srcDir("testResources$suffix") + } + } + } +} diff --git a/examples/src/ExtraCurrencyExample.kt b/examples/src/ExtraCurrencyExample.kt new file mode 100644 index 00000000..5b742cc4 --- /dev/null +++ b/examples/src/ExtraCurrencyExample.kt @@ -0,0 +1,58 @@ +package org.ton.kotlin.examples + +import org.ton.api.pk.PrivateKeyEd25519 +import org.ton.block.AddrStd +import org.ton.block.Coins +import org.ton.block.CurrencyCollection +import org.ton.contract.wallet.WalletTransfer +import org.ton.kotlin.currency.VarUInt248 +import org.ton.kotlin.examples.contract.WalletV1R3Contract +import org.ton.kotlin.examples.faucet.TestnetFaucet +import org.ton.kotlin.examples.provider.LiteClientProvider +import org.ton.kotlin.examples.provider.liteClientTestnet +import kotlin.random.Random + +private val swapAddress = AddrStd("kQC_rkxBuZDwS81yvMSLzeXBNLCGFNofm0avwlMfNXCwoOgr") + +@OptIn(ExperimentalStdlibApi::class) +suspend fun main() { + val provider = LiteClientProvider(liteClientTestnet()) + + val seed = Random.nextBytes(32) + println("seed=${seed.toHexString()}") + val key = PrivateKeyEd25519(seed) + val wallet = WalletV1R3Contract(0, key.publicKey(), provider) + println("raw address: ${wallet.address.toString(userFriendly = false)}") + println("pub-key : ${wallet.publicKey.key}") + + val faucet = TestnetFaucet(provider) + + faucet.topUpContract(wallet.address, 55000000000) + var state = requireNotNull(wallet.waitForAccountChange(wallet.getState()?.loadAccount())) + println("new balance: ${state.balance}") + + println("requesting from $swapAddress ECHIDNA...") + wallet.transfer(key, wallet.getSeqno(state), listOf(WalletTransfer { + destination = swapAddress + coins = Coins(5000000000) + })) + + while (true) { + state = requireNotNull(wallet.waitForAccountChange(state)) + println("new balance: ${state.balance}") + if (!state.balance.other.isEmpty()) { + break + } + } + + println("new extra-currency balance ${state.balance.other[100]} ECHIDNA") + + println("send back to $swapAddress") + wallet.transfer(key, wallet.getSeqno(state), listOf(WalletTransfer { + destination = swapAddress + currencyCollection = CurrencyCollection(Coins(100000000), mapOf(100 to VarUInt248(600000000))) + })) + + state = requireNotNull(wallet.waitForAccountChange(state)) + println("new balance: ${state.balance}") +} diff --git a/examples/src/ExtraCurrencyMonitor.kt b/examples/src/ExtraCurrencyMonitor.kt new file mode 100644 index 00000000..776dbc4d --- /dev/null +++ b/examples/src/ExtraCurrencyMonitor.kt @@ -0,0 +1,91 @@ +package org.ton.kotlin.examples + +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.io.bytestring.ByteString +import org.ton.api.pk.PrivateKeyEd25519 +import org.ton.block.* +import org.ton.contract.wallet.MessageData +import org.ton.contract.wallet.WalletTransfer +import org.ton.kotlin.currency.VarUInt248 +import org.ton.kotlin.examples.contract.WalletV1R3Contract +import org.ton.kotlin.examples.faucet.TestnetFaucet +import org.ton.kotlin.examples.provider.LiteClientProvider +import org.ton.kotlin.examples.provider.liteClientTestnet + +private val provider = LiteClientProvider(liteClientTestnet()) +private val swapAddress = AddrStd("kQC_rkxBuZDwS81yvMSLzeXBNLCGFNofm0avwlMfNXCwoOgr") +private val faucet = TestnetFaucet(provider) + +suspend fun main(): Unit = coroutineScope { + val key1 = PrivateKeyEd25519() + val key2 = PrivateKeyEd25519() + var (wallet1, state1) = deployWallet(key1) + val (wallet2, _) = deployWallet(key2) + println("requesting from $swapAddress ECHIDNA...") + wallet1.transfer( + key1, + wallet1.getSeqno(state1), + WalletTransfer { + destination = swapAddress + coins = Coins(3700000000) + } + ) + println("sent transfer message, waiting for extra currency...") + var tx = wallet1.waitForExtraCurrency(100) + println("wallet1 ${wallet1.address.toString(userFriendly = false)} received ${tx.inMsg?.load()?.info.value}") + + println("sending EC wallet1->wallet2...") + state1 = requireNotNull(wallet1.getState()?.loadAccount()) + wallet1.transfer(key1, wallet1.getSeqno(state1), WalletTransfer { + destination = wallet2.address + currencyCollection = CurrencyCollection(mapOf(100 to VarUInt248(300000000))) + messageData = MessageData.text("send EC wallet1->wallet2") + }) + println("transfer sent, waiting for extra currency on wallet2...") + tx = wallet2.waitForExtraCurrency(100) + println("wallet2 received ${tx.inMsg?.load()?.info.value}") +} + + +suspend fun WalletV1R3Contract.waitForExtraCurrency( + id: Int, + fromTxLt: Long? = null, + fromTxHash: ByteString? = null +): Transaction { + while (true) { + for (cellTx in provider.getTransactions(address, fromTxLt, fromTxHash)) { + val tx = cellTx.load() + (tx.inMsg?.load()?.info as? IntMsgInfo)?.value?.get(id) ?: continue + val info = tx.loadInfo() + if (info.bouncePhase !is BouncePhase.Executed) { + return tx + } + throw IllegalStateException( + "Extra currency transaction ${tx.lt}:${cellTx.hash().toHexString()} bounced: ${info.bouncePhase}" + ) + } + delay(2000) + } +} + +suspend fun deployWallet(key: PrivateKeyEd25519): Pair { + val wallet = WalletV1R3Contract(0, key.publicKey(), provider) + println("Deploying wallet...") + println(" raw address: ${wallet.address.toString(userFriendly = false)}") + println("nonBounceableAddress: ${wallet.address.toString(userFriendly = true, bounceable = false)}") + println(" bounceableAddress: ${wallet.address.toString(userFriendly = true, bounceable = true)}") + var account = wallet.getState()?.loadAccount() + println("top up from faucet...") + val faucetRequest = Coins.of(4) + faucet.topUpContract(wallet.address, faucetRequest) + account = wallet.waitForAccountChange(account) { it.balance.coins == faucetRequest } + println("topped up: ${account.balance}") + println("sending state-init to self...") + wallet.transfer(key, wallet.getSeqno(account), WalletTransfer { + destination = wallet.address + }) + account = requireNotNull(wallet.waitForAccountChange(account) { it?.isActive == true }) + println("wallet ${wallet.address.toString(userFriendly = false)} deployed!") + return wallet to account +} \ No newline at end of file diff --git a/examples/src/TestSer.kt b/examples/src/TestSer.kt new file mode 100644 index 00000000..b30bf6c6 --- /dev/null +++ b/examples/src/TestSer.kt @@ -0,0 +1,17 @@ +package org.ton.kotlin.examples + +import org.ton.block.AddrStd +import org.ton.block.CommonMsgInfo +import org.ton.block.ExtInMsgInfo +import org.ton.cell.buildCell +import org.ton.tlb.storeTlb + +fun main() { + val a = ExtInMsgInfo( + null, +// AddrStd(0, BitString("FF".repeat(32))) + AddrStd("kQBZE6MtrDRmMYDNKJwQDDRc1UiiaMRH9XFfrbVQ53zkz2Yl") + ) + val cell = buildCell { storeTlb(CommonMsgInfo, a) } + println(cell.bits.toBinary()) +} \ No newline at end of file diff --git a/examples/src/contract/BaseWalletContract.kt b/examples/src/contract/BaseWalletContract.kt new file mode 100644 index 00000000..e2fe01f8 --- /dev/null +++ b/examples/src/contract/BaseWalletContract.kt @@ -0,0 +1,60 @@ +package contract + +import kotlinx.coroutines.delay +import org.ton.api.pub.PublicKeyEd25519 +import org.ton.api.tonnode.TonNodeBlockIdExt +import org.ton.block.Account +import org.ton.block.AddrStd +import org.ton.block.ShardAccount +import org.ton.block.StateInit +import org.ton.cell.Cell +import org.ton.kotlin.examples.provider.Provider + +abstract class BaseWalletContract( + val workchain: Int = DEFAULT_WORKCHAIN, + val publicKey: PublicKeyEd25519, + val provider: Provider +) { + companion object { + const val DEFAULT_WORKCHAIN = 0 + const val DEFAULT_WALLET_ID: Int = 698983191 + } + + val walletId = DEFAULT_WALLET_ID + workchain + + val stateInit: StateInit by lazy { + StateInit(initCodeCell(), initDataCell()) + } + + val address: AddrStd get() = stateInit.address(workchain) + + abstract val maxMessages: Int + + abstract fun initDataCell(): Cell + + abstract fun initCodeCell(): Cell + + suspend fun getState(blockId: TonNodeBlockIdExt? = null): ShardAccount? = provider.getAccount(address, blockId) + + abstract fun getSeqno(accountInfo: Account?): Int + + suspend fun waitForShardAccountChange(shardAccount: ShardAccount?): ShardAccount? { + while (true) { + val newShardAccount = provider.getAccount(address) + if (newShardAccount != shardAccount) { + return newShardAccount + } + delay(2000) + } + } + + suspend fun waitForAccountChange(account: Account?, condition: (Account?) -> Boolean = { true }): Account? { + while (true) { + val newAccount = provider.getAccount(address)?.loadAccount() + if (newAccount != account && condition(newAccount)) { + return newAccount + } + delay(2000) + } + } +} \ No newline at end of file diff --git a/examples/src/contract/WalletMessage.kt b/examples/src/contract/WalletMessage.kt new file mode 100644 index 00000000..eb78fdd1 --- /dev/null +++ b/examples/src/contract/WalletMessage.kt @@ -0,0 +1,16 @@ +package org.ton.kotlin.examples.contract + +import org.ton.api.pk.PrivateKey +import org.ton.bitstring.BitString +import org.ton.contract.wallet.WalletTransfer + +interface WalletMessage { + val seqno: Int + val transfers: List + + fun sign(privateKey: PrivateKey): SignedWalletMessage +} + +interface SignedWalletMessage : WalletMessage { + val signature: BitString +} \ No newline at end of file diff --git a/examples/src/contract/WalletV1R3Contract.kt b/examples/src/contract/WalletV1R3Contract.kt new file mode 100644 index 00000000..06b034ef --- /dev/null +++ b/examples/src/contract/WalletV1R3Contract.kt @@ -0,0 +1,154 @@ +package org.ton.kotlin.examples.contract + +import contract.BaseWalletContract +import org.ton.api.pk.PrivateKey +import org.ton.api.pub.PublicKeyEd25519 +import org.ton.bitstring.BitString +import org.ton.block.* +import org.ton.boc.BagOfCells +import org.ton.cell.* +import org.ton.contract.wallet.WalletTransfer +import org.ton.kotlin.cell.CellContext +import org.ton.kotlin.examples.provider.Provider +import org.ton.kotlin.message.MessageLayout +import org.ton.tlb.TlbCodec +import org.ton.tlb.TlbStorer +import org.ton.tlb.constructor.AnyTlbConstructor + +open class WalletV1R3Contract( + workchain: Int = DEFAULT_WORKCHAIN, + publicKey: PublicKeyEd25519, + provider: Provider, +) : BaseWalletContract(workchain, publicKey, provider) { + override val maxMessages: Int = 4 + + override fun initDataCell(): Cell { + return CellBuilder.Companion.createCell { + storeUInt(0, 32) + storeBytes(publicKey.key.toByteArray()) + } + } + + override fun initCodeCell(): Cell = CODE + + override fun getSeqno(accountInfo: Account?): Int { + val accountState = accountInfo?.state ?: return 0 + val stateInit = when (accountState) { + is AccountActive -> accountState.value + is AccountFrozen -> throw IllegalStateException("Account ${accountInfo.address} frozen") + AccountUninit -> return 0 + } + val data = requireNotNull(stateInit.data.value).load().beginParse() + return data.loadUInt(32).toInt() + } + + suspend fun transfer(privateKey: PrivateKey, seqno: Int, vararg transfers: WalletTransfer) = + transfer(privateKey, seqno, transfers.toList()) + + suspend fun transfer(privateKey: PrivateKey, seqno: Int, transfers: List) { + val message = WalletV1R3Message(seqno, transfers) + .sign(privateKey) + .toMessage( + address = address, + init = if (seqno == 0) stateInit else null + ) + provider.sendMessage(SignedWalletV1R3Message, message) + } + + open class WalletV1R3Message( + override val seqno: Int, + override val transfers: List, + ) : WalletMessage { + constructor(seqno: Int, vararg transfers: WalletTransfer) : this(seqno, transfers.toList()) + + init { + require(transfers.size <= 4) { "Maximum number of transfers is 4" } + } + + override fun sign(privateKey: PrivateKey): SignedWalletV1R3Message { + val cell = buildCell { + storeTlb(this, this@WalletV1R3Message, CellContext.EMPTY) + } + val signature = BitString(privateKey.sign(cell.hash().toByteArray())) + return SignedWalletV1R3Message(signature, seqno, transfers) + } + + companion object : TlbStorer { + val messageRelaxed = MessageRelaxed.Companion.tlbCodec(AnyTlbConstructor) + + override fun storeTlb( + builder: CellBuilder, + value: WalletV1R3Message, + context: CellContext + ) { + builder.storeUInt(value.seqno.toUInt()) + for (gift in value.transfers) { + val intMsg = gift.toMessageRelaxed() + + builder.storeUInt(gift.sendMode, 8) + builder.storeRef(context) { + messageRelaxed.storeTlb(this, intMsg) + } + } + } + } + } + + class SignedWalletV1R3Message( + override val signature: BitString, + seqno: Int, + transfers: List, + ) : WalletV1R3Message(seqno, transfers), SignedWalletMessage { + override fun sign(privateKey: PrivateKey): SignedWalletV1R3Message = this + + fun toMessage( + address: MsgAddressInt, + init: StateInit? = null, + layout: MessageLayout? = null, + ) = toMessage(null, address, init, layout) + + fun toMessage( + source: AddrExtern?, + address: MsgAddressInt, + init: StateInit? = null, + layout: MessageLayout? = null + ): Message { + val info = ExtInMsgInfo(source, address) + return Message( + info = info, + init = init, + body = this, + bodyCodec = Companion, + layout = layout ?: MessageLayout.compute( + info = info, + init = init, + body = this, + bodyStorer = Companion + ) + ) + } + + companion object : TlbCodec { + override fun storeTlb( + builder: CellBuilder, + value: SignedWalletV1R3Message, + context: CellContext + ) { + builder.storeBitString(value.signature) + WalletV1R3Message.storeTlb(builder, value, context) + } + + override fun loadTlb(cellSlice: CellSlice, context: CellContext): SignedWalletV1R3Message { + TODO("Not yet implemented") + } + } + } + + companion object { + @OptIn(ExperimentalStdlibApi::class) + @JvmField + val CODE = BagOfCells( + "B5EE9C7241010101005F0000BAFF0020DD2082014C97BA218201339CBAB19C71B0ED44D0D31FD70BFFE304E0A4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54B5B86E42".hexToByteArray() + ).first() + } +} \ No newline at end of file diff --git a/examples/src/faucet/TestnetFaucet.kt b/examples/src/faucet/TestnetFaucet.kt new file mode 100644 index 00000000..a43de885 --- /dev/null +++ b/examples/src/faucet/TestnetFaucet.kt @@ -0,0 +1,41 @@ +package org.ton.kotlin.examples.faucet + +import org.ton.api.pk.PrivateKeyEd25519 +import org.ton.bigint.BigInt +import org.ton.block.Coins +import org.ton.block.MsgAddressInt +import org.ton.block.balance +import org.ton.contract.wallet.MessageData +import org.ton.contract.wallet.WalletTransfer +import org.ton.kotlin.examples.contract.WalletV1R3Contract +import org.ton.kotlin.examples.provider.Provider + +class TestnetFaucet( + val provider: Provider +) { + @OptIn(ExperimentalStdlibApi::class) + private val SECRET = + PrivateKeyEd25519("46aab91daaaa375d40588384fdf7e36c62d0c0f38c46adfea7f9c904c5973d97c02ece00eceb299066597ccc7a8ac0b2d08f0ad425f28c0ea92e74e2064f41f0".hexToByteArray()) + val wallet = WalletV1R3Contract(0, SECRET.publicKey(), provider) + + suspend fun topUpContract(destination: MsgAddressInt, amount: BigInt) = + topUpContract(destination, Coins(amount)) + + suspend fun topUpContract(destination: MsgAddressInt, amount: Long) = + topUpContract(destination, Coins(amount)) + + suspend fun topUpContract(destination: MsgAddressInt, amount: Coins) { + var account = provider.getAccount(wallet.address)?.loadAccount() + val seqno = account?.let { wallet.getSeqno(it) } ?: 0 + println("faucet balance: ${account?.balance}") + wallet.transfer(SECRET, seqno, WalletTransfer { + this.destination = destination + this.coins = amount + this.bounceable = false + this.messageData = MessageData.text("github.com/ton-community/ton-kotlin") + }) + println("Waiting for faucet new balance...") + account = wallet.waitForAccountChange(account) + println("New faucet balance: ${account.balance}") + } +} diff --git a/examples/src/provider/GlobalConfig.kt b/examples/src/provider/GlobalConfig.kt new file mode 100644 index 00000000..fc142d30 --- /dev/null +++ b/examples/src/provider/GlobalConfig.kt @@ -0,0 +1,339 @@ +package org.ton.kotlin.examples.provider + +import kotlinx.serialization.json.Json +import org.ton.api.liteclient.config.LiteClientConfigGlobal + +val TESTNET_GLOBAL_CONFIG_JSON = """ +{ + "liteservers": [ + { + "ip": 822907680, + "port": 27842, + "provided":"Beavis", + "id": { + "@type": "pub.ed25519", + "key": "sU7QavX2F964iI9oToP9gffQpCQIoOLppeqL/pdPvpM=" + } + }, + { + "ip": -1468571697, + "port": 27787, + "provided":"Beavis", + "id": { + "@type": "pub.ed25519", + "key": "Y/QVf6G5VDiKTZOKitbFVm067WsuocTN8Vg036A4zGk=" + } + }, + { + "ip": -1468575011, + "port": 51088, + "provided":"Beavis", + "id": { + "@type": "pub.ed25519", + "key": "Sy5ghr3EahQd/1rDayzZXt5+inlfF+7kLfkZDJcU/ek=" + } + }, + { + "ip": 1844203537, + "port": 37537, + "provided":"Neo", + "id": { + "@type": "pub.ed25519", + "key": "K1F7zEe0ETf+SwkefLS56hJE8x42sjCVsBJJuaY7nEA=" + } + }, + { + "ip": 1844203589, + "port": 34411, + "provided":"Neo", + "id": { + "@type": "pub.ed25519", + "key": "pOpRRpIxDuMRm1qFUPpvVjD62vo8azkO0npw4FPcW/I=" + } + }, + { + "ip": 1047529523, + "port": 37649, + "provided":"Neo", + "id": { + "@type": "pub.ed25519", + "key": "pRf2sAa7d+Chl8gDclWOMtthtxjKnLYeAIzk869mMvA=" + } + }, + { + "ip": 1592601963, + "port": 13833, + "id": { + "@type": "pub.ed25519", + "key": "QpVqQiv1u3nCHuBR3cg3fT6NqaFLlnLGbEgtBRukDpU=" + } + }, + { + "ip": 1162057690, + "port": 35939, + "id": { + "@type": "pub.ed25519", + "key": "97y55AkdzXWyyVuOAn+WX6p66XTNs2hEGG0jFUOkCIo=" + } + }, + { + "ip": -1304477830, + "port": 20700, + "id": { + "@type": "pub.ed25519", + "key": "dGLlRRai3K9FGkI0dhABmFHMv+92QEVrvmTrFf5fbqA=" + } + }, + { + "ip": 1959453117, + "port": 20700, + "id": { + "@type": "pub.ed25519", + "key": "24RL7iVI20qcG+j//URfd/XFeEG9qtezW2wqaYQgVKw=" + } + }, + { + "ip": -809760973, + "port": 20700, + "id": { + "@type": "pub.ed25519", + "key": "vunMV7K35yPlTQPx/Fqk6s+4/h5lpcbP+ao0Cy3M2hw=" + } + }, + { + "ip": 1097633201, + "port": 17439, + "id": { + "@type": "pub.ed25519", + "key": "0MIADpLH4VQn+INHfm0FxGiuZZAA8JfTujRqQugkkA8=" + } + }, + { + "ip": 1091956407, + "port": 16351, + "id": { + "@type": "pub.ed25519", + "key": "Mf/JGvcWAvcrN3oheze8RF/ps6p7oL6ifrIzFmGQFQ8=" + } + } + ], + "dht": { + "a": 3, + "k": 3, + "static_nodes": { + "nodes": [ + { + "@type": "dht.node", + "id": { + "@type": "pub.ed25519", + "key": "K2AWu8leN2RjYmhMpYAaGX/F6nGVk9oZw9c09RX3yyc=" + }, + "addr_list": { + "@type": "adnl.addressList", + "addrs": [ + { + "@type": "adnl.address.udp", + "ip": 1592601963, + "port": 38723 + } + ], + "version": 0, + "reinit_date": 0, + "priority": 0, + "expire_at": 0 + }, + "version": -1, + "signature": "21g16jxnqbb2ENAijrZFccHqLQcmmpkAI1HA46DaPvnVYvMkATFNEyHTy2R1T1jgU5M7CCLGJN+MxhwZfl/ZDA==" + }, + { + "@type": "dht.node", + "id": { + "@type": "pub.ed25519", + "key": "fVIJzD9ATMilaPd847eFs6PtGSB67C+D9b4R+nf1+/s=" + }, + "addr_list": { + "@type": "adnl.addressList", + "addrs": [ + { + "@type": "adnl.address.udp", + "ip": 1097649206, + "port": 29081 + } + ], + "version": 0, + "reinit_date": 0, + "priority": 0, + "expire_at": 0 + }, + "version": -1, + "signature": "wH0HEVT6yAfZZAoD5bF6J3EZWdSFwBGl1ZpOfhxZ0Bp2u52tv8OzjeH8tlZ+geMLTG50Csn5nxSKP1tswTWwBg==" + }, + { + "@type": "dht.node", + "id": { + "@type": "pub.ed25519", + "key": "gu+woR+x7PoRmaMqAP7oeOjK2V4U0NU8ofdacWZ34aY=" + }, + "addr_list": { + "@type": "adnl.addressList", + "addrs": [ + { + "@type": "adnl.address.udp", + "ip": 1162057690, + "port": 41578 + } + ], + "version": 0, + "reinit_date": 0, + "priority": 0, + "expire_at": 0 + }, + "version": -1, + "signature": "0PwDLXpN3IbRQuOTLkZBjkbT6+IkeUcvlhWrUY9us3IfSehmCfQjScR9mkVYsQ6cQHF+JeaFmqzV4GAiUcgjAg==" + }, + { + "@type": "dht.node", + "id": { + "@type": "pub.ed25519", + "key": "WC4BO1eZ916FnLBSKmt07Pn5NP4D3/1wary1VjaCLaY=" + }, + "addr_list": { + "@type": "adnl.addressList", + "addrs": [ + { + "@type": "adnl.address.udp", + "ip": -1304477830, + "port": 9670 + } + ], + "version": 0, + "reinit_date": 0, + "priority": 0, + "expire_at": 0 + }, + "version": -1, + "signature": "cvpzkGeuEuKV+d92qIVkln9ngm8qeDnmYtK5rq8uSet0392hAZcIv2IniDzTw0rN42NaOHL9A4KEelwKu1N2Ag==" + }, + { + "@type": "dht.node", + "id": { + "@type": "pub.ed25519", + "key": "nC8dcxV+EV2i0ARvub94IFJKKZUYACfY4xFj1NaG7Pw=" + }, + "addr_list": { + "@type": "adnl.addressList", + "addrs": [ + { + "@type": "adnl.address.udp", + "ip": 1959453117, + "port": 63625 + } + ], + "version": 0, + "reinit_date": 0, + "priority": 0, + "expire_at": 0 + }, + "version": -1, + "signature": "AHF6joNvQhyFFE0itV4OMA9n3Q8CEHVKapCLqazP7QJ4arsn4pdVkRYiGFEyQkngx+cm8izU4gB0JIaxF6PiBg==" + }, + { + "@type": "dht.node", + "id": { + "@type": "pub.ed25519", + "key": "dqsRZLzTg/P7uxUlQpgl4VyTBNYBRMc4js3mnRiolBk=" + }, + "addr_list": { + "@type": "adnl.addressList", + "addrs": [ + { + "@type": "adnl.address.udp", + "ip": -809760973, + "port": 40398 + } + ], + "version": 0, + "reinit_date": 0, + "priority": 0, + "expire_at": 0 + }, + "version": -1, + "signature": "mJxLrAv5RamN5B9mDz6MhQwFjF92D3drJ5efOSZryDaazil0AR4bRHh4vxzZlYiPhi/X/NyG6WwNvKBz+1ntBw==" + }, + { + "@type": "dht.node", + "id": { + "@type": "pub.ed25519", + "key": "fO6cFYRCRrD+yQzOJdHcNWpRFwu+qLhQnddLq0gGbTs=" + }, + "addr_list": { + "@type": "adnl.addressList", + "addrs": [ + { + "@type": "adnl.address.udp", + "ip": 1097633201, + "port": 7201 + } + ], + "version": 0, + "reinit_date": 0, + "priority": 0, + "expire_at": 0 + }, + "version": -1, + "signature": "o/rhtiUL3rvA08TKBcCn0DCiSjsNQdAv41aw7VVUig7ubaqJzYMv1cW3qMjxvsXn1BOugIheJm7voA1/brbtCg==" + } + ], + "@type": "dht.nodes" + }, + "@type": "dht.config.global" + }, + "@type": "config.global", + "validator": { + "zero_state": { + "file_hash": "Z+IKwYS54DmmJmesw/nAD5DzWadnOCMzee+kdgSYDOg=", + "seqno": 0, + "root_hash": "gj+B8wb/AmlPk1z1AhVI484rhrUpgSr2oSFIh56VoSg=", + "workchain": -1, + "shard": -9223372036854775808 + }, + "@type": "validator.config.global", + "init_block": { + "workchain": -1, + "shard": -9223372036854775808, + "seqno": 17908219, + "root_hash": "y6qWqhCnLgzWHjUFmXysaiOljuK5xVoCRMLzUwGInVM=", + "file_hash": "Y/GziXxwuYte0AM4WT7tTWsCx+6rcfLpGmRaEQwhUKI=" + }, + "hardforks": [ + { + "file_hash": "jF3RTD+OyOoP+OI9oIjdV6M8EaOh9E+8+c3m5JkPYdg=", + "seqno": 5141579, + "root_hash": "6JSqIYIkW7y8IorxfbQBoXiuY3kXjcoYgQOxTJpjXXA=", + "workchain": -1, + "shard": -9223372036854775808 + }, + { + "file_hash": "WrNoMrn5UIVPDV/ug/VPjYatvde8TPvz5v1VYHCLPh8=", + "seqno": 5172980, + "root_hash": "054VCNNtUEwYGoRe1zjH+9b1q21/MeM+3fOo76Vcjes=", + "workchain": -1, + "shard": -9223372036854775808 + }, + { + "file_hash": "xRaxgUwgTXYFb16YnR+Q+VVsczLl6jmYwvzhQ/ncrh4=", + "seqno": 5176527, + "root_hash": "SoPLqMe9Dz26YJPOGDOHApTSe5i0kXFtRmRh/zPMGuI=", + "workchain": -1, + "shard": -9223372036854775808 + } + ] + } +} +""".trimIndent() + +private val JSON = + Json { ignoreUnknownKeys = true } + +val TESTNET_GLOBAL_CONFIG: LiteClientConfigGlobal = + JSON.decodeFromString(TESTNET_GLOBAL_CONFIG_JSON) diff --git a/examples/src/provider/LiteClient.kt b/examples/src/provider/LiteClient.kt new file mode 100644 index 00000000..3205257c --- /dev/null +++ b/examples/src/provider/LiteClient.kt @@ -0,0 +1,9 @@ +package org.ton.kotlin.examples.provider + +import kotlinx.coroutines.Dispatchers +import org.ton.lite.client.LiteClient + +fun liteClientTestnet() = LiteClient( + liteClientConfigGlobal = TESTNET_GLOBAL_CONFIG, + coroutineContext = Dispatchers.Default +) diff --git a/examples/src/provider/Provider.kt b/examples/src/provider/Provider.kt new file mode 100644 index 00000000..2e5a6857 --- /dev/null +++ b/examples/src/provider/Provider.kt @@ -0,0 +1,94 @@ +package org.ton.kotlin.examples.provider + +import kotlinx.io.bytestring.ByteString +import org.ton.api.tonnode.TonNodeBlockIdExt +import org.ton.block.Message +import org.ton.block.MsgAddressInt +import org.ton.block.ShardAccount +import org.ton.block.Transaction +import org.ton.boc.BagOfCells +import org.ton.cell.CellBuilder +import org.ton.cell.CellSlice +import org.ton.cell.buildCell +import org.ton.kotlin.cell.CellContext +import org.ton.lite.client.LiteClient +import org.ton.lite.client.internal.TransactionId +import org.ton.tlb.CellRef +import org.ton.tlb.TlbCodec +import org.ton.tlb.TlbStorer +import org.ton.tlb.storeTlb + +interface Provider { + suspend fun getLastBlockId(): TonNodeBlockIdExt + + suspend fun getAccount(address: MsgAddressInt, blockId: TonNodeBlockIdExt? = null): ShardAccount? + + suspend fun sendMessage(serializer: TlbStorer, message: Message) + suspend fun getTransactions( + address: MsgAddressInt, + fromTxLt: Long? = null, + fromTxHash: ByteString? = null + ): List> +} + +class LiteClientProvider( + val liteClient: LiteClient +) : Provider { + override suspend fun getLastBlockId(): TonNodeBlockIdExt { + return liteClient.getLastBlockId() + } + + override suspend fun getAccount( + address: MsgAddressInt, + blockId: TonNodeBlockIdExt? + ): ShardAccount? { + val state = if (blockId == null) { + liteClient.getAccountState(address) + } else { + liteClient.getAccountState(address, blockId) + } + val lastTransactionId = state.lastTransactionId + if (lastTransactionId != null) { + return ShardAccount( + state.account, + ByteString(*lastTransactionId.hash.toByteArray()), + lastTransactionId.lt + ) + } else { + return ShardAccount( + state.account, + ByteString(*ByteArray(32)), + 0 + ) + } + } + + override suspend fun sendMessage(serializer: TlbStorer, message: Message) { + val cell = buildCell { + val codec = Message.tlbCodec(object : TlbCodec { + override fun storeTlb(cellBuilder: CellBuilder, value: T, context: CellContext) = + serializer.storeTlb(cellBuilder, value, context) + + override fun loadTlb(cellSlice: CellSlice, context: CellContext): T = + throw UnsupportedOperationException() + }) + storeTlb(codec, message) + } + val boc = BagOfCells(cell) + liteClient.sendMessage(boc) + } + + override suspend fun getTransactions( + address: MsgAddressInt, + fromTxLt: Long?, + fromTxHash: ByteString? + ): List> { + if (fromTxLt == null || fromTxHash == null) { + val account = getAccount(address) ?: return emptyList() + return getTransactions(address, account.lastTransLt, account.lastTransHash) + } + return liteClient.getTransactions(address, TransactionId(fromTxHash.toByteArray(), fromTxLt), 10).map { + it.transaction + } + } +} \ No newline at end of file diff --git a/hashmap-tlb/src/Dictionary.kt b/hashmap-tlb/src/Dictionary.kt index eab3b7e9..370f89ec 100644 --- a/hashmap-tlb/src/Dictionary.kt +++ b/hashmap-tlb/src/Dictionary.kt @@ -1,17 +1,238 @@ -package org.ton.hashmap +@file:Suppress("PackageDirectoryMismatch") -import org.ton.bitstring.BitString +package org.ton.kotlin.dict -public interface Dictionary { - public interface Leaf { - public val value: X +import org.ton.cell.Cell +import org.ton.cell.CellBuilder +import org.ton.kotlin.cell.CellContext +import org.ton.tlb.TlbCodec + +public open class Dictionary( + public val dict: RawDictionary, + protected val keyCodec: DictionaryKeyCodec, + protected val valueCodec: TlbCodec, + protected val context: CellContext = CellContext.EMPTY +) : Map { + init { + require(dict.keySize == keyCodec.keySize) + } + + public constructor( + cell: Cell?, + keyCodec: DictionaryKeyCodec, + valueCodec: TlbCodec, + context: CellContext = CellContext.EMPTY + ) : this( + RawDictionary(cell, keyCodec.keySize), + keyCodec, + valueCodec, + context + ) + + public constructor( + map: Map, + keyCodec: DictionaryKeyCodec, + valueCodec: TlbCodec, + context: CellContext = CellContext.EMPTY + ) : this(RawDictionary(keyCodec.keySize).apply { + val builder = CellBuilder() + map.forEach { (key, value) -> + builder.reset() + valueCodec.storeTlb(builder, value, context) + val slice = builder.endCell().beginParse() + val bitString = keyCodec.encodeKey(key) + set(bitString, slice, context) + } + }, keyCodec, valueCodec, context) + + public constructor( + dictionary: Dictionary, + context: CellContext = CellContext.EMPTY + ) : this( + dictionary.dict.root, + dictionary.keyCodec, + dictionary.valueCodec, + context + ) + + public val cell: Cell? get() = dict.root + + override val size: Int + get() = dict.iterator(context).asSequence().count() + + override val keys: Set + get() = loadKeys().toSet() + + override val values: Collection + get() = loadValues().toList() + + override val entries: Set> + get() = loadEntries().toSet() + + public fun loadEntries(context: CellContext = this.context): Sequence> = + dict.iterator(context).asSequence().map { (key, value) -> + val value = valueCodec.loadTlb(value, context) + val key = keyCodec.decodeKey(key) + DictEntry(key, value) + } + + public fun loadKeys(context: CellContext = this.context): Sequence = + dict.iterator(context).asSequence().map { (key, _) -> + keyCodec.decodeKey(key) + } + + public fun loadValues(context: CellContext = this.context): Sequence = + dict.iterator(context).asSequence().map { (_, value) -> + valueCodec.loadTlb(value, context) + } + + override fun isEmpty(): Boolean { + return dict.isEmpty() } - public interface Entry { - public val key: BitString - public val leaf: Leaf + override fun containsKey(key: K): Boolean { + return dict[keyCodec.encodeKey(key)] != null + } - public operator fun component1(): BitString = key - public operator fun component2(): X = leaf.value + override fun containsValue(value: V): Boolean { + return loadValues().contains(value) } + + override fun get(key: K): V? = get(key, context) + + public fun get(key: K, context: CellContext = this.context): V? { + return valueCodec.loadTlb(dict.get(keyCodec.encodeKey(key), context) ?: return null, context) + } + + public fun toMap(context: CellContext = this.context): Map { + if (dict.isEmpty()) return emptyMap() + return toMap(LinkedHashMap(), context) + } + + public fun > toMap(destination: M, context: CellContext = this.context): M { + if (dict.isEmpty()) return destination + dict.iterator(context).forEach { (key, value) -> + val value = valueCodec.loadTlb(value, context) + val key = keyCodec.decodeKey(key) + destination[key] = value + } + return destination + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + other as Dictionary<*, *> + return dict == other.dict + } + + override fun hashCode(): Int = dict.hashCode() + + override fun toString(): String = dict.toString() + + private inner class DictEntry( + override val key: K, + override val value: V, + ) : Map.Entry } + +public fun Map.toDictionary( + keyCodec: DictionaryKeyCodec, + valueCodec: TlbCodec, + context: CellContext = CellContext.EMPTY +): Dictionary = Dictionary(this, keyCodec, valueCodec, context) + +public fun foo() { + val dictionary: Dictionary = Any() as Dictionary + dictionary.toMap() +} + +// +//public open class MutableDictionary( +// dict: RawDictionary, +// keySerializer: (K) -> BitString, +// keyDeserializer: (BitString) -> K, +// valueSerializer: TlbCodec, +//) : Dictionary(dict, keySerializer, keyDeserializer, valueSerializer), MutableMap { +// override val keys: MutableSet +// get() = TODO("Not yet implemented") +// override val values: MutableCollection +// get() = TODO("Not yet implemented") +// override val entries: MutableSet> +// get() = object : MutableSet> { +// val entries = loadEntries(CellContext.EMPTY) +// +// override fun iterator(): MutableIterator> = entries.iterator() +// +// override fun add(element: MutableMap.MutableEntry): Boolean { +// TODO("Not yet implemented") +// } +// +// override fun remove(element: MutableMap.MutableEntry): Boolean { +// TODO("Not yet implemented") +// } +// +// override fun addAll(elements: Collection>): Boolean { +// TODO("Not yet implemented") +// } +// +// override fun removeAll(elements: Collection>): Boolean { +// TODO("Not yet implemented") +// } +// +// override fun retainAll(elements: Collection>): Boolean { +// TODO("Not yet implemented") +// } +// +// override fun clear() { +// TODO("Not yet implemented") +// } +// +// override val size: Int +// get() = TODO("Not yet implemented") +// +// override fun isEmpty(): Boolean { +// TODO("Not yet implemented") +// } +// +// override fun contains(element: MutableMap.MutableEntry): Boolean { +// TODO("Not yet implemented") +// } +// +// override fun containsAll(elements: Collection>): Boolean { +// TODO("Not yet implemented") +// } +// +// } +// +// override fun put(key: K, value: V): V? { +// val serializedKey = keySerializer(key) +// val serializedValue = CellBuilder().apply { +// storeTlb(valueCodec, value) +// }.endCell().beginParse() +// return dict.set(serializedKey, serializedValue)?.run { +// loadTlb(valueCodec) +// } +// } +// +// override fun remove(key: K): V? { +// val serializedKey = keySerializer(key) +// return dict.remove(serializedKey)?.run { +// loadTlb(valueCodec) +// } +// } +// +// override fun putAll(from: Map) { +// from.forEach { (key, value) -> +// put(key, value) +// } +// } +// +// override fun clear() { +// dict.clear() +// } +// +// private class EntriesSet( +// set: Map.Entry, +// ) : MutableSet +//} diff --git a/hashmap-tlb/src/DictionaryKeyCodec.kt b/hashmap-tlb/src/DictionaryKeyCodec.kt new file mode 100644 index 00000000..a537bb37 --- /dev/null +++ b/hashmap-tlb/src/DictionaryKeyCodec.kt @@ -0,0 +1,67 @@ +@file:Suppress("PackageDirectoryMismatch") + +package org.ton.kotlin.dict + +import org.ton.bitstring.BitString +import org.ton.cell.CellSlice +import org.ton.cell.buildCell + +public interface DictionaryKeyCodec : DictionaryKeyLoader, DictionaryKeyStorer { + public companion object { + public val INT32: DictionaryKeyCodec = int() + + public val BITS256: DictionaryKeyCodec = object : DictionaryKeyCodec { + override val keySize: Int get() = 256 + + override fun decodeKey(value: BitString): BitString { + require(value.size == 256) + return value + } + + override fun encodeKey(value: BitString): BitString { + require(value.size == 256) + return value + } + } + + public fun long(keySize: Int = Long.SIZE_BITS): DictionaryKeyCodec = object : DictionaryKeyCodec { + override val keySize: Int = keySize + + override fun decodeKey(value: BitString): Long { + return CellSlice(value).loadLong(keySize) + } + + override fun encodeKey(value: Long): BitString { + return buildCell { + storeLong(value, keySize) + }.bits + } + } + + public fun int(keySize: Int = Int.SIZE_BITS): DictionaryKeyCodec = object : DictionaryKeyCodec { + override val keySize: Int = keySize + + override fun decodeKey(value: BitString): Int { + return CellSlice(value).loadInt(keySize).toInt() + } + + override fun encodeKey(value: Int): BitString { + return buildCell { + storeInt(value, keySize) + }.bits + } + } + } +} + +public interface DictionaryKeyLoader { + public val keySize: Int + + public fun decodeKey(value: BitString): K +} + +public interface DictionaryKeyStorer { + public val keySize: Int + + public fun encodeKey(value: K): BitString +} diff --git a/hashmap-tlb/src/DictionarySet.kt b/hashmap-tlb/src/DictionarySet.kt new file mode 100644 index 00000000..a42d2c56 --- /dev/null +++ b/hashmap-tlb/src/DictionarySet.kt @@ -0,0 +1,26 @@ +@file:Suppress("PackageDirectoryMismatch") + +package org.ton.kotlin.dict + +internal enum class SetMode( + val mask: Int +) { + /** + * Sets the value associated with the key in the dictionary. + */ + Set(0b11), + + /** + * Sets the value associated with the key in the dictionary only if the key was already present in it. + */ + Replace(0b01), + + /** + * Sets the value associated with key in dictionary, but only if it is not already present. + */ + Add(0b10); + + fun canReplace(): Boolean = mask and 0b01 != 0 + + fun canAdd(): Boolean = mask and 0b10 != 0 +} \ No newline at end of file diff --git a/hashmap-tlb/src/HashMapE.kt b/hashmap-tlb/src/HashMapE.kt index e230654a..c7334202 100644 --- a/hashmap-tlb/src/HashMapE.kt +++ b/hashmap-tlb/src/HashMapE.kt @@ -16,8 +16,6 @@ public sealed interface HashMapE : Iterable>, TlbObject { override fun iterator(): Iterator> - public fun set(key: BitString, value: T): HmeRoot - public companion object { @Suppress("UNCHECKED_CAST") @JvmStatic @@ -29,19 +27,6 @@ public sealed interface HashMapE : Iterable>, TlbObject { @JvmStatic public fun root(root: CellRef>): HashMapE = HmeRoot(root) - public fun fromMap(map: Map?): HashMapE { - var hashMap = empty() - if (map == null) return hashMap - var i = -1 - map.forEach { (key, value) -> - require(!key.isEmpty()) { "Empty key" } - if (i == -1) i = key.size - else require(i == key.size) { "Variable length key, expected: $i, actual: (${key.size}) $key" } - hashMap = hashMap.set(key, value) - } - return hashMap - } - @Suppress("UNCHECKED_CAST") @JvmStatic public fun tlbCodec(n: Int, x: TlbCodec): TlbCodec> { diff --git a/hashmap-tlb/src/HashMapNode.kt b/hashmap-tlb/src/HashMapNode.kt index c326350b..c2f85239 100644 --- a/hashmap-tlb/src/HashMapNode.kt +++ b/hashmap-tlb/src/HashMapNode.kt @@ -21,11 +21,6 @@ public sealed interface HashMapNode : TlbObject { HmnFork.tlbCodec(n, x) } as TlbCodec> - public fun fork( - left: HmEdge, - right: HmEdge - ): HmnFork = HmnFork(left, right) - public fun leaf(value: T): HmnLeaf = HmnLeaf(value) } } diff --git a/hashmap-tlb/src/HashmapAugE.kt b/hashmap-tlb/src/HashmapAugE.kt index 62d20285..625b00ae 100644 --- a/hashmap-tlb/src/HashmapAugE.kt +++ b/hashmap-tlb/src/HashmapAugE.kt @@ -6,6 +6,7 @@ import kotlinx.serialization.json.JsonClassDiscriminator import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice +import org.ton.kotlin.cell.CellContext import org.ton.tlb.* import kotlin.jvm.JvmStatic @@ -122,14 +123,14 @@ private class AhmeEmptyTlbConstructor( ) : TlbConstructor>( schema = "ahme_empty\$0 {n:#} {X:Type} {Y:Type} extra:Y = HashmapAugE n X Y" ) { - override fun loadTlb(cellSlice: CellSlice): HashmapAugE.AhmeEmpty { - val extra = y.loadTlb(cellSlice) + override fun loadTlb(cellSlice: CellSlice, context: CellContext): HashmapAugE.AhmeEmpty { + val extra = y.loadTlb(cellSlice, context) return AhmeEmptyImpl(n, extra) } - override fun storeTlb(cellBuilder: CellBuilder, value: HashmapAugE.AhmeEmpty) { + override fun storeTlb(cellBuilder: CellBuilder, value: HashmapAugE.AhmeEmpty, context: CellContext) { require(value.n == n) { "n mismatch, expected: $n, actual: ${value.n}" } - y.storeTlb(cellBuilder, value.extra) + y.storeTlb(cellBuilder, value.extra, context) } } @@ -142,15 +143,15 @@ private class AhmeRootTlbConstructor( ) { private val hashmapAug = HashmapAug.tlbCodec(n, x, y) - override fun loadTlb(cellSlice: CellSlice): HashmapAugE.AhmeRoot { + override fun loadTlb(cellSlice: CellSlice, context: CellContext): HashmapAugE.AhmeRoot { val root = cellSlice.loadRef(hashmapAug) - val extra = y.loadTlb(cellSlice) + val extra = y.loadTlb(cellSlice, context) return AhmeRootImpl(n, root, extra) } - override fun storeTlb(cellBuilder: CellBuilder, value: HashmapAugE.AhmeRoot) { + override fun storeTlb(cellBuilder: CellBuilder, value: HashmapAugE.AhmeRoot, context: CellContext) { require(value.n == n) { "n mismatch, expected: $n, actual: ${value.n}" } cellBuilder.storeRef(hashmapAug, value.root) - y.storeTlb(cellBuilder, value.extra) + y.storeTlb(cellBuilder, value.extra, context) } } diff --git a/hashmap-tlb/src/HashmapAugNode.kt b/hashmap-tlb/src/HashmapAugNode.kt index 54a50fdb..2f415cb3 100644 --- a/hashmap-tlb/src/HashmapAugNode.kt +++ b/hashmap-tlb/src/HashmapAugNode.kt @@ -2,6 +2,7 @@ package org.ton.hashmap import org.ton.cell.CellBuilder import org.ton.cell.CellSlice +import org.ton.kotlin.cell.CellContext import org.ton.tlb.* import kotlin.jvm.JvmStatic @@ -112,15 +113,15 @@ private class AhmnLeafTlbConstructor( ) : TlbConstructor>( schema = "ahmn_leaf#_ {X:Type} {Y:Type} extra:Y value:X = HashmapAugNode 0 X Y" ) { - override fun loadTlb(cellSlice: CellSlice): HashmapAugNode.AhmnLeaf { - val extra = y.loadTlb(cellSlice) - val value = x.loadTlb(cellSlice) + override fun loadTlb(cellSlice: CellSlice, context: CellContext): HashmapAugNode.AhmnLeaf { + val extra = y.loadTlb(cellSlice, context) + val value = x.loadTlb(cellSlice, context) return AhmnLeafImpl(extra, value) } - override fun storeTlb(cellBuilder: CellBuilder, value: HashmapAugNode.AhmnLeaf) { - y.storeTlb(cellBuilder, value.extra) - x.storeTlb(cellBuilder, value.value) + override fun storeTlb(cellBuilder: CellBuilder, value: HashmapAugNode.AhmnLeaf, context: CellContext) { + y.storeTlb(cellBuilder, value.extra, context) + x.storeTlb(cellBuilder, value.value, context) } } diff --git a/hashmap-tlb/src/HmEdge.kt b/hashmap-tlb/src/HmEdge.kt index 69495555..c2cce67a 100644 --- a/hashmap-tlb/src/HmEdge.kt +++ b/hashmap-tlb/src/HmEdge.kt @@ -16,43 +16,6 @@ public data class HmEdge( ) : Iterable>, TlbObject { override fun iterator(): Iterator> = HmEdgeIterator(this) - public fun set(key: BitString, value: T): HmEdge { - check(!key.isEmpty()) - val label = label.toBitString() - if (label == key) { - // replace existing leaf - return HmEdge(this.label, HmnLeaf(value)) - } else if (label.isEmpty()) { - // 1-bit edge - node as HmnFork - return HmEdge(this.label, node.set(key, value)) - } else { - val labelPrefix = label.commonPrefixWith(key) - val labelReminder = label.slice(labelPrefix.size) - val keyReminder = key.slice(labelPrefix.size) - - if (keyReminder.isEmpty()) { - throw IllegalArgumentException("variable length key: $key") - } else if (!labelReminder.isEmpty() && !keyReminder.isEmpty()) { - // forking - val (left, right) = if (keyReminder[0]) { - HmEdge(HmLabel(labelReminder.slice(1)), node) to - HmEdge(HmLabel(keyReminder.slice(1)), HmnLeaf(value)) - } else { - HmEdge(HmLabel(keyReminder.slice(1)), HmnLeaf(value)) to - HmEdge(HmLabel(labelReminder.slice(1)), node) - } - return HmEdge(HmLabel(labelPrefix), HmnFork(left, right)) - } else if (!labelPrefix.isEmpty() && labelReminder.isEmpty() && !keyReminder.isEmpty()) { - // next iteration - node as HmnFork - val newNode = node.set(keyReminder, value) - return HmEdge(HmLabel(labelPrefix), newNode) - } - throw IllegalStateException() - } - } - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { type("hm_edge") { field("label", label) diff --git a/hashmap-tlb/src/HmeEmpty.kt b/hashmap-tlb/src/HmeEmpty.kt index d6e2c432..36eebe3d 100644 --- a/hashmap-tlb/src/HmeEmpty.kt +++ b/hashmap-tlb/src/HmeEmpty.kt @@ -13,11 +13,6 @@ public class HmeEmpty : HashMapE { override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer.type("hme_empty") - override fun set(key: BitString, value: T): HmeRoot { - val root = HmEdge(HmLabel(key), HmnLeaf(value)) - return HmeRoot(root) - } - override fun toString(): String = print().toString() } diff --git a/hashmap-tlb/src/HmeRoot.kt b/hashmap-tlb/src/HmeRoot.kt index 93a59603..cf86cfcc 100644 --- a/hashmap-tlb/src/HmeRoot.kt +++ b/hashmap-tlb/src/HmeRoot.kt @@ -15,15 +15,9 @@ public data class HmeRoot( val root: CellRef> ) : HashMapE { public constructor(root: Cell, tlbCodec: TlbCodec>) : this(CellRef(root, tlbCodec)) - public constructor(root: HmEdge) : this(CellRef(root)) override fun iterator(): Iterator> = root.value.iterator() - override fun set(key: BitString, value: T): HmeRoot { - val root = root.value.set(key, value) - return HmeRoot(root) - } - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer { type("hme_root") { field("root", root) diff --git a/hashmap-tlb/src/HmnFork.kt b/hashmap-tlb/src/HmnFork.kt index 5200b391..e827c6e0 100644 --- a/hashmap-tlb/src/HmnFork.kt +++ b/hashmap-tlb/src/HmnFork.kt @@ -14,33 +14,11 @@ public data class HmnFork( val left: CellRef>, val right: CellRef> ) : HashMapNode { - public constructor( - left: HmEdge, - right: HmEdge, - ) : this( - left = CellRef(left), - right = CellRef(right) - ) - override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter = printer.type("hmn_fork") { field("left", left) field("right", right) } - public fun set(key: BitString, value: T): HmnFork { - return if (key[0]) { - copy( - left = left, - right = CellRef(right.value.set(key.slice(1), value)) - ) - } else { - copy( - left = CellRef(left.value.set(key.slice(1), value)), - right = right, - ) - } - } - override fun toString(): String = print().toString() public companion object { diff --git a/hashmap-tlb/src/Label.kt b/hashmap-tlb/src/Label.kt new file mode 100644 index 00000000..d7bc09db --- /dev/null +++ b/hashmap-tlb/src/Label.kt @@ -0,0 +1,89 @@ +@file:Suppress("PackageDirectoryMismatch") + +package org.ton.kotlin.dict + +import org.ton.bitstring.BitString +import org.ton.bitstring.ByteBackedBitString +import org.ton.cell.CellBuilder +import org.ton.cell.CellSlice +import org.ton.cell.storeUInt + +internal fun CellBuilder.storeLabel( + maxKeyLength: Int, + key: BitString, + startIndex: Int, + endIndex: Int +) { + val length = endIndex - startIndex + if (length == 0) { + // mode 'hml_short$0', requires 2n+2 bits (always for n=0) + storeUInt(0u, 2) + return + } + val k = Int.SIZE_BITS - maxKeyLength.countLeadingZeroBits() + + val firstBit = key[startIndex] + when { + length > 1 && k < 2 * length - 1 && length == key.countLeadingBits(startIndex, endIndex, firstBit) -> { + // mode 'hml_same$11', requires 3+k bits (for n>=2, k<2n-1) + storeUInt(if (firstBit) 0b111u else 0b110u, 3) + storeUInt(length.toUInt(), k) + return + } + + k < length -> { + // mode 'hml_long$10', requires 2+k+n bits + storeUInt(0b10u, 2) // tag hml_long$10 + storeUInt(length.toUInt(), k) // 'n:(#<= m)' from hml_long + } + + else -> { + // mode 'hml_short$0', requires 1+2n+1 bits + storeBoolean(false) // tag hml_short$0 + // 'len:(Unary ~n)' from hml_short, + // where -0b10 = 0b1111_1111_1111_1110, + // unary_succ$1 - counter for n + // unary_zero$0 - terminator for counter + // 1110 -> n=3 + 1 terminator bit + storeLong(-0b10, length + 1) + } + } + storeBitString(key, startIndex, endIndex) +} + +internal fun CellSlice.readLabel(keyBitLength: Int): BitString { + val labelType = preloadUInt(2).toInt() + when (labelType) { + // hml_short$0 unary_zero$0 + 0b00 -> { + skipBits(2) + return BitString.empty() + } + // hml_short$0 unary_succ$1 + 0b01 -> { + skipBits(1) + val len = countLeadingBits(bit = true) + skipBits(len + 1) + return loadBitString(len) + } + // hml_long$10 + 0b10 -> { + skipBits(2) + val len = loadUIntLeq(keyBitLength).toInt() + return loadBitString(len) + } + // hml_same$11 + 0b11 -> { + skipBits(2) + val sameBit = loadBoolean() + val len = loadUIntLeq(keyBitLength).toInt() + val bytes = ByteArray((len + 7) ushr 3) + if (sameBit) { + bytes.fill(0xFF.toByte()) + } + return ByteBackedBitString.of(bytes, len) + } + + else -> throw IllegalArgumentException("Invalid label type: $labelType") + } +} diff --git a/hashmap-tlb/src/RawDictionary.kt b/hashmap-tlb/src/RawDictionary.kt new file mode 100644 index 00000000..ff012895 --- /dev/null +++ b/hashmap-tlb/src/RawDictionary.kt @@ -0,0 +1,383 @@ +@file:Suppress("PackageDirectoryMismatch") + +package org.ton.kotlin.dict + +import org.ton.bitstring.BitString +import org.ton.bitstring.ByteBackedMutableBitString +import org.ton.cell.Cell +import org.ton.cell.CellBuilder +import org.ton.cell.CellSlice +import org.ton.cell.DataCell +import org.ton.cell.exception.CellUnderflowException +import org.ton.kotlin.cell.CellContext + +/** + * Typed dictionary with fixed length keys. + */ +public class RawDictionary( + root: Cell?, + public val keySize: Int, +) : Iterable> { + public var root: Cell? = root + private set + + public constructor( + keySize: Int, + ) : this(null, keySize) + + public fun isEmpty(): Boolean = root == null + + public fun isNotEmpty(): Boolean = !isEmpty() + + public fun iterator(context: CellContext): Iterator> = + RawDictIterator(root, keySize, context) + + override fun iterator(): Iterator> = iterator(CellContext.EMPTY) + + public operator fun set(key: BitString, value: CellSlice): CellSlice? = set(key, value, CellContext.EMPTY) + + public fun set( + key: BitString, + value: CellSlice, + context: CellContext, + ): CellSlice? { + return dictSet( + key, + 0, + key.size, + value, + SetMode.Set, + context, + ) + } + + public operator fun get(key: BitString): CellSlice? = get(key, CellContext.EMPTY) + + public operator fun contains(key: BitString): Boolean = get(key) != null + + public fun get( + key: BitString, + context: CellContext, + ): CellSlice? { + require(key.size == keySize) + var data = context.loadCell(root ?: return null).beginParse() + var n = keySize + var keyOffset = 0 + while (true) { + val label = data.readLabel(n) + if (!label.isEmpty() && commonPrefixLength(label, key, keyOffset) == 0) { + return null + } + n = n - label.size + if (n <= 0) { + return data + } + keyOffset += label.size + val bit = if (key[keyOffset++]) 1 else 0 + n-- + data = context.loadCell(data.preloadRef(bit)).beginParse() + } + } + + public fun clear() { + this.root = null + } + + // TODO: optimize + public fun remove(key: BitString, context: CellContext = CellContext.EMPTY): CellSlice? { + require(key.size == keySize) + val newDict = RawDictionary(null, keySize) + var found: CellSlice? = null + iterator(context).forEach { (k, v) -> + if (key != k) { + newDict.set(k, v, context) + } else { + found = v + } + } + root = newDict.root + return found + } + + private fun commonPrefixLength( + label: BitString, + key: BitString, + keyOffset: Int = 0, + ): Int { + val shortestLength = minOf(key.size, label.size) + var prefixLen = 0 + while (prefixLen < shortestLength && key[keyOffset + prefixLen] == label[prefixLen]) { + prefixLen++ + } + return prefixLen + } + + private fun dictSet( + key: BitString, + startIndex: Int, + endIndex: Int, + value: CellSlice, + mode: SetMode, + context: CellContext + ): CellSlice? { + val root = root + if (root == null) { + if (mode == SetMode.Replace) { + return null + } + val builder = CellBuilder() + builder.storeLabel(keySize, key, startIndex, endIndex) + builder.storeSlice(value) + this.root = context.finalizeCell(builder) + return null + } + var keyOffset: Int = startIndex + var data = context.loadCell(root) + val builder = CellBuilder() + + val stack = ArrayDeque() + var leaf: Cell + var oldValue: CellSlice? = null + while (true) { + var keyLength = endIndex - keyOffset + val remainingData = data.beginParse() + + val label = remainingData.readLabel(keyLength) + + val prefixLen = commonPrefixLength(label, key, keyOffset) + + if (prefixLen == keyLength) { + if (mode == SetMode.Add) { + return stack.lastOrNull()?.data?.beginParse() + } + builder.reset() + builder.storeLabel(keySize, key, startIndex, endIndex) + builder.storeSlice(value) + leaf = context.finalizeCell(builder) + oldValue = remainingData + break + } else if (prefixLen < keyLength) { + if (prefixLen < label.size) { + // have to insert a new node (fork) inside the current edge + if (mode == SetMode.Replace) { + return null + } + val prevKeyLength = keyLength + keyOffset += prefixLen + 1 + keyLength = endIndex - keyOffset + val oldToRight = label[prefixLen] +// println("label: ${label.toBinary().substring(prefixLen + 1, label.size)}") +// println("key length: $keyLength") +// println("rem data: ${remainingData.data.toBinary()}") + builder.reset() + builder.storeLabel(keyLength, label, prefixLen + 1, label.size) + builder.storeSlice(remainingData) + val left = context.finalizeCell(builder) + + builder.reset() + builder.storeLabel(keyLength, key, keyOffset, endIndex) + builder.storeSlice(value) + val right = context.finalizeCell(builder) +// println("tree left: ${left}") +// println("data left: ${left.bits.toBinary()}") +// println("leaf right: ${right.hash()}") + builder.reset() + builder.storeLabel(prevKeyLength, label, 0, prefixLen) + if (oldToRight) { + builder.storeRef(right) + builder.storeRef(left) + } else { + builder.storeRef(left) + builder.storeRef(right) + } + + leaf = context.finalizeCell(builder) + break + } + + if (data.refs.size != 2) { + throw CellUnderflowException("Not enough references in fork") + } + keyOffset += prefixLen + val nextBranch = key[keyOffset++] + val child = context.loadCell(data.refs[if (nextBranch) 1 else 0]) +// println("child: ${child.hash()}") + stack.addLast( + Segment( + data = data, + isRightNext = nextBranch, + keyBitLength = keyLength + ) + ) + data = child + } else { + throw RuntimeException("LCP of prefix and key can't be greater than key") + } + } + +// println("rebuild by leaf: ${leaf.hash()}") + // rebuild the tree starting from leaves + while (stack.isNotEmpty()) { + val last = stack.removeLast() + val left: Cell + val right: Cell + if (last.isRightNext) { + left = last.data.refs[0] + right = leaf + } else { + left = leaf + right = last.data.refs[1] + } + val builder = CellBuilder() + builder.storeBitString(last.data.bits) + builder.storeRef(left) + builder.storeRef(right) + leaf = context.finalizeCell(builder) + } + + this.root = leaf + return oldValue + } + + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is RawDictionary) return false + return root == other.root + } + + override fun hashCode(): Int = root.hashCode() + + override fun toString(): String = "RawDictionary(${root?.hash()})" + + private class Segment( + val data: DataCell, + /** + * Which branch to take when traversing the tree, + * `false` - left, `true` - right + */ + val isRightNext: Boolean, + val keyBitLength: Int, + ) + + public companion object { + public fun loadFromSlice( + slice: CellSlice, + keySize: Int, + context: CellContext = CellContext.EMPTY + ): RawDictionary { + val builder = CellBuilder() + builder.storeSlice(slice) + val cell = context.finalizeCell(builder) + return RawDictionary(cell, keySize) + } + } +} + +internal class RawDictEntry( + override val key: BitString, + override val value: CellSlice, +) : Map.Entry + +internal class RawDictIterator( + private var root: Cell?, + private val keyBitCount: Int, + private val cellContext: CellContext +) : Iterator> { + private val path = ArrayDeque() + private var order: Int = 0 + private val key = ByteBackedMutableBitString(keyBitCount) + private var leaf: CellSlice? = null + + init { + if (root != null) { + rewind(false) + } + } + + override fun next(): Map.Entry { + val leaf = leaf ?: throw NoSuchElementException() + val key = ByteBackedMutableBitString(keyBitCount).apply { + key.copyInto(this) + } + nextLeaf(0) + return RawDictEntry(key, leaf) + } + + override fun hasNext(): Boolean = leaf != null + + private fun nextLeaf(goBack: Int): CellSlice? { + if (root == null || leaf == null) { + throw NoSuchElementException() + } + leaf = null + val mode = order xor -goBack + while (path.isNotEmpty()) { + val pe = path.last() + val bit = (mode ushr if (pe.pos > 0) 1 else 0) and 1 + if (pe.v == (bit != 0)) { + pe.rotate() + return divide(mode) + } + path.removeLast() + } + return null + } + + private fun rewind(toEnd: Boolean): CellSlice { + val mode = order xor if (toEnd) -1 else 0 + return divide(mode) + } + + private fun divide(mode: Int): CellSlice { + var mode = mode + var n = keyBitCount + var m = 0 + var node = if (path.isEmpty()) { + root + } else { + val last = path.last() + m = last.pos + 1 + n = n - m + mode = mode ushr 1 + last.next + } ?: throw NoSuchElementException() + while (true) { + val slice = cellContext.loadCell(node).beginParse() + val label = slice.readLabel(n) + label.copyInto(key, m) + m += label.size + n -= label.size + if (n == 0) { + leaf = slice + return slice + } + if (!label.isEmpty()) { + mode = mode ushr 1 + } + val bit = mode and 1 + node = slice.preloadRef(bit) + val alt = slice.preloadRef(1 - bit) + val v = bit != 0 + path.add(Fork(node, alt, m, v)) + key[m++] = v + n-- + mode = mode ushr 1 + } + } + + private inner class Fork( + var next: Cell? = null, + var alt: Cell? = null, + val pos: Int = -1, + var v: Boolean = false + ) { + fun rotate() { + val tmp = next + next = alt + alt = tmp + v = !v + key[pos] = v + } + } +} diff --git a/libs.versions.toml b/libs.versions.toml index 3a94f313..ca0442c0 100644 --- a/libs.versions.toml +++ b/libs.versions.toml @@ -39,3 +39,4 @@ hmac = { module = "io.github.andreypfau:kotlinx-crypto-hmac", version.ref = "cry [plugins] bcv = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "bcv" } +publish = { id = "com.vanniktech.maven.publish", version = "0.28.0" } diff --git a/liteapi-tl/src/LiteApiClient.kt b/liteapi-tl/src/LiteApiClient.kt index baf3b83e..1f3f4cc9 100644 --- a/liteapi-tl/src/LiteApiClient.kt +++ b/liteapi-tl/src/LiteApiClient.kt @@ -1,11 +1,13 @@ package org.ton.lite.api +import kotlinx.coroutines.coroutineScope import kotlinx.io.Buffer import kotlinx.io.readByteString import org.ton.lite.api.exception.LiteServerException import org.ton.lite.api.liteserver.* import org.ton.lite.api.liteserver.functions.* import org.ton.tl.TlCodec +import kotlin.coroutines.cancellation.CancellationException public interface LiteApiClient : LiteApi { public suspend fun sendQuery( @@ -13,7 +15,7 @@ public interface LiteApiClient : LiteApi { answerCodec: TlCodec, query: Q, waitMasterchainSeqno: Int = -1 - ): A { + ): A = coroutineScope { val rawQuery = Buffer().apply { if (waitMasterchainSeqno > 0) { val wait = LiteServerWaitMasterchainSeqno(waitMasterchainSeqno, 30000) @@ -29,10 +31,10 @@ public interface LiteApiClient : LiteApi { null } if (liteServerError != null) { - throw LiteServerException.create(liteServerError.code, liteServerError.message) + throw CancellationException(LiteServerException.create(liteServerError.code, liteServerError.message)) } val answer = answerCodec.decodeBoxed(result) - return answer + answer } public suspend fun sendRawQuery(query: ByteArray): ByteArray diff --git a/liteapi-tl/src/liteserver/functions/LiteServerRunSmcMethod.kt b/liteapi-tl/src/liteserver/functions/LiteServerRunSmcMethod.kt index 5c0518b5..c4e4a2d5 100644 --- a/liteapi-tl/src/liteserver/functions/LiteServerRunSmcMethod.kt +++ b/liteapi-tl/src/liteserver/functions/LiteServerRunSmcMethod.kt @@ -8,7 +8,9 @@ import org.ton.block.VmStack import org.ton.block.VmStackList import org.ton.block.VmStackValue import org.ton.boc.BagOfCells +import org.ton.cell.buildCell import org.ton.crypto.crc16 +import org.ton.kotlin.cell.CellContext import org.ton.lite.api.liteserver.LiteServerAccountId import org.ton.lite.api.liteserver.LiteServerRunMethodResult import org.ton.tl.* @@ -44,7 +46,9 @@ public data class LiteServerRunSmcMethod( @JvmStatic public fun params(vmStack: VmStack): ByteArray = - BagOfCells(VmStack.createCell(vmStack)).toByteArray() + BagOfCells(buildCell(CellContext.EMPTY) { + VmStack.storeTlb(this, vmStack, CellContext.EMPTY) + }).toByteArray() @JvmStatic public fun params(vmStackList: VmStackList?): ByteArray = diff --git a/liteclient/src/CheckProofUtils.kt b/liteclient/src/CheckProofUtils.kt index e90d12a9..068ead99 100644 --- a/liteclient/src/CheckProofUtils.kt +++ b/liteclient/src/CheckProofUtils.kt @@ -59,14 +59,14 @@ internal object CheckProofUtils { val shardAccount = checkNotNull(shardState.accounts.value.x[address.address]?.value) { "Shard account ${address.address} not found in shard state" } - check(shardAccount.account.hash() == root.hash()) { + check(shardAccount.account.cell.virtualize().hash() == root.hash()) { "Account state hash mismatch, expected: ${shardAccount.account.hash()}, actual: ${root.hash()}" } return FullAccountState( shardBlock, address, - TransactionId(shardAccount.lastTransHash, shardAccount.lastTransLt.toLong()), + TransactionId(shardAccount.lastTransHash.toByteArray(), shardAccount.lastTransLt.toLong()), account ) } diff --git a/liteclient/src/LiteClient.kt b/liteclient/src/LiteClient.kt index 709460d0..853ebadb 100644 --- a/liteclient/src/LiteClient.kt +++ b/liteclient/src/LiteClient.kt @@ -318,7 +318,7 @@ public class LiteClient( } catch (e: Exception) { throw RuntimeException("Can't deserialize block data", e) } - val actualRootHash = root.hash().toBitString() + root.hash().toBitString() // FIXME: https://github.com/andreypfau/ton-kotlin/issues/82 // check(blockId.rootHash.toBitString() == actualRootHash) { // "block root hash mismatch, expected: ${blockId.rootHash} , actual: $actualRootHash" @@ -344,7 +344,7 @@ public class LiteClient( throw IllegalStateException("Can't deserialize account state", e) } if (root.isEmpty()) { - return FullAccountState(rawAccountState.shardBlock, accountAddress, null, CellRef(AccountNone, Account)) + return FullAccountState(rawAccountState.shardBlock, accountAddress, null, CellRef(null, Account)) } check(rawAccountState.id == blockId || rawAccountState.id.seqno == 0) { @@ -454,9 +454,11 @@ public class LiteClient( } - public suspend fun sendMessage(body: Message): LiteServerSendMsgStatus = sendMessage(CellRef(body)) + public suspend fun sendMessage(body: Message): LiteServerSendMsgStatus = + sendMessage(CellRef(body, Message.tlbCodec(AnyTlbConstructor))) + public suspend fun sendMessage(body: CellRef>): LiteServerSendMsgStatus = - sendMessage(body.toCell(Message.tlbCodec(AnyTlbConstructor))) + sendMessage(body.cell) public suspend fun sendMessage(cell: Cell): LiteServerSendMsgStatus = sendMessage(BagOfCells(cell)) public suspend fun sendMessage(boc: BagOfCells): LiteServerSendMsgStatus { diff --git a/liteclient/src/intetnal/BlockHeaderResult.kt b/liteclient/src/intetnal/BlockHeaderResult.kt index 8dc931e7..e1687a1d 100644 --- a/liteclient/src/intetnal/BlockHeaderResult.kt +++ b/liteclient/src/intetnal/BlockHeaderResult.kt @@ -17,7 +17,6 @@ internal data class BlockHeaderResult( val stateHash: BitString? ) -@Serializable public data class FullAccountState( @SerialName("block_id") @get:JvmName("blockId") @@ -31,7 +30,7 @@ public data class FullAccountState( public val lastTransactionId: TransactionId?, @get:JvmName("account") - public val account: CellRef + public val account: CellRef ) @Serializable @@ -49,7 +48,6 @@ public data class TransactionId( } } -@Serializable public data class TransactionInfo( @SerialName("block_id") @get:JvmName("blockId") diff --git a/settings.gradle.kts b/settings.gradle.kts index d51c838c..bdab7025 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -66,6 +66,8 @@ submodule("contract") //include(":ton-kotlin-experimental") //include(":ton-kotlin-dht") +include(":examples") + fun submodule(name: String) { include(":ton-kotlin-$name") project(":ton-kotlin-$name").projectDir = file(name) diff --git a/tlb/src/CellRef.kt b/tlb/src/CellRef.kt index f00fc85b..56a33fc4 100644 --- a/tlb/src/CellRef.kt +++ b/tlb/src/CellRef.kt @@ -1,22 +1,27 @@ package org.ton.tlb import org.ton.bitstring.BitString -import org.ton.cell.Cell -import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice -import org.ton.cell.CellType +import org.ton.cell.* +import org.ton.kotlin.cell.CellContext import kotlin.jvm.JvmStatic public inline fun CellRef(cell: Cell, codec: TlbCodec): CellRef = CellRef.valueOf(cell, codec) -public inline fun CellRef(value: T, codec: TlbCodec? = null): CellRef = CellRef.valueOf(value, codec) + +public inline fun CellRef(value: T, codec: TlbCodec): CellRef = CellRef.valueOf(value, codec) public inline fun CellRef(codec: TlbCodec): TlbCodec> = CellRef.tlbCodec(codec) public inline fun Cell.asRef(codec: TlbCodec): CellRef = CellRef.valueOf(this, codec) public interface CellRef : TlbObject { - public val value: T + @Deprecated("use load() instead.", ReplaceWith("load()")) + public val value: T get() = load() + public val cell: Cell + + public fun load(): T = load(CellContext.EMPTY) + public fun load(context: CellContext): T - public fun toCell(codec: TlbCodec<@UnsafeVariance T>? = null): Cell + @Deprecated("use cell instead.", ReplaceWith("cell")) + public fun toCell(codec: TlbCodec<@UnsafeVariance T>? = null): Cell = cell public fun hash(): BitString = hash(null) public fun hash(codec: TlbCodec<@UnsafeVariance T>?): BitString = toCell().hash() @@ -38,11 +43,15 @@ public interface CellRef : TlbObject { @JvmStatic public fun valueOf(cell: Cell, codec: TlbCodec): CellRef = CellRefImpl(cell, codec) + @Suppress("DEPRECATION") @JvmStatic + @Deprecated("Scheduled to be removed") public fun valueOf(value: T): CellRef = CellRefValue(value, null) @JvmStatic - public fun valueOf(value: T, codec: TlbCodec?): CellRef = CellRefValue(value, codec) + public fun valueOf(value: T, codec: TlbCodec): CellRef = CellRefImpl(buildCell { + codec.storeTlb(this, value, CellContext.EMPTY) + }, codec) @JvmStatic public fun tlbCodec(codec: TlbCodec): TlbCodec> = CellRefTlbConstructor(codec) @@ -50,16 +59,11 @@ public interface CellRef : TlbObject { } private class CellRefImpl( - val cell: Cell, + override val cell: Cell, val codec: TlbCodec ) : CellRef { - override val value: T by lazy(LazyThreadSafetyMode.PUBLICATION) { - check(cell.type != CellType.PRUNED_BRANCH) { "Can't load reference value: $cell" } - codec.loadTlb(cell) - } - - override fun toCell(codec: TlbCodec?): Cell { - return cell + override fun load(context: CellContext): T { + return codec.loadTlb(context.loadCell(cell).beginParse(), context) } override fun print(printer: TlbPrettyPrinter): TlbPrettyPrinter { @@ -75,16 +79,22 @@ private class CellRefImpl( override fun toString(): String = "CellRef($cell)" } +@Deprecated("Deprecated") private class CellRefValue( override val value: T, val codec: TlbCodec? = null ) : CellRef { - override fun toCell(codec: TlbCodec?): Cell { - val currentCodec = codec ?: this.codec - require(currentCodec != null) { "Codec is not specified" } - return CellBuilder.createCell { - currentCodec.storeTlb(this, value) + override val cell: Cell + get() { + val currentCodec = codec ?: this.codec + require(currentCodec != null) { "Codec is not specified" } + return CellBuilder.createCell { + currentCodec.storeTlb(this, value, CellContext.EMPTY) + } } + + override fun load(context: CellContext): T { + return value } override fun toString(): String = "CellRef($value)" @@ -103,7 +113,7 @@ private class CellRefTlbConstructor( } public inline fun CellBuilder.storeRef(codec: TlbCodec, value: CellRef) { - storeRef(value.toCell(codec)) + storeRef(value.cell) } public inline fun CellSlice.loadRef(codec: TlbCodec): CellRef { diff --git a/tlb/src/TlbCodec.kt b/tlb/src/TlbCodec.kt index 5f687d11..e4ada182 100644 --- a/tlb/src/TlbCodec.kt +++ b/tlb/src/TlbCodec.kt @@ -5,19 +5,22 @@ package org.ton.tlb import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice +import org.ton.kotlin.cell.CellContext public interface TlbStorer { - public fun storeTlb(cellBuilder: CellBuilder, value: T) + public fun storeTlb(builder: CellBuilder, value: T): Unit = storeTlb(builder, value, CellContext.EMPTY) + public fun storeTlb(builder: CellBuilder, value: T, context: CellContext): Unit = storeTlb(builder, value) public fun createCell(value: T): Cell = CellBuilder.createCell { - storeTlb(this, value) + storeTlb(this, value, CellContext.EMPTY) } } +@Deprecated("Scheduled to remove") public interface TlbNegatedStorer : TlbStorer { - public fun storeNegatedTlb(cellBuilder: CellBuilder, value: T): Int + public fun storeNegatedTlb(builder: CellBuilder, value: T): Int - override fun storeTlb(cellBuilder: CellBuilder, value: T) { - storeNegatedTlb(cellBuilder, value) + override fun storeTlb(builder: CellBuilder, value: T, context: CellContext) { + storeNegatedTlb(builder, value) } } @@ -27,17 +30,20 @@ public interface TlbLoader { return loadTlb(cellSlice) } - public fun loadTlb(cellSlice: CellSlice): T + public fun loadTlb(slice: CellSlice): T = loadTlb(slice, CellContext.EMPTY) + + public fun loadTlb(slice: CellSlice, context: CellContext): T = loadTlb(slice) } +@Deprecated("Scheduled to remove") public interface TlbNegatedLoader : TlbLoader { public fun loadNegatedTlb(cell: Cell): TlbNegatedResult = cell.parse { loadNegatedTlb(this) } - public fun loadNegatedTlb(cellSlice: CellSlice): TlbNegatedResult + public fun loadNegatedTlb(slice: CellSlice): TlbNegatedResult - override fun loadTlb(cellSlice: CellSlice): T = loadNegatedTlb(cellSlice).value + override fun loadTlb(slice: CellSlice): T = loadNegatedTlb(slice).value } public data class TlbNegatedResult( @@ -46,8 +52,34 @@ public data class TlbNegatedResult( ) public interface TlbCodec : TlbStorer, TlbLoader + +@Suppress("DEPRECATION") +@Deprecated("Scheduled to remove") public interface TlbNegatedCodec : TlbCodec, TlbNegatedStorer, TlbNegatedLoader +public fun TlbCodec.asNullable(): TlbCodec = NullableTlbCodec(this) + +public class NullableTlbCodec( + private val codec: TlbCodec +) : TlbCodec { + override fun storeTlb(builder: CellBuilder, value: T?, context: CellContext) { + if (value == null) { + builder.storeBoolean(false) + } else { + builder.storeBoolean(true) + codec.storeTlb(builder, value, context) + } + } + + override fun loadTlb(slice: CellSlice, context: CellContext): T? { + return if (slice.loadBoolean()) { + codec.loadTlb(slice, context) + } else { + null + } + } +} + public inline fun CellSlice.loadTlb(codec: TlbLoader): T { return codec.loadTlb(this) } @@ -56,8 +88,12 @@ public inline fun CellSlice.loadNegatedTlb(codec: TlbNegatedLoader): TlbN return codec.loadNegatedTlb(this) } -public inline fun CellBuilder.storeTlb(codec: TlbStorer, value: T): CellBuilder = apply { - codec.storeTlb(this, value) +public inline fun CellBuilder.storeTlb( + codec: TlbStorer, + value: T, + context: CellContext = CellContext.EMPTY +): CellBuilder = apply { + codec.storeTlb(this, value, context) } public inline fun CellBuilder.storeNegatedTlb(codec: TlbNegatedStorer, value: T): Int = diff --git a/tlb/src/TlbCombinator.kt b/tlb/src/TlbCombinator.kt index 3473be95..2084321a 100644 --- a/tlb/src/TlbCombinator.kt +++ b/tlb/src/TlbCombinator.kt @@ -3,6 +3,7 @@ package org.ton.tlb import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice +import org.ton.kotlin.cell.CellContext import org.ton.tlb.exception.UnknownTlbConstructorException import org.ton.tlb.providers.TlbCombinatorProvider import org.ton.tlb.providers.TlbConstructorProvider @@ -44,24 +45,24 @@ public abstract class TlbCombinator( override fun tlbCombinator(): TlbCombinator = this - override fun loadTlb(cellSlice: CellSlice): T { - val constructor = findTlbLoaderOrNull(cellSlice) ?: throw UnknownTlbConstructorException( - cellSlice.preloadBits(32) + override fun loadTlb(slice: CellSlice, context: CellContext): T { + val constructor = findTlbLoaderOrNull(slice) ?: throw UnknownTlbConstructorException( + slice.preloadBitString(32) ) if (constructor is TlbConstructor<*>) { - cellSlice.skipBits(constructor.id.size) + slice.skipBits(constructor.id.size) } - return constructor.loadTlb(cellSlice) + return constructor.loadTlb(slice, context) } - override fun storeTlb(cellBuilder: CellBuilder, value: T) { + override fun storeTlb(builder: CellBuilder, value: T, context: CellContext) { val storer = findTlbStorerOrNull(value) ?: throw UnknownTlbConstructorException() if (storer is TlbConstructorProvider<*>) { - cellBuilder.storeBits(storer.tlbConstructor().id) + builder.storeBitString(storer.tlbConstructor().id) } else if (storer is TlbConstructor<*>) { - cellBuilder.storeBits(storer.id) + builder.storeBitString(storer.id) } - return storer.storeTlb(cellBuilder, value) + return storer.storeTlb(builder, value, context) } protected open fun findTlbLoaderOrNull(cellSlice: CellSlice): TlbLoader? { diff --git a/tlb/src/TlbConstructor.kt b/tlb/src/TlbConstructor.kt index 43af2581..e6522aa4 100644 --- a/tlb/src/TlbConstructor.kt +++ b/tlb/src/TlbConstructor.kt @@ -3,6 +3,7 @@ package org.ton.tlb import org.ton.bitstring.BitString import org.ton.cell.CellBuilder import org.ton.cell.CellSlice +import org.ton.kotlin.cell.CellContext import org.ton.tlb.exception.ParseTlbException import org.ton.tlb.providers.TlbConstructorProvider import kotlin.jvm.JvmStatic @@ -72,11 +73,20 @@ public abstract class TlbNegatedConstructor( schema: String, id: BitString? = null ) : TlbConstructor(schema, id), TlbNegatedCodec { - override fun storeTlb(cellBuilder: CellBuilder, value: T) { + + override fun storeTlb(builder: CellBuilder, value: T) { + storeNegatedTlb(builder, value) + } + + override fun storeTlb(cellBuilder: CellBuilder, value: T, context: CellContext) { storeNegatedTlb(cellBuilder, value) } - override fun loadTlb(cellSlice: CellSlice): T = loadNegatedTlb(cellSlice).value + override fun loadTlb(slice: CellSlice, context: CellContext): T = loadNegatedTlb(slice).value + + override fun loadTlb(slice: CellSlice): T { + return loadNegatedTlb(slice).value + } } public inline fun TlbConstructor.asTlbCombinator(): TlbCombinator = asTlbCombinator(T::class) diff --git a/tlb/src/TlbNegatedCombinator.kt b/tlb/src/TlbNegatedCombinator.kt index bcaf0520..793ebdb7 100644 --- a/tlb/src/TlbNegatedCombinator.kt +++ b/tlb/src/TlbNegatedCombinator.kt @@ -2,6 +2,7 @@ package org.ton.tlb import org.ton.cell.CellBuilder import org.ton.cell.CellSlice +import org.ton.kotlin.cell.CellContext import org.ton.tlb.exception.UnknownTlbConstructorException import kotlin.reflect.KClass @@ -12,11 +13,11 @@ public abstract class TlbNegatedCombinator( baseClass, *subClasses ), TlbNegatedCodec { - override fun storeTlb(cellBuilder: CellBuilder, value: T) { + override fun storeTlb(cellBuilder: CellBuilder, value: T, context: CellContext) { storeNegatedTlb(cellBuilder, value) } - override fun loadTlb(cellSlice: CellSlice): T = loadNegatedTlb(cellSlice).value + override fun loadTlb(cellSlice: CellSlice, context: CellContext): T = loadNegatedTlb(cellSlice).value override fun storeNegatedTlb(cellBuilder: CellBuilder, value: T): Int { val constructor = findTlbStorerOrNull(value) as? TlbNegatedConstructor diff --git a/tlb/src/constructor/AnyTlbConstructor.kt b/tlb/src/constructor/AnyTlbConstructor.kt index 65f477b3..7c899bf2 100644 --- a/tlb/src/constructor/AnyTlbConstructor.kt +++ b/tlb/src/constructor/AnyTlbConstructor.kt @@ -4,6 +4,7 @@ import org.ton.cell.Cell import org.ton.cell.CellBuilder import org.ton.cell.CellSlice import org.ton.cell.buildCell +import org.ton.kotlin.cell.CellContext import org.ton.tlb.TlbCodec public object AnyTlbConstructor : TlbCodec { @@ -19,3 +20,17 @@ public object AnyTlbConstructor : TlbCodec { } } } + +public object RemainingTlbCodec : TlbCodec { + override fun storeTlb(builder: CellBuilder, value: CellSlice, context: CellContext) { + builder.storeBitString(value.bits) + builder.storeRefs(value.refs) + } + + override fun loadTlb(cellSlice: CellSlice): CellSlice { + return buildCell { + storeBitString(cellSlice.loadBits(cellSlice.bits.size - cellSlice.bitsPosition)) + storeRefs(cellSlice.loadRefs(cellSlice.refs.size - cellSlice.refsPosition)) + }.beginParse() + } +} \ No newline at end of file diff --git a/tlb/src/providers/TlbCombinatorProvider.kt b/tlb/src/providers/TlbCombinatorProvider.kt index 11273c40..849ea351 100644 --- a/tlb/src/providers/TlbCombinatorProvider.kt +++ b/tlb/src/providers/TlbCombinatorProvider.kt @@ -2,14 +2,16 @@ package org.ton.tlb.providers import org.ton.cell.CellBuilder import org.ton.cell.CellSlice +import org.ton.kotlin.cell.CellContext import org.ton.tlb.TlbCodec import org.ton.tlb.TlbCombinator public interface TlbCombinatorProvider : TlbProvider, TlbCodec { public fun tlbCombinator(): TlbCombinator - override fun loadTlb(cellSlice: CellSlice): T = tlbCombinator().loadTlb(cellSlice) - override fun storeTlb(cellBuilder: CellBuilder, value: T) { - tlbCombinator().storeTlb(cellBuilder, value) - } + override fun loadTlb(slice: CellSlice, context: CellContext): T = + tlbCombinator().loadTlb(slice, context) + + override fun storeTlb(builder: CellBuilder, value: T, context: CellContext): Unit = + tlbCombinator().storeTlb(builder, value, context) } diff --git a/tlb/src/providers/TlbConstructorProvider.kt b/tlb/src/providers/TlbConstructorProvider.kt index e0b0c6e9..17f60a4e 100644 --- a/tlb/src/providers/TlbConstructorProvider.kt +++ b/tlb/src/providers/TlbConstructorProvider.kt @@ -1,15 +1,18 @@ package org.ton.tlb.providers import org.ton.cell.CellBuilder -import org.ton.cell.CellSlice +import org.ton.kotlin.cell.CellContext import org.ton.tlb.TlbCodec import org.ton.tlb.TlbConstructor -public interface TlbConstructorProvider : TlbProvider, TlbCodec { +public interface TlbConstructorProvider : TlbCodec { public fun tlbConstructor(): TlbConstructor - override fun loadTlb(cellSlice: CellSlice): T = tlbConstructor().loadTlb(cellSlice) - override fun storeTlb(cellBuilder: CellBuilder, value: T) { - tlbConstructor().storeTlb(cellBuilder, value) + override fun storeTlb(builder: CellBuilder, value: T, context: CellContext) { + tlbConstructor().storeTlb(builder, value) + } + + override fun storeTlb(builder: CellBuilder, value: T) { + tlbConstructor().storeTlb(builder, value, CellContext.EMPTY) } } diff --git a/tonapi-tl/src/pk/ed25519.kt b/tonapi-tl/src/pk/ed25519.kt index d4a08e8f..ad778217 100644 --- a/tonapi-tl/src/pk/ed25519.kt +++ b/tonapi-tl/src/pk/ed25519.kt @@ -1,6 +1,7 @@ package org.ton.api.pk import kotlinx.io.bytestring.ByteString +import kotlinx.io.bytestring.toHexString import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.ton.api.pub.PublicKeyEd25519 @@ -24,7 +25,7 @@ public data class PrivateKeyEd25519( @Serializable(ByteStringBase64Serializer::class) public val key: ByteString ) : PrivateKey, Decryptor { - public constructor(key: ByteArray) : this(ByteString(key)) + public constructor(key: ByteArray) : this(ByteString(*key.copyOf(32))) init { require(key.size == 32) { "key must be 32 byte long" } @@ -42,6 +43,8 @@ public data class PrivateKeyEd25519( public fun sharedKey(publicKey: PublicKeyEd25519): ByteArray = Ed25519.sharedKey(key.toByteArray(), publicKey.key.toByteArray()) + override fun toString(): String = "PrivateKeyEd25519(${key.toHexString()})" + public companion object : TlConstructor( schema = "pk.ed25519 key:int256 = PrivateKey" ) { diff --git a/tonapi-tl/src/pub/ed25519.kt b/tonapi-tl/src/pub/ed25519.kt index 400c0ca4..a5dc55f3 100644 --- a/tonapi-tl/src/pub/ed25519.kt +++ b/tonapi-tl/src/pub/ed25519.kt @@ -3,6 +3,7 @@ package org.ton.api.pub import kotlinx.io.bytestring.ByteString +import kotlinx.io.bytestring.toHexString import kotlinx.serialization.Polymorphic import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -29,7 +30,7 @@ public data class PublicKeyEd25519( public constructor(byteArray: ByteArray) : this(ByteString(byteArray)) private val _adnlIdShort: AdnlIdShort by lazy(LazyThreadSafetyMode.PUBLICATION) { - AdnlIdShort(ByteString(*PublicKeyEd25519.hash(this))) + AdnlIdShort(ByteString(*hash(this))) } private val _encryptor by lazy(LazyThreadSafetyMode.PUBLICATION) { EncryptorEd25519(key.toByteArray()) @@ -37,6 +38,8 @@ public data class PublicKeyEd25519( override fun toAdnlIdShort(): AdnlIdShort = _adnlIdShort + override fun toString(): String = "PublicKeyEd25519(${key.toHexString()})" + public companion object : TlConstructor( schema = "pub.ed25519 key:int256 = PublicKey", ) { diff --git a/tvm/build.gradle.kts b/tvm/build.gradle.kts index c714df43..5a7f43bd 100644 --- a/tvm/build.gradle.kts +++ b/tvm/build.gradle.kts @@ -11,6 +11,7 @@ kotlin { api(projects.tonKotlinBigint) api(projects.tonKotlinCrypto) implementation(libs.serialization.json) + api(libs.kotlinx.io) } } } diff --git a/tvm/src/boc/BagOfCells.kt b/tvm/src/boc/BagOfCells.kt index 91e62124..d76f76df 100644 --- a/tvm/src/boc/BagOfCells.kt +++ b/tvm/src/boc/BagOfCells.kt @@ -2,6 +2,7 @@ package org.ton.boc import io.ktor.utils.io.core.* import org.ton.cell.Cell +import kotlin.io.encoding.Base64 import kotlin.jvm.JvmStatic public fun BagOfCells(byteArray: ByteArray): BagOfCells = BagOfCells.of(byteArray) @@ -58,3 +59,5 @@ public interface BagOfCells : Iterable { } } } + +public fun String.base64ToCell(): Cell = BagOfCells(Base64.decode(this)).first() \ No newline at end of file diff --git a/tvm/src/boc/BagOfCellsUtils.kt b/tvm/src/boc/BagOfCellsUtils.kt index 11b667b6..c9d7dcd4 100644 --- a/tvm/src/boc/BagOfCellsUtils.kt +++ b/tvm/src/boc/BagOfCellsUtils.kt @@ -6,7 +6,6 @@ import org.ton.bitstring.BitString import org.ton.cell.Cell import org.ton.cell.CellDescriptor import org.ton.cell.buildCell -import kotlin.experimental.and internal fun Input.readBagOfCell(): BagOfCells { val prefix = readInt() @@ -50,8 +49,8 @@ internal fun Input.readBagOfCell(): BagOfCells { val offsetSize = readByte().toInt() val cellCount = readInt(refSize) val rootsCount = readInt(refSize) - val absentCount = readInt(refSize) - val totalCellsSize = readInt(offsetSize) + readInt(refSize) + readInt(offsetSize) // Roots val rootIndexes = IntArray(rootsCount) { @@ -164,7 +163,7 @@ private suspend fun createCell( cells[refIndex].await() } val descriptor = descriptors[index] - val hashes = cellHashes[index] + cellHashes[index] // val cell = if (!descriptors[index].isExotic && hashes != null) { // val new = buildCell { // isExotic = descriptor.isExotic @@ -255,26 +254,25 @@ private fun serializeBagOfCells( } val serializedCells = cells.mapIndexed { index: Int, cell: Cell -> - buildPacket { - val (d1, d2) = cell.descriptor - writeByte(d1) - writeByte(d2) - val cellData = cell.bits.toByteArray( - augment = (d2 and 1) != 0.toByte() - ) + val serializedCell = buildPacket { + val descriptor = cell.descriptor + writeByte(descriptor.d1) + writeByte(descriptor.d2) + val cellData = cell.bits.toByteArray(true) writeFully(cellData) cell.refs.forEach { reference -> val refIndex = cells.indexOf(reference) writeInt(refIndex, sizeBytes) } - } + }.readBytes() + serializedCell } var fullSize = 0 val sizeIndex = ArrayList() serializedCells.forEach { serializedCell -> sizeIndex.add(fullSize) - fullSize += serializedCell.remaining.toInt() + fullSize += serializedCell.size } var offsetBytes = 0 while (fullSize >= (1L shl (offsetBytes shl 3))) { @@ -312,8 +310,7 @@ private fun serializeBagOfCells( } } serializedCells.forEach { serializedCell -> - val bytes = serializedCell.readBytes() - writeFully(bytes) + writeFully(serializedCell) } }.readBytes() diff --git a/tvm/src/cell/Cell.kt b/tvm/src/cell/Cell.kt index 3e27037b..c47e81b8 100644 --- a/tvm/src/cell/Cell.kt +++ b/tvm/src/cell/Cell.kt @@ -83,6 +83,8 @@ public interface Cell { appendable.append(' ') } appendable.append(cell.bits.toString()) + appendable.append(", hash:") + appendable.append(cell.hash().toHexString()) cell.refs.forEach { reference -> appendable.append('\n') toString(reference, appendable, "$indent ") diff --git a/tvm/src/cell/CellBuilder.kt b/tvm/src/cell/CellBuilder.kt index d2ef27af..84a75e8b 100644 --- a/tvm/src/cell/CellBuilder.kt +++ b/tvm/src/cell/CellBuilder.kt @@ -1,12 +1,14 @@ package org.ton.cell import io.github.andreypfau.kotlinx.crypto.sha2.SHA256 +import kotlinx.io.bytestring.ByteString import org.ton.bigint.* import org.ton.bitstring.BitString import org.ton.bitstring.ByteBackedMutableBitString import org.ton.bitstring.MutableBitString import org.ton.bitstring.toBitString import org.ton.cell.exception.CellOverflowException +import org.ton.kotlin.cell.CellContext import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -30,12 +32,25 @@ public interface CellBuilder { public fun endCell(): Cell = build() public fun build(): Cell - public fun storeBit(bit: Boolean): CellBuilder + @Deprecated( + message = "Use storeBoolean()", + level = DeprecationLevel.WARNING, + replaceWith = ReplaceWith("storeBoolean(bit)") + ) + public fun storeBit(bit: Boolean): CellBuilder = storeBoolean(bit) + + public fun storeBoolean(value: Boolean): CellBuilder + public fun storeBits(vararg bits: Boolean): CellBuilder public fun storeBits(bits: Iterable): CellBuilder public fun storeBits(bits: Collection): CellBuilder - public fun storeBits(bits: BitString): CellBuilder + @Deprecated("use storeBitString(bits) instead.", ReplaceWith("storeBitString(bits)")) + public fun storeBits(bits: BitString): CellBuilder = storeBitString(bits) + + public fun storeBitString(value: BitString, startIndex: Int = 0, endIndex: Int = value.size): CellBuilder + + public fun storeByteString(value: ByteString): CellBuilder public fun storeBytes(byteArray: ByteArray): CellBuilder public fun storeByte(byte: Byte): CellBuilder @@ -43,6 +58,7 @@ public interface CellBuilder { * Stores a reference to cell into builder. */ public fun storeRef(ref: Cell): CellBuilder + public fun storeNullableRef(ref: Cell?): CellBuilder public fun storeRefs(vararg refs: Cell): CellBuilder public fun storeRefs(refs: Iterable): CellBuilder @@ -57,10 +73,14 @@ public interface CellBuilder { public fun storeUInt(value: Int, length: Int): CellBuilder = storeUInt(value.toBigInt(), length) public fun storeUInt(value: Long, length: Int): CellBuilder = storeUInt(value.toBigInt(), length) + public fun storeULong(value: ULong, bitCount: Int = ULong.SIZE_BITS): CellBuilder = storeLong(value.toLong(), 64) + public fun storeUInt8(value: UByte): CellBuilder = storeInt(value.toByte(), 8) public fun storeUInt16(value: UShort): CellBuilder = storeInt(value.toShort(), 16) public fun storeUInt32(value: UInt): CellBuilder = storeInt(value.toInt(), 32) - public fun storeUInt64(value: ULong): CellBuilder = storeInt(value.toLong(), 64) + + @Deprecated("Use storeULong(value) instead.", ReplaceWith("storeULong(value)")) + public fun storeUInt64(value: ULong): CellBuilder = storeULong(value) public fun storeUIntLeq(value: BigInt, max: BigInt): CellBuilder = storeUInt(value, max.bitLength) public fun storeUIntLeq(value: Byte, max: Byte): CellBuilder = storeUIntLeq(value.toInt(), max.toInt()) @@ -81,13 +101,27 @@ public interface CellBuilder { public fun storeInt(value: Byte, length: Int): CellBuilder = storeInt(value.toInt(), length) public fun storeInt(value: Short, length: Int): CellBuilder = storeInt(value.toInt(), length) public fun storeInt(value: Int, length: Int): CellBuilder = storeInt(value.toBigInt(), length) - public fun storeInt(value: Long, length: Int): CellBuilder = storeInt(value.toBigInt(), length) + + @Deprecated("Use storeLong(length) instead", ReplaceWith("storeLong(value, length)")) + public fun storeInt(value: Long, length: Int): CellBuilder = storeLong(value, length) + + public fun storeLong(value: Long, bitCount: Int = Long.SIZE_BITS): CellBuilder { + if (bitCount <= 0) return this + if (value == 0L) { + storeBits(*BooleanArray(bitCount)) + return this + } + storeInt(value.toBigInt(), bitCount) + return this + } /** * Stores [slice] into builder. */ public fun storeSlice(slice: CellSlice): CellBuilder + public fun reset(): CellBuilder + public companion object { @JvmStatic public fun of(cell: Cell): CellBuilder = @@ -128,6 +162,7 @@ public interface CellBuilder { } public fun storeBytes(byteArray: ByteArray, length: Int): CellBuilder + } public inline operator fun CellBuilder.invoke(builder: CellBuilder.() -> Unit) { @@ -135,23 +170,29 @@ public inline operator fun CellBuilder.invoke(builder: CellBuilder.() -> Unit) { } @OptIn(ExperimentalContracts::class) -public inline fun buildCell(builderAction: CellBuilder.() -> Unit): Cell { +public inline fun buildCell(context: CellContext = CellContext.EMPTY, builderAction: CellBuilder.() -> Unit): Cell { contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return CellBuilder.beginCell().apply(builderAction).endCell() + return context.finalizeCell(CellBuilder.beginCell().apply(builderAction)) } -public inline fun CellBuilder.storeRef(refBuilder: CellBuilder.() -> Unit): CellBuilder = apply { - val cellBuilder = CellBuilder.beginCell() - cellBuilder.apply(refBuilder) - val cell = cellBuilder.endCell() +@OptIn(ExperimentalContracts::class) +public inline fun CellBuilder.storeRef( + context: CellContext = CellContext.EMPTY, + block: CellBuilder.() -> Unit +): CellBuilder { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + val cell = context.finalizeCell(CellBuilder.beginCell().apply(block)) storeRef(cell) + return this } public inline fun CellBuilder(cell: Cell): CellBuilder = CellBuilder.of(cell) public inline fun CellBuilder(): CellBuilder = CellBuilder.beginCell() private class CellBuilderImpl( - override var bits: MutableBitString = ByteBackedMutableBitString(ByteArray(128), 0), + override var bits: MutableBitString = ByteBackedMutableBitString(0), override var refs: MutableList = ArrayList(), override var levelMask: LevelMask? = null, override var isExotic: Boolean = false @@ -159,7 +200,7 @@ private class CellBuilderImpl( override val bitsPosition: Int get() = bits.size override val remainingBits: Int get() = Cell.MAX_BITS_SIZE - bitsPosition - override fun storeBit(bit: Boolean): CellBuilder = apply { + override fun storeBoolean(bit: Boolean): CellBuilder = apply { checkBitsOverflow(1) bits.plus(bit) } @@ -174,13 +215,25 @@ private class CellBuilderImpl( this.bits.plus(bits) } - override fun storeBits(bits: BitString): CellBuilder = apply { - checkBitsOverflow(bits.size) - this.bits.plus(bits) + override fun storeBitString(value: BitString, startIndex: Int, endIndex: Int): CellBuilder { + if (startIndex == endIndex) return this + if (startIndex == 0 && endIndex == value.size) { + checkBitsOverflow(value.size) + this.bits.plus(value) + } else { + this.bits.plus(value.slice(startIndex, endIndex)) + } + return this } override fun storeBits(bits: Iterable): CellBuilder = storeBits(bits.toList()) + override fun storeByteString(value: ByteString): CellBuilder { + checkBitsOverflow(value.size * Byte.SIZE_BITS) + this.bits.plus(value.toByteArray()) + return this + } + override fun storeBytes(byteArray: ByteArray): CellBuilder = apply { checkBitsOverflow(byteArray.size * Byte.SIZE_BITS) this.bits.plus(byteArray) @@ -201,6 +254,17 @@ private class CellBuilderImpl( refs.add(ref) } + override fun storeNullableRef(ref: Cell?): CellBuilder { + if (ref != null) { + checkRefsOverflow(1) + storeBoolean(true) + refs.add(ref) + } else { + storeBoolean(false) + } + return this + } + override fun storeRefs(vararg refs: Cell): CellBuilder = apply { checkRefsOverflow(refs.size) this.refs.addAll(refs) @@ -233,17 +297,23 @@ private class CellBuilderImpl( } override fun storeSlice(slice: CellSlice): CellBuilder = apply { - val (bits, refs) = slice + checkBitsOverflow(slice.remainingBits) + checkRefsOverflow(slice.remainingRefs) - checkBitsOverflow(bits.size) - checkRefsOverflow(refs.size) - - storeBits(bits) - refs.forEach { ref -> - storeRef(ref) + storeBitString(slice.preloadBitString(slice.remainingBits)) + repeat(slice.remainingRefs) { index -> + storeRef(slice.preloadRef(index)) } } + override fun reset(): CellBuilder { + bits = ByteBackedMutableBitString(ByteArray(128), 0) + refs.clear() + levelMask = null + isExotic = false + return this + } + override fun build(): Cell { var childrenMask = LevelMask() refs.forEach { child -> @@ -265,6 +335,7 @@ private class CellBuilderImpl( hash.toBitString(), depth, descriptor, bits ) } + else -> if (descriptor == EmptyCell.descriptor) { EmptyCell } else { @@ -407,3 +478,13 @@ private class CellBuilderImpl( const val DEPTH_BITS = 16 } } + +public fun CellBuilder.storeUInt(value: UInt, bits: Int = UInt.SIZE_BITS): CellBuilder { + if (bits <= 0) return this + if (value == 0u) { + storeBits(*BooleanArray(bits)) + return this + } + storeUInt(value.toLong().toBigInt(), bits) + return this +} \ No newline at end of file diff --git a/tvm/src/cell/CellContext.kt b/tvm/src/cell/CellContext.kt new file mode 100644 index 00000000..17aedd6a --- /dev/null +++ b/tvm/src/cell/CellContext.kt @@ -0,0 +1,28 @@ +@file:Suppress("PackageDirectoryMismatch") + +package org.ton.kotlin.cell + +import org.ton.cell.Cell +import org.ton.cell.CellBuilder +import org.ton.cell.DataCell +import org.ton.cell.VirtualCell + +public interface CellContext { + public fun loadCell(cell: Cell): DataCell + + public fun finalizeCell(builder: CellBuilder): Cell + + public companion object { + public val EMPTY: CellContext = object : CellContext { + override fun loadCell(cell: Cell): DataCell { + if (cell is DataCell) return cell + if (cell is VirtualCell && cell.cell is DataCell) return cell.cell + else throw IllegalArgumentException("Can't load ${cell::class} $cell") + } + + override fun finalizeCell(builder: CellBuilder): Cell { + return builder.build() + } + } + } +} \ No newline at end of file diff --git a/tvm/src/cell/CellSize.kt b/tvm/src/cell/CellSize.kt new file mode 100644 index 00000000..c61d140e --- /dev/null +++ b/tvm/src/cell/CellSize.kt @@ -0,0 +1,57 @@ +@file:Suppress("PackageDirectoryMismatch") + +package org.ton.kotlin.cell + +import org.ton.cell.Cell + +public class CellSize( + public val minBits: Int, + public val minRefs: Int, + public val maxBits: Int, + public val maxRefs: Int +) { + public constructor(bits: Int, refs: Int) : this(bits, refs, bits, refs) + + public fun isFixed(): Boolean = minBits == maxBits && minRefs == maxRefs + + public fun fitsIntoCell(): Boolean { + return minBits in 0..Cell.MAX_BITS_SIZE && maxBits in 0..Cell.MAX_BITS_SIZE && minRefs in 0..4 && maxRefs in 0..4 + } + + public operator fun plus(other: CellSize): CellSize = + CellSize( + minBits = minBits + other.minBits, + minRefs = minRefs + other.minRefs, + maxBits = maxBits + other.maxBits, + maxRefs = maxRefs + other.maxRefs + ) + + override fun toString(): String = buildString { + fun appendSize(bits: Int, refs: Int) { + append(bits) + if (refs > 0) { + append("+") + append(refs) + append("R") + } + } + if (isFixed()) { + append("=") + appendSize(minBits, minRefs) + } else { + appendSize(minBits, minRefs) + append("..") + appendSize(maxBits, maxRefs) + } + } + + public companion object { + public val ZERO: CellSize = CellSize(0, 0, 0, 0) + } +} + +public interface CellSizeable { + public val cellSize: CellSize +} + +public val CellSizeable?.cellSize: CellSize get() = this?.cellSize ?: CellSize.ZERO \ No newline at end of file diff --git a/tvm/src/cell/CellSlice.kt b/tvm/src/cell/CellSlice.kt index d2934c20..555e5b1f 100644 --- a/tvm/src/cell/CellSlice.kt +++ b/tvm/src/cell/CellSlice.kt @@ -2,11 +2,16 @@ package org.ton.cell +import kotlinx.io.bytestring.ByteString import org.ton.bigint.* import org.ton.bitstring.BitString import org.ton.bitstring.ByteBackedBitString +import org.ton.bitstring.ByteBackedMutableBitString import org.ton.bitstring.exception.BitStringUnderflowException import org.ton.cell.exception.CellUnderflowException +import org.ton.kotlin.cell.CellContext +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import kotlin.jvm.JvmStatic public inline fun CellSlice(bits: BitString, refs: List = emptyList()): CellSlice = CellSlice.of(bits, refs) @@ -17,6 +22,7 @@ public interface CellSlice { public var bitsPosition: Int public var refsPosition: Int public val remainingBits: Int get() = bits.size - bitsPosition + public val remainingRefs: Int get() = refs.size - refsPosition /** * Checks if slice is empty. If not, throws an exception. @@ -29,28 +35,73 @@ public interface CellSlice { public fun loadRef(): Cell public fun loadRefs(count: Int): List + public fun loadNullableRef(): Cell? + public fun preloadRef(): Cell public fun preloadRefs(count: Int): List public fun preloadRef(cellSlice: CellSlice.() -> T): T + public fun preloadRef(offset: Int): Cell + + @Deprecated("use loadBoolean() instead", ReplaceWith("loadBoolean()")) + public fun loadBit(): Boolean = loadBoolean() - public fun loadBit(): Boolean - public fun preloadBit(): Boolean + @Deprecated("use preloadBoolean() instead", ReplaceWith("preloadBoolean()")) + public fun preloadBit(): Boolean = preloadBoolean() + + public fun loadBoolean(): Boolean + public fun preloadBoolean(): Boolean public fun skipBits(length: Int): CellSlice - public fun loadBits(length: Int): BitString - public fun preloadBits(length: Int): BitString + @Deprecated("use loadBitString(length) instead", ReplaceWith("loadBitString(length)")) + public fun loadBits(length: Int): BitString = loadBitString(length) + + @Deprecated("use preloadBits(length) instead", ReplaceWith("preloadBitString(length)")) + public fun preloadBits(length: Int): BitString = preloadBitString(length) + + public fun loadBitString(bitCount: Int): BitString + public fun preloadBitString(bitCount: Int): BitString + + public fun loadByteString(byteCount: Int): ByteString = ByteString(*loadByteArray(byteCount)) + public fun preloadByteString(byteCount: Int): ByteString = ByteString(*preloadByteArray(byteCount)) + + public fun loadByteArray(byteCount: Int): ByteArray + public fun preloadByteArray(byteCount: Int): ByteArray public fun loadInt(length: Int): BigInt - public fun preloadInt(length: Int): BigInt + public fun preloadInt(length: Int): BigInt { + val uint = preloadUInt(length) + val int = 1.toBigInt() shl (length - 1) + return if (uint >= int) uint - (int * 2.toBigInt()) else uint + } + + public fun loadLong(bitCount: Int = Long.SIZE_BITS): Long = loadInt(bitCount).toLong() + public fun preloadLong(bitCount: Int = Long.SIZE_BITS): Long = preloadInt(bitCount).toLong() public fun loadUInt(length: Int): BigInt - public fun preloadUInt(length: Int): BigInt + public fun preloadUInt(length: Int): BigInt { + if (length == 0) return 0.toBigInt() + val bits = preloadBitString(length) + val intBits = buildString(length) { + bits.forEach { bit -> + if (bit) { + append('1') + } else { + append('0') + } + } + } + return BigInt(intBits, 2) + } public fun loadUInt8(): UByte = loadTinyInt(8).toUByte() public fun loadUInt16(): UShort = loadTinyInt(16).toUShort() public fun loadUInt32(): UInt = loadTinyInt(32).toUInt() - public fun loadUInt64(): ULong = loadTinyInt(64).toULong() + + @Deprecated("use loadULong() instead", ReplaceWith("loadULong()")) + public fun loadUInt64(): ULong = loadULong() + + public fun loadULong(bitCount: Int = ULong.SIZE_BITS): ULong = loadTinyInt(64).toULong() public fun loadTinyInt(length: Int): Long = loadInt(length).toLong() public fun preloadTinyInt(length: Int): Long = preloadInt(length).toLong() @@ -63,6 +114,9 @@ public interface CellSlice { public fun isEmpty(): Boolean = bits.isEmpty() && refs.isEmpty() + public fun countLeadingBits(bit: Boolean): Int = + bits.countLeadingBits(bitsPosition, bits.size, bit) + public operator fun component1(): BitString = bits public operator fun component2(): List = refs @@ -72,12 +126,17 @@ public interface CellSlice { return of(cell.bits, cell.refs) } + @Deprecated("Scheduled to remove", level = DeprecationLevel.WARNING) @JvmStatic public fun of(bits: BitString, refs: List = emptyList()): CellSlice { return if (bits is ByteBackedBitString) { CellSliceByteBackedBitString(bits, refs) } else { - CellSliceImpl(bits, refs) + val bitString = ByteBackedMutableBitString.of(bits.size) + bits.forEachIndexed { index, bit -> + bitString[index] = bit + } + CellSliceByteBackedBitString(bitString, refs) } } } @@ -85,130 +144,19 @@ public interface CellSlice { public inline operator fun CellSlice.invoke(cellSlice: CellSlice.() -> T): T = let(cellSlice) -public inline fun CellSlice.loadRef(cellSlice: CellSlice.() -> T): T = - cellSlice(loadRef().beginParse()) - -private open class CellSliceImpl( - override val bits: BitString, - override val refs: List, - override var bitsPosition: Int = 0, - override var refsPosition: Int = 0 -) : CellSlice { - override fun endParse() = - check(bitsPosition >= bits.size) { "bitsPosition: $bitsPosition != bits.length: ${bits.size}" } - - override fun loadRef(): Cell { - checkRefsOverflow() - val cell = preloadRef() - refsPosition++ - return cell - } - - override fun loadRefs(count: Int): List = List(count) { loadRef() } - - override fun preloadRef(): Cell = refs[refsPosition] - - override fun preloadRef(cellSlice: CellSlice.() -> T): T { - val slice = preloadRef().beginParse() - return cellSlice(slice) - } - - override fun preloadRefs(count: Int): List = List(refsPosition + count) { refs[it] } - - override fun loadBit(): Boolean { - val bit = preloadBit() - bitsPosition++ - return bit - } - - override fun preloadBit(): Boolean = try { - bits[bitsPosition] - } catch (e: BitStringUnderflowException) { - throw CellUnderflowException(e) - } - - override fun skipBits(length: Int): CellSlice = apply { - bitsPosition += length - } - - override fun loadBits(length: Int): BitString { - val bitString = preloadBits(length) - bitsPosition += length - return bitString - } - - override fun preloadBits(length: Int): BitString { - checkBitsOverflow(length) - return bits.slice(bitsPosition..length) - } - - override fun loadInt(length: Int): BigInt { - val int = preloadInt(length) - bitsPosition += length - return int - } - - override fun loadTinyInt(length: Int): Long { - val tinyInt = preloadTinyInt(length) - bitsPosition += length - return tinyInt - } - - override fun preloadInt(length: Int): BigInt { - val uint = preloadUInt(length) - val int = 1.toBigInt() shl (length - 1) - return if (uint >= int) uint - (int * 2.toBigInt()) else uint - } - - override fun loadUInt(length: Int): BigInt { - val uint = preloadUInt(length) - bitsPosition += length - return uint - } - - override fun preloadUInt(length: Int): BigInt { - if (length == 0) return 0.toBigInt() - val bits = preloadBits(length) - val intBits = buildString(length) { - bits.forEach { bit -> - if (bit) { - append('1') - } else { - append('0') - } - } - } - return BigInt(intBits, 2) - } - - protected fun checkBitsOverflow(length: Int) { - val remaining = bits.size - bitsPosition - require(length <= remaining) { - "Bits overflow. Can't load $length bits. $remaining bits left." - } - } - - protected fun checkRefsOverflow() { - val remaining = 4 - refsPosition - require(1 <= remaining) { - "Refs overflow. Can't load ref. $remaining refs left." - } - } - - override fun toString(): String = buildString { - append("x") - append(bits.toString()) - if (refs.isNotEmpty()) { - append(",") - append(refs.size) - } +public inline fun CellSlice.loadRef(context: CellContext = CellContext.EMPTY, block: CellSlice.() -> T): T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return block(context.loadCell(loadRef()).beginParse()) } private class CellSliceByteBackedBitString( override val bits: ByteBackedBitString, - refs: List -) : CellSliceImpl(bits, refs) { + override val refs: List, + override var bitsPosition: Int = 0, + override var refsPosition: Int = 0 +) : CellSlice { val data get() = bits.bytes fun getBits(offset: Int, length: Int): Byte { @@ -250,24 +198,23 @@ private class CellSliceByteBackedBitString( return value shr (64 - length) } - override fun preloadBits(length: Int): BitString { - val bytes = length / 8 - val remainder = length % 8 - val arraySize = bytes + if (remainder != 0) 1 else 0 - val array = ByteArray(arraySize) - if (bitsPosition % 8 == 0) { - val startIndex = bitsPosition / 8 - data.copyInto(array, startIndex = startIndex, endIndex = startIndex + bytes) - } else { - repeat(bytes) { i -> - array[i] = getByte(i * 8) - } - } - if (remainder != 0) { - val v = getBits(bytes * 8, remainder).toInt() shl (8 - remainder) - array[array.lastIndex] = v.toByte() - } - return BitString(array, length) + override fun preloadBitString(bitCount: Int): BitString { + val bits = ByteBackedMutableBitString(bitCount) + this.bits.copyInto(bits, 0, bitsPosition, bitsPosition + bitCount) + return bits + } + + override fun loadByteArray(byteCount: Int): ByteArray { + val result = preloadByteArray(byteCount) + bitsPosition += byteCount * 8 + return result + } + + override fun preloadByteArray(byteCount: Int): ByteArray { + val array = ByteArray(byteCount) + val bits = ByteBackedMutableBitString(array, byteCount * 8) + this.bits.copyInto(bits, 0, bitsPosition, bitsPosition + byteCount * 8) + return array } override fun preloadUInt(length: Int): BigInt { @@ -322,4 +269,100 @@ private class CellSliceByteBackedBitString( else -> throw IllegalArgumentException("expected length in 0..64, actual: $length") } } + + override fun endParse() = + check(bitsPosition >= bits.size) { "bitsPosition: $bitsPosition != bits.length: ${bits.size}" } + + override fun loadRef(): Cell { + checkRefsOverflow() + val cell = preloadRef() + refsPosition++ + return cell + } + + override fun loadNullableRef(): Cell? { + return if (loadBoolean()) { + loadRef() + } else { + null + } + } + + override fun loadRefs(count: Int): List = List(count) { loadRef() } + + override fun preloadRef(): Cell = refs[refsPosition] + + override fun preloadRef(cellSlice: CellSlice.() -> T): T { + val slice = preloadRef().beginParse() + return cellSlice(slice) + } + + override fun preloadRef(offset: Int): Cell { + return refs[refsPosition + offset] + } + + override fun preloadRefs(count: Int): List = List(refsPosition + count) { refs[it] } + + override fun loadBoolean(): Boolean { + val bit = preloadBoolean() + bitsPosition++ + return bit + } + + override fun preloadBoolean(): Boolean = try { + bits[bitsPosition] + } catch (e: BitStringUnderflowException) { + throw CellUnderflowException(e) + } + + override fun skipBits(length: Int): CellSlice = apply { + bitsPosition += length + } + + override fun loadBitString(bitCount: Int): BitString { + val bitString = preloadBitString(bitCount) + bitsPosition += bitCount + return bitString + } + + override fun loadInt(length: Int): BigInt { + val int = preloadInt(length) + bitsPosition += length + return int + } + + override fun loadTinyInt(length: Int): Long { + val tinyInt = preloadTinyInt(length) + bitsPosition += length + return tinyInt + } + + override fun loadUInt(length: Int): BigInt { + val uint = preloadUInt(length) + bitsPosition += length + return uint + } + + protected fun checkBitsOverflow(length: Int) { + val remaining = bits.size - bitsPosition + require(length <= remaining) { + "Bits overflow. Can't load $length bits. $remaining bits left." + } + } + + protected fun checkRefsOverflow() { + val remaining = 4 - refsPosition + require(1 <= remaining) { + "Refs overflow. Can't load ref. $remaining refs left." + } + } + + override fun toString(): String = buildString { + append("x") + append(bits.toString()) + if (refs.isNotEmpty()) { + append(",") + append(refs.size) + } + } } diff --git a/tvm/test/BagOfCellsTest.kt b/tvm/test/BagOfCellsTest.kt index 74cfa964..ced4eddc 100644 --- a/tvm/test/BagOfCellsTest.kt +++ b/tvm/test/BagOfCellsTest.kt @@ -2,6 +2,8 @@ package org.ton.cell import io.ktor.util.* import org.ton.boc.BagOfCells +import org.ton.boc.base64ToCell +import kotlin.io.encoding.Base64 import kotlin.test.Test import kotlin.test.assertEquals @@ -13,4 +15,28 @@ class BagOfCellsTest { assertEquals("000001010000000000000045", hex(boc.roots.first().bits.toByteArray())) } + + @Test + fun testTxBoc() { + val base64boc = + "te6cckECBwEAAXYAA7V5QBVtaGBzXelnC+DoDhctQO99SeiHtx97kPR6CqcKIBAAAY3pKFDwECaGi15kBA/sg+mS5AXFRbdn6kqS4yBQE7nybKbPnPtQAAGN4NmfWBZxzFkwACBgQSDoAQIDAgHgBAUAgnJQdVmYCFXS9KgXRepSXHT8e+rFn5z5+QuRNP8kfXkPQu1TOHkZ0mu5gLKdK7eCsCXnvOxGjTz0QiYLq2OyHJBWAB8ETQjmJaABwDAgjTMEEa1AAK9oAct9CC/XwHCKXyewXhMtNci1Zua3V+FLpl8rt7T586IZACUAVbWhgc13pZwvg6A4XLUDvfUnoh7cfe5D0egqnCiATmJaAAYII1oAADG9JJAMBM45ixpAAQHfBgC3WAEoAq2tDA5rvSzhfB0BwuWoHe+pPRD24+9yHo9BVOFEAwA5b6EF+vgOEUvk9gvCZaa5Fqzc1ur8KXTL5Xb2nz50Qw5J8AAGCCNaAAAxvSUKHgTOOYsmf////8AumLaq" + val boc = base64boc.base64ToCell() + assertEquals( + "416f947497d143bc02e344fa292ace136e21c2f4b4f8b2dde039dc189b37a8ca", + boc.hash().toHexString().lowercase() + ) + } + + @Test + fun testDeserialization() { + val boc1 = Base64.decode( + "te6cckECUwEACncAART/APSkE/S88sgLAQIBYgIDAgLMBAUAEaE0Y+AN4BHgCwIBIAYHAgFIDA0ApdGZFjgEkvgfBoaYGAuNhJL4HweAN9IBgBaY/pn5FAosxdT+p9IALBBExLQF55cD34BUkZmHFBBARJGl1HCWoQ+AR4AonjgvlwXoD9IBh4Bcit8UAgEgCAkCASAKCwARTtRND6QDD4YYADscMjKAFADzxYBzxaLAs8WyXAgyMsBE/QA9ADLAMmAAGz5AHB0yMsCygfL/8nQgBFlND5AvhBiIiIcMhQBc8WFMsBFMv/E8xSIMzMyXAgyMsBE/QA9ADLAMnwBfgogOSUoPAgEgJCUBFP8A9KQT9LzyyAsmAQiIEvAEEAEU/wD0pBP0vPLICxECAWISEwICzBQVACmgvqvgA/CD8IXwh/CJ8IvwjfCP4AcCASAWFwHZtQBBrkOmP6Z+YEMCIiN1HKJj8IYljgvlwyMEEJiWgOX2BfCIAuEEIapk7baw2wYM4QAxkZYKoA+eLKAL9AQrltQllj+WfkTdZyixni4DImXEA5ID9gD/8MMWBfDI4fDL4AXAAwQQESRpdcYEtyMCASAYGQAV1kLGeLAP0BZPw0QCASAaGwIBICEiA/UMyLHAJJfA+DQ0wP6QDDwAQFxsJQxAfAK4ALTH9M/IoFFmLrjAjAhgRESuo49bCH4QxLHBfLhkfhEAXCCAUWYWG2BAKBwgBjIywVQB88WUAX6AhXLahLLH8s/Im6zlFjPFwGRMuIByQH7AOD4QfLh1yGCAUV4uuMCMzGAcHR4AbTtRNDSAAH4YfpAAfhi+kAB+GP6QAH4ZPhBs/hE10nAArCRMODTPwH4ZdMfAfhm1AH4Z9Qw+GiACuGwi+EH4QhTHBbMTsfhE10nCArEC+kAB+GQCjjMx+EQBcIIBRZhYbYBAcIAYyMsFUAfPFlAF+gIVy2oSyx/LPyJus5RYzxcBkTLiAckB+wDg+GXUMPhncPhmiPhoSR8B0DEBgghMS0Ch8AMgjj1TILzy4834Rvgjtgn4ZoIIkUV4+CNtcHCAGMjLBVAHzxZQBfoCFctqEssfyz8ibrOUWM8XAZEy4gHJAfsAjhJbIIIQBfXhALzy49D4I6YU+GbiUiDwBIIBRXgBIACsgTJSuo5N+EbCAPhG+CO5sPLj0fADMPhHWPhCcIIICJI0BMjMUAXPFhRDMIMGcIAYyMsFUAfPFlAF+gIVy2oSyx/LPyJus5RYzxcBkTLiAckB+wCRMOIAZvhDcIEREfgjbYBAcIAYyMsFUAfPFlAF+gIVy2oSyx/LPyJus5RYzxcBkTLiAckB+wDwAgBggggehIBZbXJwgBjIywVQB88WUAX6AhXLahLLH8s/Im6zlFjPFwGRMuIByQH7APACAEU+Ej4R/hG+EX4QcjKAPhCzxb4Q88W+ETPFss/yx/MzMntVIAAjPhI0CDXSZQwiwJw4fpA+gAwgAHr4QhLHBfLhkfADMAFwggh4kjRYbYEAoHCAGMjLBVAHzxZQBfoCFctqEssfyz8ibrOUWM8XAZEy4gHJAfsAAFMIfAIIPAFgUWYdoAYyMsFUAPPFnD6AhLLaxLMyx8Tyz9YzxbMyYBA+wCAAUT4I4EIiHCAEMjLBfhBzxaCC5OHAPoCy2rLH8s/Esxw+gIBzxbJcfsAgAgFiJygCAsspKgIBIEFCAgEgKywCAWI/QAIBIC0uADHfwjfCL8Inwh5Hwg54t8IWeLZmZmZmT2qkAgFILzACASA7PATfDIhxwCSXwPg0NMDAXGwkl8D4PpA+kAx+gAxcdch+gAx+gAw8AfwBo4VMGwS+EHHBfLhkfpAAfhi1DD4Y/AI4QLTH9M/IoIQX8w9FLqOijIC+ELHBfLhkVjgIoIQL8smorrjAiKBERG64wIigQd3uoDEyMzQAET6RDDAAPLhTYAL0AfpAIfAB+kDSADH6AAaCCvrwgKEhlFMUoKHeItcLAcMAIJIFoZE14iDC//LhkiGOPYIQBRONkcj4Qs8WUAjPFnElBEkTVEigcIAQyMsFUAfPFlAF+gIVy2oSyx/LPyJus5RYzxcBkTLiAckB+wCSNjDiApJsMeMN+GI5OgCGMDFsInCCEIt3FzWCAf3o7UPYyMv/+EHPFkEwgEBwgBDIywVQB88WUAX6AhXLahLLH8s/Im6zlFjPFwGRMuIByQH7AABuMDFsInCBERLwBsjL/0EwgEBwgBDIywVQB88WUAX6AhXLahLLH8s/Im6zlFjPFwGRMuIByQH7AAT8jhA1WzH4QscF8uGR1DD4ZPAI4CKBCZm6jrQDcPgz0NcL/wH6RAHA/wK6sPLhkQLTHzEhghBfzD0UupM0bCHjDYEHd7qW1DD4ZPAIkTDi4DQ0IIIQaT05ULrjAjMigQiIuo4RbBL4QscF8uGR1PoA+kAw8BDgMAGBCIm64wIwNTY3OAL+REBSBAH6QCHwAfpA0gAx+gAGggr68IChIZRTFKCh3iLXCwHDACCSBaGRNeIgwv/y4ZIhjj2CEAUTjZHI+ELPFlAIzxZxJQRJE1RIoHCAEMjLBVAHzxZQBfoCFctqEssfyz8ibrOUWM8XAZEy4gHJAfsAkjYw4gKSbDHjDfhiATk6AFAwMQGCEKjLAK1wgBDIywVQBM8WI/oCE8tqEssfyz/4RtDPFsmAQPsAAGBwAdSOKAGAQPSWb6UxII4YBKQggQD6vpPywY/eA9QC+gD6QDDwEEATkTHisxLmXwMACIQP8vAAaiHwAUEwghDVMnbbUARtcXCAEMjLBVAHzxZQBfoCFctqEssfyz8ibrOUWM8XAZEy4gHJAfsAAATwCAAbX5AHB0yMsCygfL/8nQgCASA9PgAPPhC10nAArOAATztRND6QAH4YfpAAfhi8AaU1AH4Y5SDB9ch4tQB+GTUAfhl1AH4ZtGACn0ItD5Avgo+EWIiHDIUAXPFhTLARTL/xPMUiDMzMlwIMjLARP0APQAywDJIPAFdoAYyMsFWM8WJPoCy2vMAc8WEswBwACSgECRcOIByQH7AISUoAYUcCFtcI4eBNMHAZ40IqoCEtcYMXjXIX9QJN8DpCPXSbMlsRQV5jMCkTLgW4QP8vAggCASBDRAIBIEtMAAe4tdMYAgEgRUYAHbXa/gD/CNoaYfph/0gGEAIBIEdIAlmx6PwB/go+EWIiHDIUAXPFhTLARTL/xPMUiDMzMlwIMjLARP0APQAywDJ8AWBJSgJdsDL8Af5Avgo+EWIiHDIUAXPFhTLARTL/xPMUiDMzMlwIMjLARP0APQAywDJ8AWBJSgAAAAkAAAABIAIBSE1OAgEgT1AAJbPz/AHf4IB/ejtQ9j4QfhC+ESAAE7AW/AHf/hE+EKAADbTB/gD+ANACASBRUgD3sMM8AcB8BL4Q9BSEMcF8uRXIddJjhwy8BIwAddJpgiCALqTyMsPAoIBcMvtQ9gSzxbJ4DEBwAGOPfhE0NMHAcAA8udQ1DCC8JGsScaXSCMg5UlvLlLjbMcHC5X8ITCb89pSg/x8oHrPAYMH9A/y51EB10mmCAHgMHPIyYAAds3o+ENukvAH3vhD0PkCgEOMwag==" + ) + val cell1 = BagOfCells(boc1).first() + + val boc2 = BagOfCells(cell1).toByteArray() + + val cell2 = BagOfCells(boc2).first() + assertEquals(cell1, cell2) + } }