From beab635aba9d222ca2a7f0858f9eec34046f641a Mon Sep 17 00:00:00 2001 From: Peter <> Date: Mon, 23 Sep 2019 22:30:37 +0400 Subject: [PATCH] Update tonlib [skip ci] --- submodules/MtProtoKit/TON/TON.h | 5 +- submodules/MtProtoKit/TON/TON.mm | 26 ++- .../TelegramCore/TelegramCore/Wallets.swift | 130 ++++++++----- .../WalletUI/Sources/WalletInfoScreen.swift | 78 ++++++-- .../WalletUI/Sources/WalletSendScreen.swift | 6 +- .../ton/tonlib-src/adnl/adnl-ext-client.cpp | 107 +++++++++++ .../ton/tonlib-src/adnl/adnl-ext-client.h | 8 + .../ton/tonlib-src/adnl/adnl-ext-client.hpp | 46 +++++ .../ton/tonlib-src/tdutils/td/utils/Timer.cpp | 31 ++- .../ton/tonlib-src/tdutils/td/utils/Timer.h | 10 +- .../tdutils/td/utils/filesystem.cpp | 15 +- .../tl/generate/auto/tl/ton_api.cpp | 14 +- .../tonlib-src/tl/generate/auto/tl/ton_api.h | 6 +- .../tl/generate/auto/tl/ton_api_json.cpp | 10 +- .../tl/generate/auto/tl/tonlib_api.cpp | 20 +- .../tl/generate/auto/tl/tonlib_api.h | 20 +- .../tl/generate/auto/tl/tonlib_api_json.cpp | 36 +++- .../tonlib-src/tl/generate/scheme/ton_api.tl | 2 +- .../tonlib-src/tl/generate/scheme/ton_api.tlo | Bin 51664 -> 51684 bytes .../tl/generate/scheme/tonlib_api.tl | 8 +- .../tl/generate/scheme/tonlib_api.tlo | Bin 9420 -> 9548 bytes .../ton/tonlib-src/tonlib/CMakeLists.txt | 2 + .../tonlib-src/tonlib/test/.online.cpp.swp | Bin 24576 -> 0 bytes .../ton/tonlib-src/tonlib/test/offline.cpp | 4 +- .../ton/tonlib-src/tonlib/test/online.cpp | 11 +- .../tonlib/tonlib/BlockchainInfoStorage.cpp | 0 .../tonlib/tonlib/BlockchainInfoStorage.h | 11 -- .../tonlib-src/tonlib/tonlib/ExtClient.cpp | 6 +- .../ton/tonlib-src/tonlib/tonlib/ExtClient.h | 6 +- .../tonlib/tonlib/GenericAccount.cpp | 2 +- .../tonlib-src/tonlib/tonlib/LastBlock.cpp | 66 +++++-- .../ton/tonlib-src/tonlib/tonlib/LastBlock.h | 111 +++++++++-- .../tonlib/tonlib/LastBlockStorage.cpp | 44 +++++ .../tonlib/tonlib/LastBlockStorage.h | 16 ++ .../tonlib-src/tonlib/tonlib/TestGiver.cpp | 5 +- .../ton/tonlib-src/tonlib/tonlib/TestGiver.h | 2 +- .../tonlib-src/tonlib/tonlib/TestWallet.cpp | 12 +- .../ton/tonlib-src/tonlib/tonlib/TestWallet.h | 3 +- .../tonlib-src/tonlib/tonlib/TonlibClient.cpp | 178 +++++++++++------- .../tonlib-src/tonlib/tonlib/TonlibClient.h | 3 + .../tonlib-src/tonlib/tonlib/tonlib-cli.cpp | 13 +- 41 files changed, 807 insertions(+), 266 deletions(-) delete mode 100644 submodules/ton/tonlib-src/tonlib/test/.online.cpp.swp delete mode 100644 submodules/ton/tonlib-src/tonlib/tonlib/BlockchainInfoStorage.cpp delete mode 100644 submodules/ton/tonlib-src/tonlib/tonlib/BlockchainInfoStorage.h create mode 100644 submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.cpp create mode 100644 submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.h diff --git a/submodules/MtProtoKit/TON/TON.h b/submodules/MtProtoKit/TON/TON.h index 21051e8dee..17c500e573 100644 --- a/submodules/MtProtoKit/TON/TON.h +++ b/submodules/MtProtoKit/TON/TON.h @@ -43,8 +43,9 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) int64_t value; @property (nonatomic, strong, readonly) NSString * _Nonnull source; @property (nonatomic, strong, readonly) NSString * _Nonnull destination; +@property (nonatomic, strong, readonly) NSString * _Nonnull textMessage; -- (instancetype)initWithValue:(int64_t)value source:(NSString * _Nonnull)source destination:(NSString * _Nonnull)destination; +- (instancetype)initWithValue:(int64_t)value source:(NSString * _Nonnull)source destination:(NSString * _Nonnull)destination textMessage:(NSString * _Nonnull)textMessage; @end @@ -80,7 +81,7 @@ NS_ASSUME_NONNULL_BEGIN - (MTSignal *)getTestGiverAddress; - (MTSignal *)testGiverSendGramsWithAccountState:(TONAccountState *)accountState accountAddress:(NSString *)accountAddress amount:(int64_t)amount; - (MTSignal *)getAccountStateWithAddress:(NSString *)accountAddress; -- (MTSignal *)sendGramsFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount; +- (MTSignal *)sendGramsFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount textMessage:(NSString *)textMessage; - (MTSignal *)exportKey:(TONKey *)key localPassword:(NSData *)localPassword; - (MTSignal *)importKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword wordList:(NSArray *)wordList; - (MTSignal *)deleteKeyWithPublicKey:(NSString *)publicKey; diff --git a/submodules/MtProtoKit/TON/TON.mm b/submodules/MtProtoKit/TON/TON.mm index a1d75df6eb..10ed2e58e6 100644 --- a/submodules/MtProtoKit/TON/TON.mm +++ b/submodules/MtProtoKit/TON/TON.mm @@ -43,10 +43,14 @@ static TONTransactionMessage * _Nullable parseTransactionMessage(tonlib_api::obj } NSString *source = readString(message->source_); NSString *destination = readString(message->source_); + NSString *textMessage = readString(message->message_); if (source == nil || destination == nil) { return nil; } - return [[TONTransactionMessage alloc] initWithValue:message->value_ source:source destination:destination]; + if (textMessage == nil) { + textMessage = @""; + } + return [[TONTransactionMessage alloc] initWithValue:message->value_ source:source destination:destination textMessage:textMessage]; } @implementation TONKey @@ -91,12 +95,13 @@ static TONTransactionMessage * _Nullable parseTransactionMessage(tonlib_api::obj @implementation TONTransactionMessage -- (instancetype)initWithValue:(int64_t)value source:(NSString * _Nonnull)source destination:(NSString * _Nonnull)destination { +- (instancetype)initWithValue:(int64_t)value source:(NSString * _Nonnull)source destination:(NSString * _Nonnull)destination textMessage:(NSString * _Nonnull)textMessage { self = [super init]; if (self != nil) { _value = value; _source = source; _destination = destination; + _textMessage = textMessage; } return self; } @@ -449,7 +454,12 @@ typedef enum { } }]; - auto query = make_object(make_object(accountAddress.UTF8String), accountState.seqno, amount); + auto query = make_object(make_object( + accountAddress.UTF8String), + accountState.seqno, + amount, + std::string() + ); _client->send({ requestId, std::move(query) }); return [[MTBlockDisposable alloc] initWithBlock:^{ @@ -493,13 +503,18 @@ typedef enum { }] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]]; } -- (MTSignal *)sendGramsFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount { +- (MTSignal *)sendGramsFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount textMessage:(NSString * _Nonnull)textMessage { return [[[[MTSignal alloc] initWithGenerator:^id(MTSubscriber *subscriber) { NSData *publicKeyData = [key.publicKey dataUsingEncoding:NSUTF8StringEncoding]; if (publicKeyData == nil) { [subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in sendGramsFromKey"]]; return [[MTBlockDisposable alloc] initWithBlock:^{}]; } + NSData *textMessageData = [textMessage dataUsingEncoding:NSUTF8StringEncoding]; + if (textMessageData == nil) { + [subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in sendGramsFromKey"]]; + return [[MTBlockDisposable alloc] initWithBlock:^{}]; + } uint64_t requestId = _nextRequestId; _nextRequestId += 1; @@ -523,7 +538,8 @@ typedef enum { ), make_object(fromAddress.UTF8String), make_object(address.UTF8String), - amount + amount, + makeString(textMessageData) ); _client->send({ requestId, std::move(query) }); diff --git a/submodules/TelegramCore/TelegramCore/Wallets.swift b/submodules/TelegramCore/TelegramCore/Wallets.swift index 4bd3b2f353..0eb9770fc2 100644 --- a/submodules/TelegramCore/TelegramCore/Wallets.swift +++ b/submodules/TelegramCore/TelegramCore/Wallets.swift @@ -69,10 +69,33 @@ public final class TonInstance { }) } - fileprivate func createWallet(keychain: TonKeychain, serverSalt: Data) -> Signal<(WalletInfo, [String]), NoError> { + fileprivate func exportKey(key: TONKey, serverSalt: Data) -> Signal<[String], NoError> { return Signal { subscriber in let disposable = MetaDisposable() + self.impl.with { impl in + impl.withInstance { ton in + let cancel = ton.export(key, localPassword: serverSalt).start(next: { wordList in + guard let wordList = wordList as? [String] else { + assertionFailure() + return + } + subscriber.putNext(wordList) + subscriber.putCompletion() + }) + disposable.set(ActionDisposable { + cancel?.dispose() + }) + } + } + + return disposable + } + } + + fileprivate func createWallet(keychain: TonKeychain, serverSalt: Data) -> Signal<(WalletInfo, [String]), NoError> { + return Signal { subscriber in + let disposable = MetaDisposable() self.impl.with { impl in impl.withInstance { ton in let cancel = ton.createKey(withLocalPassword: serverSalt, mnemonicPassword: Data()).start(next: { key in @@ -85,13 +108,11 @@ public final class TonInstance { assertionFailure() return } - let cancel = ton.export(key, localPassword: serverSalt).start(next: { wordList in - guard let wordList = wordList as? [String] else { - assertionFailure() - return - } + let _ = self.exportKey(key: key, serverSalt: serverSalt).start(next: { wordList in subscriber.putNext((WalletInfo(publicKey: WalletPublicKey(rawValue: key.publicKey), encryptedSecret: EncryptedWalletSecret(rawValue: encryptedSecretData)), wordList)) subscriber.putCompletion() + }, error: { _ in + preconditionFailure() }) }, error: { _ in }, completed: { @@ -195,30 +216,20 @@ public final class TonInstance { } } - fileprivate func walletBalance(publicKey: WalletPublicKey) -> Signal { + fileprivate func getWalletState(address: String) -> Signal { return Signal { subscriber in let disposable = MetaDisposable() self.impl.with { impl in impl.withInstance { ton in - let cancel = ton.getTestWalletAccountAddress(withPublicKey: publicKey.rawValue).start(next: { address in - guard let address = address as? String else { + let cancel = ton.getAccountState(withAddress: address).start(next: { state in + guard let state = state as? TONAccountState else { return } - let cancel = ton.getAccountState(withAddress: address).start(next: { state in - guard let state = state as? TONAccountState else { - return - } - subscriber.putNext(WalletBalance(rawValue: state.balance)) - }, error: { _ in - }, completed: { - subscriber.putCompletion() - }) - disposable.set(ActionDisposable { - cancel?.dispose() - }) + subscriber.putNext(WalletState(balance: state.balance, lastTransactionId: state.lastTransactionId.flatMap(WalletTransactionId.init(tonTransactionId:)))) }, error: { _ in }, completed: { + subscriber.putCompletion() }) disposable.set(ActionDisposable { cancel?.dispose() @@ -282,17 +293,39 @@ public final class TonInstance { } } - fileprivate func getGramsFromTestGiver(address: String, amount: Int64) -> Signal { + fileprivate func getTestGiverAccountState() -> Signal { return Signal { subscriber in let disposable = MetaDisposable() self.impl.with { impl in impl.withInstance { ton in let cancel = ton.getTestGiverAccountState().start(next: { state in - guard let state = state as? TONAccountState else { - subscriber.putError(.generic) - return - } + subscriber.putNext(state as? TONAccountState) + subscriber.putCompletion() + }, error: { _ in + subscriber.putNext(nil) + subscriber.putCompletion() + }, completed: { + }) + } + } + + return disposable + } + } + + fileprivate func getGramsFromTestGiver(address: String, amount: Int64) -> Signal { + return self.getTestGiverAccountState() + |> introduceError(GetGramsFromTestGiverError.self) + |> mapToSignal { state in + guard let state = state else { + return .fail(.generic) + } + return Signal { subscriber in + let disposable = MetaDisposable() + + self.impl.with { impl in + impl.withInstance { ton in let cancel = ton.testGiverSendGrams(with: state, accountAddress: address, amount: amount).start(next: { _ in }, error: { _ in subscriber.putError(.generic) @@ -302,21 +335,15 @@ public final class TonInstance { disposable.set(ActionDisposable { cancel?.dispose() }) - }, error: { _ in - subscriber.putError(.generic) - }, completed: { - }) - disposable.set(ActionDisposable { - cancel?.dispose() - }) + } } + + return disposable } - - return disposable } } - fileprivate func sendGramsFromWallet(keychain: TonKeychain, serverSalt: Data, walletInfo: WalletInfo, fromAddress: String, toAddress: String, amount: Int64) -> Signal { + fileprivate func sendGramsFromWallet(keychain: TonKeychain, serverSalt: Data, walletInfo: WalletInfo, fromAddress: String, toAddress: String, amount: Int64, textMessage: String) -> Signal { return keychain.decrypt(walletInfo.encryptedSecret.rawValue) |> introduceError(SendGramsFromWalletError.self) |> mapToSignal { decryptedSecret -> Signal in @@ -328,7 +355,7 @@ public final class TonInstance { self.impl.with { impl in impl.withInstance { ton in - let cancel = ton.sendGrams(from: TONKey(publicKey: walletInfo.publicKey.rawValue, secret: decryptedSecret), localPassword: serverSalt, fromAddress: fromAddress, toAddress: toAddress, amount: amount).start(next: { _ in + let cancel = ton.sendGrams(from: TONKey(publicKey: walletInfo.publicKey.rawValue, secret: decryptedSecret), localPassword: serverSalt, fromAddress: fromAddress, toAddress: toAddress, amount: amount, textMessage: textMessage).start(next: { _ in preconditionFailure() }, error: { _ in subscriber.putError(.generic) @@ -526,11 +553,13 @@ public func walletRestoreWords(network: Network, walletInfo: WalletInfo, tonInst } } -public struct WalletBalance: Hashable { - public var rawValue: Int64 +public struct WalletState: Equatable { + public let balance: Int64 + public let lastTransactionId: WalletTransactionId? - public init(rawValue: Int64) { - self.rawValue = rawValue + public init(balance: Int64, lastTransactionId: WalletTransactionId?) { + self.balance = balance + self.lastTransactionId = lastTransactionId } } @@ -542,8 +571,8 @@ public func testGiverWalletAddress(tonInstance: TonInstance) -> Signal Signal { - return tonInstance.walletBalance(publicKey: publicKey) +public func getWalletState(address: String, tonInstance: TonInstance) -> Signal { + return tonInstance.getWalletState(address: address) } public enum GetGramsFromTestGiverError { @@ -559,7 +588,7 @@ public enum SendGramsFromWalletError { case secretDecryptionFailed } -public func sendGramsFromWallet(network: Network, tonInstance: TonInstance, keychain: TonKeychain, walletInfo: WalletInfo, toAddress: String, amount: Int64) -> Signal { +public func sendGramsFromWallet(network: Network, tonInstance: TonInstance, keychain: TonKeychain, walletInfo: WalletInfo, toAddress: String, amount: Int64, textMessage: String) -> Signal { return getServerWalletSalt(network: network) |> mapError { _ -> SendGramsFromWalletError in return .generic @@ -568,7 +597,7 @@ public func sendGramsFromWallet(network: Network, tonInstance: TonInstance, keyc return walletAddress(publicKey: walletInfo.publicKey, tonInstance: tonInstance) |> introduceError(SendGramsFromWalletError.self) |> mapToSignal { fromAddress in - return tonInstance.sendGramsFromWallet(keychain: keychain, serverSalt: serverSalt, walletInfo: walletInfo, fromAddress: fromAddress, toAddress: toAddress, amount: amount) + return tonInstance.sendGramsFromWallet(keychain: keychain, serverSalt: serverSalt, walletInfo: walletInfo, fromAddress: fromAddress, toAddress: toAddress, amount: amount, textMessage: textMessage) } } } @@ -589,11 +618,13 @@ public final class WalletTransactionMessage: Equatable { public let value: Int64 public let source: String public let destination: String + public let textMessage: String - init(value: Int64, source: String, destination: String) { + init(value: Int64, source: String, destination: String, textMessage: String) { self.value = value self.source = source self.destination = destination + self.textMessage = textMessage } public static func ==(lhs: WalletTransactionMessage, rhs: WalletTransactionMessage) -> Bool { @@ -604,7 +635,10 @@ public final class WalletTransactionMessage: Equatable { return false } if lhs.destination != rhs.destination { - return false; + return false + } + if lhs.textMessage != rhs.textMessage { + return false } return true } @@ -612,7 +646,7 @@ public final class WalletTransactionMessage: Equatable { private extension WalletTransactionMessage { convenience init(tonTransactionMessage: TONTransactionMessage) { - self.init(value: tonTransactionMessage.value, source: tonTransactionMessage.source, destination: tonTransactionMessage.destination) + self.init(value: tonTransactionMessage.value, source: tonTransactionMessage.source, destination: tonTransactionMessage.destination, textMessage: tonTransactionMessage.textMessage) } } diff --git a/submodules/WalletUI/Sources/WalletInfoScreen.swift b/submodules/WalletUI/Sources/WalletInfoScreen.swift index 7271d2fc7a..da9dab6d27 100644 --- a/submodules/WalletUI/Sources/WalletInfoScreen.swift +++ b/submodules/WalletUI/Sources/WalletInfoScreen.swift @@ -87,8 +87,8 @@ public final class WalletInfoScreen: ViewController { } private final class WalletInfoBalanceNode: ASDisplayNode { - private let balanceTextNode: ImmediateTextNode - private let balanceIconNode: ASImageNode + let balanceTextNode: ImmediateTextNode + let balanceIconNode: ASImageNode var balance: String = " " { didSet { @@ -96,6 +96,8 @@ private final class WalletInfoBalanceNode: ASDisplayNode { } } + var isLoading: Bool = true + init(theme: PresentationTheme) { self.balanceTextNode = ImmediateTextNode() self.balanceTextNode.displaysAsynchronously = false @@ -123,9 +125,14 @@ private final class WalletInfoBalanceNode: ASDisplayNode { let balanceOrigin = CGPoint(x: floor((width - balanceTextSize.width - balanceIconSpacing - balanceIconSize.width / 2.0) / 2.0), y: 0.0) let balanceTextFrame = CGRect(origin: balanceOrigin, size: balanceTextSize) - let balanceIconFrame = CGRect(origin: CGPoint(x: balanceTextFrame.maxX + balanceIconSpacing, y: balanceTextFrame.minY + floor((balanceTextFrame.height - balanceIconSize.height) / 2.0)), size: balanceIconSize) + let balanceIconFrame: CGRect + if self.isLoading { + balanceIconFrame = CGRect(origin: CGPoint(x: floor((width - balanceIconSize.width) / 2.0), y: balanceTextFrame.minY + floor((balanceTextFrame.height - balanceIconSize.height) / 2.0)), size: balanceIconSize) + } else { + balanceIconFrame = CGRect(origin: CGPoint(x: balanceTextFrame.maxX + balanceIconSpacing, y: balanceTextFrame.minY + floor((balanceTextFrame.height - balanceIconSize.height) / 2.0)), size: balanceIconSize) + } transition.updateFrameAdditive(node: self.balanceTextNode, frame: balanceTextFrame) - transition.updateFrameAdditive(node: self.balanceIconNode, frame: balanceIconFrame) + transition.updateFrame(node: self.balanceIconNode, frame: balanceIconFrame) return balanceTextSize.height } @@ -245,10 +252,10 @@ private final class WalletInfoHeaderNode: ASDisplayNode { } } if self.balance == nil { - self.balanceNode.isHidden = true + self.balanceNode.balanceTextNode.isHidden = true self.balanceSubtitleNode.isHidden = true } else { - self.balanceNode.isHidden = false + self.balanceNode.balanceTextNode.isHidden = false self.balanceSubtitleNode.isHidden = false } transition.updateFrame(node: self.receiveButtonNode, frame: receiveButtonFrame) @@ -272,7 +279,8 @@ private final class WalletInfoHeaderNode: ASDisplayNode { func animateIn() { self.sendButtonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) self.receiveButtonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) - self.balanceNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + self.balanceNode.isLoading = false + self.balanceNode.balanceTextNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) self.balanceSubtitleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) } } @@ -366,6 +374,8 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { private var currentEntries: [WalletInfoListEntry]? + private var isReady: Bool = false + init(account: Account, tonContext: TonContext, presentationData: PresentationData, walletInfo: WalletInfo, address: String, sendAction: @escaping () -> Void, receiveAction: @escaping () -> Void, openTransaction: @escaping (WalletTransaction) -> Void) { self.account = account self.tonContext = tonContext @@ -379,24 +389,28 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { self.listNode = ListView() self.listNode.verticalScrollIndicatorColor = self.presentationData.theme.list.scrollIndicatorColor self.listNode.verticalScrollIndicatorFollowsOverscroll = true + self.listNode.isHidden = true super.init() self.backgroundColor = .white - self.balanceDisposable.set((currentWalletBalance(publicKey: walletInfo.publicKey, tonInstance: tonContext.instance) + self.balanceDisposable.set((getWalletState(address: address, tonInstance: tonContext.instance) |> deliverOnMainQueue).start(next: { [weak self] value in guard let strongSelf = self else { return } - let firstTime = strongSelf.headerNode.balance == nil - strongSelf.headerNode.balanceNode.balance = formatBalanceText(max(0, value.rawValue)) - strongSelf.headerNode.balance = max(0, value.rawValue) + strongSelf.headerNode.balanceNode.balance = formatBalanceText(max(0, value.balance)) + strongSelf.headerNode.balance = max(0, value.balance) + if let (layout, navigationHeight) = strongSelf.validLayout { strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate) } - if firstTime { - strongSelf.headerNode.animateIn() + + let wasReady = strongSelf.isReady + strongSelf.isReady = strongSelf.headerNode.balance != nil && strongSelf.currentEntries != nil + if strongSelf.isReady && !wasReady { + strongSelf.animateReadyIn() } })) @@ -410,7 +424,9 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { strongSelf.listOffset = offset - strongSelf.headerNode.update(size: strongSelf.headerNode.bounds.size, navigationHeight: navigationHeight, offset: offset, transition: listTransition) + if strongSelf.isReady { + strongSelf.headerNode.update(size: strongSelf.headerNode.bounds.size, navigationHeight: navigationHeight, offset: offset, transition: listTransition) + } } self.listNode.visibleBottomContentOffsetChanged = { [weak self] offset in @@ -464,11 +480,22 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { let headerHeight: CGFloat = navigationHeight + 260.0 let topInset: CGFloat = headerHeight - let headerFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: headerHeight)) - transition.updateFrame(node: self.headerNode, frame: headerFrame) - self.headerNode.update(size: headerFrame.size, navigationHeight: navigationHeight, offset: self.listOffset ?? 0.0, transition: transition) + let visualHeaderHeight: CGFloat + let visualHeaderOffset: CGFloat + if !self.isReady { + visualHeaderHeight = layout.size.height + visualHeaderOffset = visualHeaderHeight + } else { + visualHeaderHeight = headerHeight + visualHeaderOffset = self.listOffset ?? 0.0 + } + let visualListOffset = visualHeaderHeight - headerHeight - transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: layout.size)) + let headerFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: visualHeaderHeight)) + transition.updateFrame(node: self.headerNode, frame: headerFrame) + self.headerNode.update(size: headerFrame.size, navigationHeight: navigationHeight, offset: visualHeaderOffset, transition: transition) + + transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(x: 0.0, y: visualListOffset), size: layout.size)) var duration: Double = 0.0 var curve: UInt = 0 @@ -599,8 +626,11 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { self.enqueuedTransactions.append(transaction) self.dequeueTransaction() - if isFirst { - self.listNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + let wasReady = self.isReady + self.isReady = self.headerNode.balance != nil && self.currentEntries != nil + + if self.isReady && !wasReady { + self.animateReadyIn() } } @@ -619,6 +649,14 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode { self.listNode.transaction(deleteIndices: transaction.deletions, insertIndicesAndItems: transaction.insertions, updateIndicesAndItems: transaction.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { _ in }) } + + private func animateReadyIn() { + self.listNode.isHidden = false + self.headerNode.animateIn() + if let (layout, navigationHeight) = self.validLayout { + self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.5, curve: .spring)) + } + } } func formatBalanceText(_ value: Int64) -> String { diff --git a/submodules/WalletUI/Sources/WalletSendScreen.swift b/submodules/WalletUI/Sources/WalletSendScreen.swift index dc173c92fe..94ce5ee88e 100644 --- a/submodules/WalletUI/Sources/WalletSendScreen.swift +++ b/submodules/WalletUI/Sources/WalletSendScreen.swift @@ -355,7 +355,7 @@ func walletSendScreen(context: AccountContext, tonContext: TonContext, walletInf } }) - let balance: Signal = Signal.single(WalletBalance(rawValue: 2500)) + let balance: Signal = Signal.single(WalletState(balance: 2500, lastTransactionId: nil)) var focusItemTag: ItemListItemTag? if address == nil { @@ -373,14 +373,14 @@ func walletSendScreen(context: AccountContext, tonContext: TonContext, walletInf let amount = amountValue(state.amount) var sendEnabled = false if let balance = balance { - sendEnabled = isValidAddress(state.address, exactLength: true) && amount > 0 && amount <= balance.rawValue + sendEnabled = isValidAddress(state.address, exactLength: true) && amount > 0 && amount <= balance.balance } let rightNavigationButton = ItemListNavigationButton(content: .text("Send"), style: .bold, enabled: sendEnabled, action: { arguments.proceed() }) let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text("Send Grams"), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) - let listState = ItemListNodeState(entries: walletSendScreenEntries(presentationData: presentationData, balance: balance?.rawValue, state: state), style: .blocks, focusItemTag: focusItemTag, animateChanges: false) + let listState = ItemListNodeState(entries: walletSendScreenEntries(presentationData: presentationData, balance: balance?.balance, state: state), style: .blocks, focusItemTag: focusItemTag, animateChanges: false) return (controllerState, (listState, arguments)) } diff --git a/submodules/ton/tonlib-src/adnl/adnl-ext-client.cpp b/submodules/ton/tonlib-src/adnl/adnl-ext-client.cpp index efc71e6f27..d7a39d417e 100644 --- a/submodules/ton/tonlib-src/adnl/adnl-ext-client.cpp +++ b/submodules/ton/tonlib-src/adnl/adnl-ext-client.cpp @@ -176,6 +176,113 @@ td::Status AdnlOutboundConnection::process_packet(td::BufferSlice data) { return td::Status::OK(); } +void AdnlExtMultiClientImpl::start_up() { + for (auto &id : ids_) { + add_server(id.first, id.second, [](td::Result R) {}); + } + ids_.clear(); +} + +void AdnlExtMultiClientImpl::add_server(AdnlNodeIdFull dst, td::IPAddress dst_addr, td::Promise promise) { + for (auto &c : clients_) { + if (c.second->addr == dst_addr) { + promise.set_error(td::Status::Error(ErrorCode::error, "duplicate ip")); + return; + } + } + + auto g = ++generation_; + auto cli = std::make_unique(AdnlExtClient::create(dst, dst_addr, make_callback(g)), dst, dst_addr, g); + clients_[g] = std::move(cli); +} + +void AdnlExtMultiClientImpl::del_server(td::IPAddress dst_addr, td::Promise promise) { + for (auto &c : clients_) { + if (c.second->addr == dst_addr) { + if (c.second->ready) { + total_ready_--; + if (!total_ready_) { + callback_->on_stop_ready(); + } + } + clients_.erase(c.first); + promise.set_value(td::Unit()); + return; + } + } + promise.set_error(td::Status::Error(ErrorCode::error, "ip not found")); +} + +void AdnlExtMultiClientImpl::send_query(std::string name, td::BufferSlice data, td::Timestamp timeout, + td::Promise promise) { + if (total_ready_ == 0) { + promise.set_error(td::Status::Error(ErrorCode::notready, "conn not ready")); + return; + } + + std::vector vec; + for (auto &c : clients_) { + if (c.second->ready) { + vec.push_back(c.first); + } + } + CHECK(vec.size() == total_ready_); + + auto &c = clients_[vec[td::Random::fast(0, td::narrow_cast(vec.size() - 1))]]; + + td::actor::send_closure(c->client, &AdnlExtClient::send_query, std::move(name), std::move(data), timeout, + std::move(promise)); +} + +void AdnlExtMultiClientImpl::client_ready(td::uint32 idx, bool value) { + auto it = clients_.find(idx); + if (it == clients_.end()) { + return; + } + auto &c = it->second; + if (c->ready == value) { + return; + } + c->ready = value; + if (value) { + total_ready_++; + if (total_ready_ == 1) { + callback_->on_ready(); + } + } else { + total_ready_--; + if (total_ready_ == 0) { + callback_->on_stop_ready(); + } + } +} + +std::unique_ptr AdnlExtMultiClientImpl::make_callback(td::uint32 g) { + class Cb : public Callback { + public: + Cb(td::actor::ActorId id, td::uint32 idx) : id_(id), idx_(idx) { + } + + void on_ready() override { + td::actor::send_closure(id_, &AdnlExtMultiClientImpl::client_ready, idx_, true); + } + + void on_stop_ready() override { + td::actor::send_closure(id_, &AdnlExtMultiClientImpl::client_ready, idx_, false); + } + + private: + td::actor::ActorId id_; + td::uint32 idx_; + }; + return std::make_unique(actor_id(this), g); +} + +td::actor::ActorOwn AdnlExtMultiClient::create( + std::vector> ids, std::unique_ptr callback) { + return td::actor::create_actor("extmulticlient", std::move(ids), std::move(callback)); +} + } // namespace adnl } // namespace ton diff --git a/submodules/ton/tonlib-src/adnl/adnl-ext-client.h b/submodules/ton/tonlib-src/adnl/adnl-ext-client.h index babccced5e..bd60f202d6 100644 --- a/submodules/ton/tonlib-src/adnl/adnl-ext-client.h +++ b/submodules/ton/tonlib-src/adnl/adnl-ext-client.h @@ -43,6 +43,14 @@ class AdnlExtClient : public td::actor::Actor { std::unique_ptr callback); }; +class AdnlExtMultiClient : public AdnlExtClient { + public: + virtual void add_server(AdnlNodeIdFull dst, td::IPAddress dst_addr, td::Promise promise) = 0; + virtual void del_server(td::IPAddress dst_addr, td::Promise promise) = 0; + static td::actor::ActorOwn create(std::vector> ids, + std::unique_ptr callback); +}; + } // namespace adnl } // namespace ton diff --git a/submodules/ton/tonlib-src/adnl/adnl-ext-client.hpp b/submodules/ton/tonlib-src/adnl/adnl-ext-client.hpp index 95348135ca..d58247fcc4 100644 --- a/submodules/ton/tonlib-src/adnl/adnl-ext-client.hpp +++ b/submodules/ton/tonlib-src/adnl/adnl-ext-client.hpp @@ -140,6 +140,52 @@ class AdnlExtClientImpl : public AdnlExtClient { void try_stop(); }; +class AdnlExtMultiClientImpl : public AdnlExtMultiClient { + public: + AdnlExtMultiClientImpl(std::vector> ids, + std::unique_ptr callback) + : ids_(std::move(ids)), callback_(std::move(callback)) { + } + + void start_up() override; + + void add_server(AdnlNodeIdFull dst, td::IPAddress dst_addr, td::Promise promise) override; + void del_server(td::IPAddress dst_addr, td::Promise promise) override; + + void check_ready(td::Promise promise) override { + if (total_ready_ > 0) { + promise.set_value(td::Unit()); + } else { + promise.set_error(td::Status::Error(ErrorCode::notready, "conn not ready")); + } + } + void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout, + td::Promise promise) override; + + void client_ready(td::uint32 idx, bool value); + + private: + std::unique_ptr make_callback(td::uint32 g); + + struct Client { + Client(td::actor::ActorOwn client, AdnlNodeIdFull pubkey, td::IPAddress addr, td::uint32 generation) + : client(std::move(client)), pubkey(std::move(pubkey)), addr(addr), generation(generation), ready(false) { + } + td::actor::ActorOwn client; + AdnlNodeIdFull pubkey; + td::IPAddress addr; + td::uint32 generation; + bool ready = false; + }; + td::uint32 total_ready_ = 0; + + td::uint32 generation_ = 0; + std::map> clients_; + + std::vector> ids_; + std::unique_ptr callback_; +}; + } // namespace adnl } // namespace ton diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/Timer.cpp b/submodules/ton/tonlib-src/tdutils/td/utils/Timer.cpp index 27e5d985ce..dd2a3a618a 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/Timer.cpp +++ b/submodules/ton/tonlib-src/tdutils/td/utils/Timer.cpp @@ -25,15 +25,40 @@ namespace td { -Timer::Timer() : start_time_(Time::now()) { +Timer::Timer(bool is_paused) : is_paused_(is_paused) { + if (is_paused_) { + start_time_ = 0; + } else { + start_time_ = Time::now(); + } +} + +void Timer::pause() { + if (is_paused_) { + return; + } + elapsed_ += Time::now() - start_time_; + is_paused_ = true; +} + +void Timer::resume() { + if (!is_paused_) { + return; + } + start_time_ = Time::now(); + is_paused_ = false; } double Timer::elapsed() const { - return Time::now() - start_time_; + double res = elapsed_; + if (!is_paused_) { + res += Time::now() - start_time_; + } + return res; } StringBuilder &operator<<(StringBuilder &string_builder, const Timer &timer) { - return string_builder << "in " << Time::now() - timer.start_time_; + return string_builder << format::as_time(timer.elapsed()); } PerfWarningTimer::PerfWarningTimer(string name, double max_duration) diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/Timer.h b/submodules/ton/tonlib-src/tdutils/td/utils/Timer.h index 1b84b7daba..ed5afa7468 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/Timer.h +++ b/submodules/ton/tonlib-src/tdutils/td/utils/Timer.h @@ -24,14 +24,22 @@ namespace td { class Timer { public: - Timer(); + Timer() : Timer(false) { + } + explicit Timer(bool is_paused); + Timer(const Timer &other) = default; + Timer &operator=(const Timer &other) = default; double elapsed() const; + void pause(); + void resume(); private: friend StringBuilder &operator<<(StringBuilder &string_builder, const Timer &timer); + double elapsed_{0}; double start_time_; + bool is_paused_{false}; }; class PerfWarningTimer { diff --git a/submodules/ton/tonlib-src/tdutils/td/utils/filesystem.cpp b/submodules/ton/tonlib-src/tdutils/td/utils/filesystem.cpp index 9ee0cf615f..0d6a21a832 100644 --- a/submodules/ton/tonlib-src/tdutils/td/utils/filesystem.cpp +++ b/submodules/ton/tonlib-src/tdutils/td/utils/filesystem.cpp @@ -53,17 +53,20 @@ SecureString create_empty(size_t size) { template Result read_file_impl(CSlice path, int64 size, int64 offset) { TRY_RESULT(from_file, FileFd::open(path, FileFd::Read)); + TRY_RESULT(file_size, from_file.get_size()); + if (offset < 0 || offset > file_size) { + return Status::Error("Failed to read file: invalid offset"); + } if (size == -1) { - TRY_RESULT(file_size, from_file.get_size()); - size = file_size; + size = file_size - offset; + } else if (size >= 0) { + if (size + offset > file_size) { + size = file_size - offset; + } } if (size < 0) { return Status::Error("Failed to read file: invalid size"); } - if (offset < 0 || offset > size) { - return Status::Error("Failed to read file: invalid offset"); - } - size -= offset; auto content = create_empty(narrow_cast(size)); TRY_RESULT(got_size, from_file.pread(as_mutable_slice(content), offset)); if (got_size != static_cast(size)) { diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp index 8d4a3f1c23..bfbdee4ed8 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.cpp @@ -7643,21 +7643,21 @@ engine_validator_config::engine_validator_config() , dht_() , validators_() , fullnode_() - , fullnodeslave_() + , fullnodeslaves_() , fullnodemasters_() , liteservers_() , control_() , gc_() {} -engine_validator_config::engine_validator_config(std::int32_t out_port_, std::vector> &&addrs_, std::vector> &&adnl_, std::vector> &&dht_, std::vector> &&validators_, td::Bits256 const &fullnode_, object_ptr &&fullnodeslave_, std::vector> &&fullnodemasters_, std::vector> &&liteservers_, std::vector> &&control_, object_ptr &&gc_) +engine_validator_config::engine_validator_config(std::int32_t out_port_, std::vector> &&addrs_, std::vector> &&adnl_, std::vector> &&dht_, std::vector> &&validators_, td::Bits256 const &fullnode_, std::vector> &&fullnodeslaves_, std::vector> &&fullnodemasters_, std::vector> &&liteservers_, std::vector> &&control_, object_ptr &&gc_) : out_port_(out_port_) , addrs_(std::move(addrs_)) , adnl_(std::move(adnl_)) , dht_(std::move(dht_)) , validators_(std::move(validators_)) , fullnode_(fullnode_) - , fullnodeslave_(std::move(fullnodeslave_)) + , fullnodeslaves_(std::move(fullnodeslaves_)) , fullnodemasters_(std::move(fullnodemasters_)) , liteservers_(std::move(liteservers_)) , control_(std::move(control_)) @@ -7678,7 +7678,7 @@ engine_validator_config::engine_validator_config(td::TlParser &p) , dht_(TlFetchVector>::parse(p)) , validators_(TlFetchVector>::parse(p)) , fullnode_(TlFetchInt256::parse(p)) - , fullnodeslave_(TlFetchObject::parse(p)) + , fullnodeslaves_(TlFetchVector>::parse(p)) , fullnodemasters_(TlFetchVector>::parse(p)) , liteservers_(TlFetchVector>::parse(p)) , control_(TlFetchVector>::parse(p)) @@ -7694,7 +7694,7 @@ void engine_validator_config::store(td::TlStorerCalcLength &s) const { TlStoreVector::store(dht_, s); TlStoreVector::store(validators_, s); TlStoreBinary::store(fullnode_, s); - TlStoreObject::store(fullnodeslave_, s); + TlStoreVector::store(fullnodeslaves_, s); TlStoreVector::store(fullnodemasters_, s); TlStoreVector::store(liteservers_, s); TlStoreVector::store(control_, s); @@ -7709,7 +7709,7 @@ void engine_validator_config::store(td::TlStorerUnsafe &s) const { TlStoreVector::store(dht_, s); TlStoreVector::store(validators_, s); TlStoreBinary::store(fullnode_, s); - TlStoreObject::store(fullnodeslave_, s); + TlStoreVector::store(fullnodeslaves_, s); TlStoreVector::store(fullnodemasters_, s); TlStoreVector::store(liteservers_, s); TlStoreVector::store(control_, s); @@ -7725,7 +7725,7 @@ void engine_validator_config::store(td::TlStorerToString &s, const char *field_n { const std::vector> &v = dht_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("dht", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } { const std::vector> &v = validators_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("validators", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } s.store_field("fullnode", fullnode_); - if (fullnodeslave_ == nullptr) { s.store_field("fullnodeslave", "null"); } else { fullnodeslave_->store(s, "fullnodeslave"); } + { const std::vector> &v = fullnodeslaves_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("fullnodeslaves", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } { const std::vector> &v = fullnodemasters_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("fullnodemasters", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } { const std::vector> &v = liteservers_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("liteservers", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } { const std::vector> &v = control_; const std::uint32_t multiplicity = static_cast(v.size()); const auto vector_name = "vector[" + td::to_string(multiplicity)+ "]"; s.store_class_begin("control", vector_name.c_str()); for (std::uint32_t i = 0; i < multiplicity; i++) { if (v[i] == nullptr) { s.store_field("", "null"); } else { v[i]->store(s, ""); } } s.store_class_end(); } diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h index 3387d77f77..41eec24536 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api.h @@ -4214,7 +4214,7 @@ class engine_validator_config final : public Object { std::vector> dht_; std::vector> validators_; td::Bits256 fullnode_; - object_ptr fullnodeslave_; + std::vector> fullnodeslaves_; std::vector> fullnodemasters_; std::vector> liteservers_; std::vector> control_; @@ -4222,9 +4222,9 @@ class engine_validator_config final : public Object { engine_validator_config(); - engine_validator_config(std::int32_t out_port_, std::vector> &&addrs_, std::vector> &&adnl_, std::vector> &&dht_, std::vector> &&validators_, td::Bits256 const &fullnode_, object_ptr &&fullnodeslave_, std::vector> &&fullnodemasters_, std::vector> &&liteservers_, std::vector> &&control_, object_ptr &&gc_); + engine_validator_config(std::int32_t out_port_, std::vector> &&addrs_, std::vector> &&adnl_, std::vector> &&dht_, std::vector> &&validators_, td::Bits256 const &fullnode_, std::vector> &&fullnodeslaves_, std::vector> &&fullnodemasters_, std::vector> &&liteservers_, std::vector> &&control_, object_ptr &&gc_); - static const std::int32_t ID = 17126390; + static const std::int32_t ID = -826140252; std::int32_t get_id() const final { return ID; } diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp index 58e145707d..d08d906c9d 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/ton_api_json.cpp @@ -625,7 +625,7 @@ Result tl_constructor_from_string(ton_api::Object *object, const std::str {"engine.adnlProxy.config", 1848000769}, {"engine.adnlProxy.port", -117344950}, {"engine.dht.config", -197295930}, - {"engine.validator.config", 17126390}, + {"engine.validator.config", -826140252}, {"engine.validator.controlQueryError", 1999018527}, {"engine.validator.dhtServerStatus", -1323440290}, {"engine.validator.dhtServersStatus", 725155112}, @@ -3099,9 +3099,9 @@ Status from_json(ton_api::engine_validator_config &to, JsonObject &from) { } } { - TRY_RESULT(value, get_json_object_field(from, "fullnodeslave", JsonValue::Type::Null, true)); + TRY_RESULT(value, get_json_object_field(from, "fullnodeslaves", JsonValue::Type::Null, true)); if (value.type() != JsonValue::Type::Null) { - TRY_STATUS(from_json(to.fullnodeslave_, value)); + TRY_STATUS(from_json(to.fullnodeslaves_, value)); } } { @@ -6711,9 +6711,7 @@ void to_json(JsonValueScope &jv, const ton_api::engine_validator_config &object) jo << ctie("dht", ToJson(object.dht_)); jo << ctie("validators", ToJson(object.validators_)); jo << ctie("fullnode", ToJson(object.fullnode_)); - if (object.fullnodeslave_) { - jo << ctie("fullnodeslave", ToJson(object.fullnodeslave_)); - } + jo << ctie("fullnodeslaves", ToJson(object.fullnodeslaves_)); jo << ctie("fullnodemasters", ToJson(object.fullnodemasters_)); jo << ctie("liteservers", ToJson(object.liteservers_)); jo << ctie("control", ToJson(object.control_)); diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp index 8deb110d68..0a6d3b95d8 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.cpp @@ -413,12 +413,14 @@ raw_message::raw_message() : source_() , destination_() , value_() + , message_() {} -raw_message::raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_) +raw_message::raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::string const &message_) : source_(std::move(source_)) , destination_(std::move(destination_)) , value_(value_) + , message_(std::move(message_)) {} const std::int32_t raw_message::ID; @@ -429,6 +431,7 @@ void raw_message::store(td::TlStorerToString &s, const char *field_name) const { s.store_field("source", source_); s.store_field("destination", destination_); s.store_field("value", value_); + s.store_bytes_field("message", message_); s.store_class_end(); } } @@ -741,13 +744,15 @@ generic_sendGrams::generic_sendGrams() , source_() , destination_() , amount_() + , message_() {} -generic_sendGrams::generic_sendGrams(object_ptr &&private_key_, object_ptr &&source_, object_ptr &&destination_, std::int64_t amount_) +generic_sendGrams::generic_sendGrams(object_ptr &&private_key_, object_ptr &&source_, object_ptr &&destination_, std::int64_t amount_, std::string const &message_) : private_key_(std::move(private_key_)) , source_(std::move(source_)) , destination_(std::move(destination_)) , amount_(amount_) + , message_(std::move(message_)) {} const std::int32_t generic_sendGrams::ID; @@ -759,6 +764,7 @@ void generic_sendGrams::store(td::TlStorerToString &s, const char *field_name) c if (source_ == nullptr) { s.store_field("source", "null"); } else { source_->store(s, "source"); } if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); } s.store_field("amount", amount_); + s.store_bytes_field("message", message_); s.store_class_end(); } } @@ -1058,12 +1064,14 @@ testGiver_sendGrams::testGiver_sendGrams() : destination_() , seqno_() , amount_() + , message_() {} -testGiver_sendGrams::testGiver_sendGrams(object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_) +testGiver_sendGrams::testGiver_sendGrams(object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_, std::string const &message_) : destination_(std::move(destination_)) , seqno_(seqno_) , amount_(amount_) + , message_(std::move(message_)) {} const std::int32_t testGiver_sendGrams::ID; @@ -1074,6 +1082,7 @@ void testGiver_sendGrams::store(td::TlStorerToString &s, const char *field_name) if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); } s.store_field("seqno", seqno_); s.store_field("amount", amount_); + s.store_bytes_field("message", message_); s.store_class_end(); } } @@ -1137,13 +1146,15 @@ testWallet_sendGrams::testWallet_sendGrams() , destination_() , seqno_() , amount_() + , message_() {} -testWallet_sendGrams::testWallet_sendGrams(object_ptr &&private_key_, object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_) +testWallet_sendGrams::testWallet_sendGrams(object_ptr &&private_key_, object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_, std::string const &message_) : private_key_(std::move(private_key_)) , destination_(std::move(destination_)) , seqno_(seqno_) , amount_(amount_) + , message_(std::move(message_)) {} const std::int32_t testWallet_sendGrams::ID; @@ -1155,6 +1166,7 @@ void testWallet_sendGrams::store(td::TlStorerToString &s, const char *field_name if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); } s.store_field("seqno", seqno_); s.store_field("amount", amount_); + s.store_bytes_field("message", message_); s.store_class_end(); } } diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h index bbca471746..36277cd3a0 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api.h @@ -442,12 +442,13 @@ class raw_message final : public Object { std::string source_; std::string destination_; std::int64_t value_; + std::string message_; raw_message(); - raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_); + raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::string const &message_); - static const std::int32_t ID = -1131081640; + static const std::int32_t ID = -259956097; std::int32_t get_id() const final { return ID; } @@ -717,12 +718,13 @@ class generic_sendGrams final : public Function { object_ptr source_; object_ptr destination_; std::int64_t amount_; + std::string message_; generic_sendGrams(); - generic_sendGrams(object_ptr &&private_key_, object_ptr &&source_, object_ptr &&destination_, std::int64_t amount_); + generic_sendGrams(object_ptr &&private_key_, object_ptr &&source_, object_ptr &&destination_, std::int64_t amount_, std::string const &message_); - static const std::int32_t ID = 799772985; + static const std::int32_t ID = 1523427648; std::int32_t get_id() const final { return ID; } @@ -1012,12 +1014,13 @@ class testGiver_sendGrams final : public Function { object_ptr destination_; std::int32_t seqno_; std::int64_t amount_; + std::string message_; testGiver_sendGrams(); - testGiver_sendGrams(object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_); + testGiver_sendGrams(object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_, std::string const &message_); - static const std::int32_t ID = -178493799; + static const std::int32_t ID = -1361914347; std::int32_t get_id() const final { return ID; } @@ -1087,12 +1090,13 @@ class testWallet_sendGrams final : public Function { object_ptr destination_; std::int32_t seqno_; std::int64_t amount_; + std::string message_; testWallet_sendGrams(); - testWallet_sendGrams(object_ptr &&private_key_, object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_); + testWallet_sendGrams(object_ptr &&private_key_, object_ptr &&destination_, std::int32_t seqno_, std::int64_t amount_, std::string const &message_); - static const std::int32_t ID = -1716705044; + static const std::int32_t ID = 43200674; std::int32_t get_id() const final { return ID; } diff --git a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp index 1b35ee3e61..3c1402d996 100644 --- a/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp +++ b/submodules/ton/tonlib-src/tl/generate/auto/tl/tonlib_api_json.cpp @@ -60,7 +60,7 @@ Result tl_constructor_from_string(tonlib_api::Object *object, const std:: {"internal.transactionId", -989527262}, {"raw.accountState", 461615898}, {"raw.initialAccountState", 777456197}, - {"raw.message", -1131081640}, + {"raw.message", -259956097}, {"raw.transaction", -1159530820}, {"raw.transactions", 240548986}, {"testGiver.accountState", 860930426}, @@ -84,7 +84,7 @@ Result tl_constructor_from_string(tonlib_api::Function *object, const std {"exportKey", 399723440}, {"exportPemKey", -2047752448}, {"generic.getAccountState", -657000446}, - {"generic.sendGrams", 799772985}, + {"generic.sendGrams", 1523427648}, {"getBip39Hints", -1889640982}, {"importEncryptedKey", 656724958}, {"importKey", -1607900903}, @@ -100,11 +100,11 @@ Result tl_constructor_from_string(tonlib_api::Function *object, const std {"runTests", -2039925427}, {"testGiver.getAccountAddress", -540100768}, {"testGiver.getAccountState", 267738275}, - {"testGiver.sendGrams", -178493799}, + {"testGiver.sendGrams", -1361914347}, {"testWallet.getAccountAddress", -1557748223}, {"testWallet.getAccountState", 654082364}, {"testWallet.init", 419055225}, - {"testWallet.sendGrams", -1716705044} + {"testWallet.sendGrams", 43200674} }; auto it = m.find(str); if (it == m.end()) { @@ -377,6 +377,12 @@ Status from_json(tonlib_api::raw_message &to, JsonObject &from) { TRY_STATUS(from_json(to.value_, value)); } } + { + TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.message_, value)); + } + } return Status::OK(); } Status from_json(tonlib_api::raw_transaction &to, JsonObject &from) { @@ -638,6 +644,12 @@ Status from_json(tonlib_api::generic_sendGrams &to, JsonObject &from) { TRY_STATUS(from_json(to.amount_, value)); } } + { + TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.message_, value)); + } + } return Status::OK(); } Status from_json(tonlib_api::getBip39Hints &to, JsonObject &from) { @@ -848,6 +860,12 @@ Status from_json(tonlib_api::testGiver_sendGrams &to, JsonObject &from) { TRY_STATUS(from_json(to.amount_, value)); } } + { + TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.message_, value)); + } + } return Status::OK(); } Status from_json(tonlib_api::testWallet_getAccountAddress &to, JsonObject &from) { @@ -902,6 +920,12 @@ Status from_json(tonlib_api::testWallet_sendGrams &to, JsonObject &from) { TRY_STATUS(from_json(to.amount_, value)); } } + { + TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true)); + if (value.type() != JsonValue::Type::Null) { + TRY_STATUS(from_json_bytes(to.message_, value)); + } + } return Status::OK(); } void to_json(JsonValueScope &jv, const tonlib_api::accountAddress &object) { @@ -1043,6 +1067,7 @@ void to_json(JsonValueScope &jv, const tonlib_api::raw_message &object) { jo << ctie("source", ToJson(object.source_)); jo << ctie("destination", ToJson(object.destination_)); jo << ctie("value", ToJson(JsonInt64{object.value_})); + jo << ctie("message", ToJson(JsonBytes{object.message_})); } void to_json(JsonValueScope &jv, const tonlib_api::raw_transaction &object) { auto jo = jv.enter_object(); @@ -1167,6 +1192,7 @@ void to_json(JsonValueScope &jv, const tonlib_api::generic_sendGrams &object) { jo << ctie("destination", ToJson(object.destination_)); } jo << ctie("amount", ToJson(JsonInt64{object.amount_})); + jo << ctie("message", ToJson(JsonBytes{object.message_})); } void to_json(JsonValueScope &jv, const tonlib_api::getBip39Hints &object) { auto jo = jv.enter_object(); @@ -1280,6 +1306,7 @@ void to_json(JsonValueScope &jv, const tonlib_api::testGiver_sendGrams &object) } jo << ctie("seqno", ToJson(object.seqno_)); jo << ctie("amount", ToJson(JsonInt64{object.amount_})); + jo << ctie("message", ToJson(JsonBytes{object.message_})); } void to_json(JsonValueScope &jv, const tonlib_api::testWallet_getAccountAddress &object) { auto jo = jv.enter_object(); @@ -1313,6 +1340,7 @@ void to_json(JsonValueScope &jv, const tonlib_api::testWallet_sendGrams &object) } jo << ctie("seqno", ToJson(object.seqno_)); jo << ctie("amount", ToJson(JsonInt64{object.amount_})); + jo << ctie("message", ToJson(JsonBytes{object.message_})); } } // namespace tonlib_api } // namespace ton diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl b/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl index 073595ce56..860ffd5d37 100644 --- a/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl +++ b/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tl @@ -490,7 +490,7 @@ engine.validator.fullNodeMaster port:int adnl:int256 = engine.validator.FullNode engine.validator.fullNodeSlave ip:int port:int adnl:PublicKey = engine.validator.FullNodeSlave; engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector engine.adnl) dht:(vector engine.dht) - validators:(vector engine.validator) fullnode:int256 fullnodeslave:engine.validator.fullNodeSlave + validators:(vector engine.validator) fullnode:int256 fullnodeslaves:(vector engine.validator.fullNodeSlave) fullnodemasters:(vector engine.validator.fullNodeMaster) liteservers:(vector engine.liteServer) control:(vector engine.controlInterface) gc:engine.gc = engine.validator.Config; diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tlo b/submodules/ton/tonlib-src/tl/generate/scheme/ton_api.tlo index 00dc97c4e01c909e9d9d044767f1066cac991239..7ad04d37e5870c32a76bf471285bb183653b8505 100644 GIT binary patch delta 82 zcmcaGnfb|N<_#u-EK4L0o!e|7=n%&WVu?>aSSZ4imYELX+&m`a!##Q7F73%D^1tx% frIqI74z88=%9I>dollWX!NAVM?pRTxEh(@Jx4^72zsi*pjoQW?Nt O@{@u)5G6+n6(Rthvl!_B diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl b/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl index 9535f056fc..356f263c2d 100644 --- a/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl +++ b/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tl @@ -32,7 +32,7 @@ internal.transactionId lt:int64 hash:bytes = internal.TransactionId; raw.initialAccountState code:bytes data:bytes = raw.InitialAccountState; raw.accountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId sync_utime:int53 = raw.AccountState; -raw.message source:string destination:string value:int64 = raw.Message; +raw.message source:string destination:string value:int64 message:bytes = raw.Message; raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 in_msg:raw.message out_msgs:vector = raw.Transaction; raw.transactions transactions:vector previous_transaction_id:internal.transactionId = raw.Transactions; @@ -81,15 +81,15 @@ raw.getTransactions account_address:accountAddress from_transaction_id:internal. testWallet.init private_key:inputKey = Ok; testWallet.getAccountAddress initital_account_state:testWallet.initialAccountState = AccountAddress; testWallet.getAccountState account_address:accountAddress = testWallet.AccountState; -testWallet.sendGrams private_key:inputKey destination:accountAddress seqno:int32 amount:int64 = Ok; +testWallet.sendGrams private_key:inputKey destination:accountAddress seqno:int32 amount:int64 message:bytes = Ok; testGiver.getAccountState = testGiver.AccountState; testGiver.getAccountAddress = AccountAddress; -testGiver.sendGrams destination:accountAddress seqno:int32 amount:int64 = Ok; +testGiver.sendGrams destination:accountAddress seqno:int32 amount:int64 message:bytes = Ok; //generic.getAccountAddress initital_account_state:generic.InitialAccountState = AccountAddress; generic.getAccountState account_address:accountAddress = generic.AccountState; -generic.sendGrams private_key:inputKey source:accountAddress destination:accountAddress amount:int64 = Ok; +generic.sendGrams private_key:inputKey source:accountAddress destination:accountAddress amount:int64 message:bytes = Ok; onLiteServerQueryResult id:int64 bytes:bytes = Ok; onLiteServerQueryError id:int64 error:error = Ok; diff --git a/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tlo b/submodules/ton/tonlib-src/tl/generate/scheme/tonlib_api.tlo index 7d87ccac80f8c60377aeecb6efe0bc2109fd84ef..40a4ccdce44ce004914d6b93a3f7b4c6155e02a7 100644 GIT binary patch delta 193 zcmX@(dB$r)0}D%iQsalsEi5Lyk{}j$QDV7XZfbFHVtOiwfAg4-56k3>g6WeDcvvQ{ zU>BIIAs_ysL2^pGK{Q~byc({Z;(nr);ifhUSP3? uG&_svwM*+J>nO=EvP=$CK`|YqWb+9n2S%1f29ud4^Qb6*jp{}-h6ezk?>}Jx delta 153 zcmX@(b;ff;0}D%pz|=jPTUbnZB|$9iqQr8&+|=UY#Pn1U|K>3vALhvy1=D$ooY{0Z zY}*ckL?@>R9RX{ctRrj!F(E}*ft|&2;%fcL9a1ukER%axv?pJXN|>A>FR?g7nw@24 oTFlqUIZ85&%#$~&q=SSvYbZM~vb@n)J9Bc5iUL?mH&9#z0H#1SUjP6A diff --git a/submodules/ton/tonlib-src/tonlib/CMakeLists.txt b/submodules/ton/tonlib-src/tonlib/CMakeLists.txt index 6c2f11a423..9b9b81da08 100644 --- a/submodules/ton/tonlib-src/tonlib/CMakeLists.txt +++ b/submodules/ton/tonlib-src/tonlib/CMakeLists.txt @@ -13,6 +13,7 @@ set(TONLIB_SOURCE tonlib/GenericAccount.cpp tonlib/KeyStorage.cpp tonlib/LastBlock.cpp + tonlib/LastBlockStorage.cpp tonlib/TestGiver.cpp tonlib/TestWallet.cpp tonlib/TonlibClient.cpp @@ -26,6 +27,7 @@ set(TONLIB_SOURCE tonlib/GenericAccount.h tonlib/KeyStorage.h tonlib/LastBlock.h + tonlib/LastBlockStorage.h tonlib/TestGiver.h tonlib/TestWallet.h tonlib/TonlibCallback.h diff --git a/submodules/ton/tonlib-src/tonlib/test/.online.cpp.swp b/submodules/ton/tonlib-src/tonlib/test/.online.cpp.swp deleted file mode 100644 index f03547aa930ae6896420d7fd927d7dccdeaaf1c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24576 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 diff --git a/submodules/ton/tonlib-src/tonlib/test/offline.cpp b/submodules/ton/tonlib-src/tonlib/test/offline.cpp index d5d86dba24..e009adf7c7 100644 --- a/submodules/ton/tonlib-src/tonlib/test/offline.cpp +++ b/submodules/ton/tonlib-src/tonlib/test/offline.cpp @@ -127,8 +127,8 @@ TEST(Tonlib, TestGiver) { auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data; - auto res = GenericAccount::create_ext_message(TestGiver::address(), {}, - TestGiver::make_a_gift_message(0, 1000000000ll * 6666 / 1000, address)); + auto res = GenericAccount::create_ext_message( + TestGiver::address(), {}, TestGiver::make_a_gift_message(0, 1000000000ll * 6666 / 1000, "GIFT", address)); vm::CellSlice(vm::NoVm(), res).print_rec(std::cerr); CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == res->get_hash()); } diff --git a/submodules/ton/tonlib-src/tonlib/test/online.cpp b/submodules/ton/tonlib-src/tonlib/test/online.cpp index 8f5a73e9a0..716f9153bc 100644 --- a/submodules/ton/tonlib-src/tonlib/test/online.cpp +++ b/submodules/ton/tonlib-src/tonlib/test/online.cpp @@ -118,7 +118,7 @@ void transfer_grams(Client& client, std::string from, std::string to, td::int64 auto balance = get_balance(client, to); sync_send(client, tonlib_api::make_object( std::move(input_key), tonlib_api::make_object(from), - tonlib_api::make_object(to), amount)) + tonlib_api::make_object(to), amount, "GIFT")) .ensure(); while (balance == get_balance(client, to)) { client.receive(1); @@ -270,7 +270,7 @@ int main(int argc, char* argv[]) { { sync_send(client, make_object( make_object(wallet_addr.rserialize()), seqno, - 1000000000ll * 6666 / 1000)) + 1000000000ll * 6666 / 1000, "GIFT")) .ensure(); } @@ -307,9 +307,10 @@ int main(int argc, char* argv[]) { } { - sync_send(client, make_object( - create_input_key(), make_object(wallet_addr.rserialize()), - make_object(test_giver_address), 1000000000ll * 3333 / 1000)) + sync_send(client, + make_object( + create_input_key(), make_object(wallet_addr.rserialize()), + make_object(test_giver_address), 1000000000ll * 3333 / 1000, "GIFT")) .ensure(); } while (true) { diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/BlockchainInfoStorage.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/BlockchainInfoStorage.cpp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/BlockchainInfoStorage.h b/submodules/ton/tonlib-src/tonlib/tonlib/BlockchainInfoStorage.h deleted file mode 100644 index 4a249cffa2..0000000000 --- a/submodules/ton/tonlib-src/tonlib/tonlib/BlockchainInfoStorage.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "tonlib/LastBlock.h" - -namespace tonlib { -class BlockchainInfoStorage { - td::Status set_directory(std::string directory); - td::Result get_state(ZeroStateIdExt); - void save_state(LastBlock::State state); -}; -} // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.cpp index 5633363dab..0ec942ed90 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.cpp @@ -21,10 +21,10 @@ #include "tonlib/LastBlock.h" namespace tonlib { -void ExtClient::with_last_block(td::Promise promise) { +void ExtClient::with_last_block(td::Promise promise) { auto query_id = last_block_queries_.create(std::move(promise)); - td::Promise P = [query_id, self = this, - actor_id = td::actor::actor_id()](td::Result result) { + td::Promise P = [query_id, self = this, + actor_id = td::actor::actor_id()](td::Result result) { send_lambda(actor_id, [self, query_id, result = std::move(result)]() mutable { self->last_block_queries_.extract(query_id).set_result(std::move(result)); }); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.h b/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.h index 8f92ea9e1b..dca5cdfdd4 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/ExtClient.h @@ -29,7 +29,7 @@ namespace tonlib { class LastBlock; -struct LastBlockInfo; +struct LastBlockState; struct ExtClientRef { td::actor::ActorId andl_ext_client_; td::actor::ActorId last_block_actor_; @@ -50,7 +50,7 @@ class ExtClient { return client_; } - void with_last_block(td::Promise promise); + void with_last_block(td::Promise promise); template void send_query(QueryT query, td::Promise promise) { @@ -75,7 +75,7 @@ class ExtClient { private: ExtClientRef client_; td::Container> queries_; - td::Container> last_block_queries_; + td::Container> last_block_queries_; void send_raw_query(td::BufferSlice query, td::Promise promise); }; diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.cpp index ca02099400..330393c0e7 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/GenericAccount.cpp @@ -28,7 +28,7 @@ td::Ref GenericAccount::get_init_state(td::Ref code, td::Ref .finalize(); } block::StdAddress GenericAccount::get_address(ton::WorkchainId workchain_id, const td::Ref& init_state) { - return block::StdAddress(workchain_id, init_state->get_hash().bits()); + return block::StdAddress(workchain_id, init_state->get_hash().bits(), false); } td::Ref GenericAccount::create_ext_message(const block::StdAddress& address, td::Ref new_state, td::Ref body) { diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.cpp index f4754023c9..3593adc5ec 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.cpp @@ -23,13 +23,23 @@ #include "lite-client/lite-client-common.h" namespace tonlib { -LastBlock::LastBlock(ExtClientRef client, State state, td::unique_ptr callback) + +td::StringBuilder& operator<<(td::StringBuilder& sb, const LastBlockState& state) { + return sb << td::tag("last_block", state.last_block_id.to_str()) + << td::tag("last_key_block", state.last_key_block_id.to_str()) << td::tag("utime", state.utime); +} + +LastBlock::LastBlock(ExtClientRef client, LastBlockState state, td::unique_ptr callback) : state_(std::move(state)), callback_(std::move(callback)) { client_.set_client(client); } -void LastBlock::get_last_block(td::Promise promise) { +void LastBlock::get_last_block(td::Promise promise) { if (promises_.empty()) { + total_sync_ = td::Timer(); + validate_ = td::Timer(true); + queries_ = 0; + LOG(INFO) << "Begin last block synchronization " << state_; do_get_last_block(); } promises_.push_back(std::move(promise)); @@ -41,6 +51,7 @@ void LastBlock::do_get_last_block() { //return; //liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof; + queries_++; client_.send_query( ton::lite_api::liteServer_getBlockProof(0, create_tl_lite_block_id(state_.last_key_block_id), nullptr), [this, from = state_.last_key_block_id](auto r_block_proof) { @@ -51,21 +62,30 @@ void LastBlock::do_get_last_block() { td::Result LastBlock::process_block_proof( ton::BlockIdExt from, td::Result> r_block_proof) { + validate_.resume(); + SCOPE_EXIT { + validate_.pause(); + }; + TRY_RESULT(block_proof, std::move(r_block_proof)); - LOG(ERROR) << to_string(block_proof); + LOG(DEBUG) << "Got proof FROM\n" << to_string(block_proof->from_) << "TO\n" << to_string(block_proof->to_); TRY_RESULT(chain, liteclient::deserialize_proof_chain(std::move(block_proof))); if (chain->from != from) { return td::Status::Error(PSLICE() << "block proof chain starts from block " << chain->from.to_str() << ", not from requested block " << from.to_str()); } TRY_STATUS(chain->validate()); - update_mc_last_block(chain->to); + bool is_changed = false; + is_changed |= update_mc_last_block(chain->to); if (chain->has_key_block) { - update_mc_last_key_block(chain->key_blkid); + is_changed |= update_mc_last_key_block(chain->key_blkid); } if (chain->has_utime) { update_utime(chain->last_utime); } + if (is_changed) { + callback_->on_state_changed(state_); + } return chain->complete; } @@ -73,17 +93,20 @@ void LastBlock::on_block_proof( ton::BlockIdExt from, td::Result> r_block_proof) { auto r_is_ready = process_block_proof(from, std::move(r_block_proof)); + bool is_ready; if (r_is_ready.is_error()) { - LOG(WARNING) << "Failed liteServer_getBlockProof " << r_is_ready.error(); - return; + LOG(WARNING) << "Error during last block synchronization " << r_is_ready.error(); + is_ready = true; + } else { + is_ready = r_is_ready.move_as_ok(); } - auto is_ready = r_is_ready.move_as_ok(); if (is_ready) { + LOG(INFO) << "End last block synchronization " << state_ << "\n" + << " net queries: " << queries_ << "\n" + << " total: " << total_sync_ << " validation: " << validate_; for (auto& promise : promises_) { - LastBlockInfo res; - res.id = state_.last_block_id; - res.utime = state_.utime; - promise.set_value(std::move(res)); + auto state = state_; + promise.set_value(std::move(state)); } promises_.clear(); } else { @@ -101,10 +124,8 @@ void LastBlock::on_masterchain_info( LOG(WARNING) << "Failed liteServer_getMasterchainInfo " << r_info.error(); } for (auto& promise : promises_) { - LastBlockInfo res; - res.id = state_.last_block_id; - res.utime = state_.utime; - promise.set_value(std::move(res)); + auto state = state_; + promise.set_value(std::move(state)); } promises_.clear(); } @@ -131,25 +152,30 @@ void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id) { // One will have to restart ton client } -void LastBlock::update_mc_last_block(ton::BlockIdExt mc_block_id) { +bool LastBlock::update_mc_last_block(ton::BlockIdExt mc_block_id) { if (!mc_block_id.is_valid()) { LOG(ERROR) << "Ignore invalid masterchain block"; - return; + return false; } if (!state_.last_block_id.is_valid() || state_.last_block_id.id.seqno < mc_block_id.id.seqno) { state_.last_block_id = mc_block_id; LOG(INFO) << "Update masterchain block id: " << state_.last_block_id.to_str(); + return true; } + return false; } -void LastBlock::update_mc_last_key_block(ton::BlockIdExt mc_key_block_id) { + +bool LastBlock::update_mc_last_key_block(ton::BlockIdExt mc_key_block_id) { if (!mc_key_block_id.is_valid()) { LOG(ERROR) << "Ignore invalid masterchain block"; - return; + return false; } if (!state_.last_key_block_id.is_valid() || state_.last_key_block_id.id.seqno < mc_key_block_id.id.seqno) { state_.last_key_block_id = mc_key_block_id; LOG(INFO) << "Update masterchain key block id: " << state_.last_key_block_id.to_str(); + return true; } + return false; } void LastBlock::update_utime(td::int64 utime) { diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.h b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.h index 968f21bddb..bb250d749e 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlock.h @@ -22,35 +22,114 @@ #include "tonlib/ExtClient.h" namespace tonlib { -struct LastBlockInfo { - ton::BlockIdExt id; +td::StringBuilder &operator<<(td::StringBuilder &sb, const LastBlockState &state); +template +void store(const td::BitArray &arr, StorerT &storer) { + storer.store_binary(arr); +} +template +void parse(td::BitArray &arr, ParserT &parser) { + arr = parser.template fetch_binary>(); +} + +template +void store(const ton::ZeroStateIdExt &zero_state_id, StorerT &storer) { + using td::store; + using tonlib::store; + store(zero_state_id.workchain, storer); + store(zero_state_id.root_hash, storer); + store(zero_state_id.file_hash, storer); +} +template +void parse(ton::ZeroStateIdExt &zero_state_id, ParserT &parser) { + using td::parse; + using tonlib::parse; + parse(zero_state_id.workchain, parser); + parse(zero_state_id.root_hash, parser); + parse(zero_state_id.file_hash, parser); +} +template +void store(const ton::BlockId &block_id, StorerT &storer) { + using td::store; + using tonlib::store; + store(block_id.workchain, storer); + store(block_id.shard, storer); + store(block_id.seqno, storer); +} +template +void parse(ton::BlockId &block_id, ParserT &parser) { + using td::parse; + using tonlib::parse; + parse(block_id.workchain, parser); + parse(block_id.shard, parser); + parse(block_id.seqno, parser); +} +template +void store(const ton::BlockIdExt &block_id, StorerT &storer) { + using td::store; + using tonlib::store; + store(block_id.id, storer); + store(block_id.root_hash, storer); + store(block_id.file_hash, storer); +} +template +void parse(ton::BlockIdExt &block_id, ParserT &parser) { + using td::parse; + using tonlib::parse; + parse(block_id.id, parser); + parse(block_id.root_hash, parser); + parse(block_id.file_hash, parser); +} +struct LastBlockState { + ton::ZeroStateIdExt zero_state_id; + ton::BlockIdExt last_key_block_id; + ton::BlockIdExt last_block_id; td::int64 utime{0}; + + template + void store(StorerT &storer) const { + using td::store; + using tonlib::store; + store(zero_state_id, storer); + store(last_key_block_id, storer); + store(last_block_id, storer); + store(utime, storer); + } + + template + void parse(ParserT &parser) { + using td::parse; + using tonlib::parse; + parse(zero_state_id, parser); + parse(last_key_block_id, parser); + parse(last_block_id, parser); + parse(utime, parser); + } }; + class LastBlock : public td::actor::Actor { public: - struct State { - ton::ZeroStateIdExt zero_state_id; - ton::BlockIdExt last_key_block_id; - ton::BlockIdExt last_block_id; - td::int64 utime{0}; - }; - class Callback { public: virtual ~Callback() { } - virtual void on_state_changes(State state) = 0; + virtual void on_state_changed(LastBlockState state) = 0; }; - explicit LastBlock(ExtClientRef client, State state, td::unique_ptr callback); - void get_last_block(td::Promise promise); + explicit LastBlock(ExtClientRef client, LastBlockState state, td::unique_ptr callback); + void get_last_block(td::Promise promise); private: ExtClient client_; - State state_; + LastBlockState state_; td::unique_ptr callback_; - std::vector> promises_; + // stats + td::Timer total_sync_; + td::Timer validate_; + td::uint32 queries_; + + std::vector> promises_; void do_get_last_block(); void on_masterchain_info(td::Result> r_info); @@ -62,8 +141,8 @@ class LastBlock : public td::actor::Actor { void update_zero_state(ton::ZeroStateIdExt zero_state_id); - void update_mc_last_block(ton::BlockIdExt mc_block_id); - void update_mc_last_key_block(ton::BlockIdExt mc_key_block_id); + bool update_mc_last_block(ton::BlockIdExt mc_block_id); + bool update_mc_last_key_block(ton::BlockIdExt mc_key_block_id); void update_utime(td::int64 utime); }; } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.cpp new file mode 100644 index 0000000000..fa979a3ca3 --- /dev/null +++ b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.cpp @@ -0,0 +1,44 @@ +#include "LastBlockStorage.h" + +#include "td/utils/as.h" +#include "td/utils/filesystem.h" +#include "td/utils/port/path.h" +#include "td/utils/tl_helpers.h" + +namespace tonlib { + +td::Status LastBlockStorage::set_directory(std::string directory) { + TRY_RESULT(path, td::realpath(directory)); + TRY_RESULT(stat, td::stat(path)); + if (!stat.is_dir_) { + return td::Status::Error("not a directory"); + } + directory_ = std::move(path); + return td::Status::OK(); +} + +std::string LastBlockStorage::get_file_name(td::Slice name) { + return directory_ + TD_DIR_SLASH + td::buffer_to_hex(name) + ".blkstate"; +} + +td::Result LastBlockStorage::get_state(td::Slice name) { + TRY_RESULT(data, td::read_file(get_file_name(name))); + if (data.size() < 8) { + return td::Status::Error("too short"); + } + if (td::as(data.data()) != td::crc64(td::Slice(data).substr(8))) { + return td::Status::Error("crc64 mismatch"); + } + LastBlockState res; + TRY_STATUS(td::unserialize(res, td::Slice(data).substr(8))); + return res; +} + +void LastBlockStorage::save_state(td::Slice name, LastBlockState state) { + auto x = td::serialize(state); + std::string y(x.size() + 8, 0); + td::MutableSlice(y).substr(8).copy_from(x); + td::as(td::MutableSlice(y).data()) = td::crc64(x); + td::atomic_write_file(get_file_name(name), y); +} +} // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.h b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.h new file mode 100644 index 0000000000..fa920ef6ed --- /dev/null +++ b/submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.h @@ -0,0 +1,16 @@ +#pragma once + +#include "tonlib/LastBlock.h" + +namespace tonlib { +class LastBlockStorage { + public: + td::Status set_directory(std::string directory); + td::Result get_state(td::Slice name); + void save_state(td::Slice name, LastBlockState state); + + private: + std::string directory_; + std::string get_file_name(td::Slice name); +}; +} // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.cpp index c9ebbcc9df..9ea58e54e2 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.cpp @@ -32,8 +32,9 @@ vm::CellHash TestGiver::get_init_code_hash() { return vm::CellHash::from_slice(td::base64_decode("wDkZp0yR4xo+9+BnuAPfGVjBzK6FPzqdv2DwRq3z3KE=").move_as_ok()); } -td::Ref TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, +td::Ref TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message, const block::StdAddress& dest_address) { + CHECK(message.size() <= 128); td::BigInt256 dest_addr; dest_addr.import_bits(dest_address.addr.as_bitslice()); vm::CellBuilder cb; @@ -44,7 +45,7 @@ td::Ref TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gr .store_int256(dest_addr, 256); block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms)); - auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("GIFT").finalize(); + auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes(message).finalize(); return vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize(); } } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.h b/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.h index 88ccd1b772..6859be8ff0 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TestGiver.h @@ -23,7 +23,7 @@ class TestGiver { public: static const block::StdAddress& address(); static vm::CellHash get_init_code_hash(); - static td::Ref make_a_gift_message(td::uint32 seqno, td::uint64 gramms, + static td::Ref make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message, const block::StdAddress& dest_address); }; } // namespace tonlib diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.cpp index bda32c1752..c092bac29c 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.cpp @@ -38,7 +38,9 @@ td::Ref TestWallet::get_init_message(const td::Ed25519::PrivateKey& pr } td::Ref TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, - td::int64 gramms, const block::StdAddress& dest_address) { + td::int64 gramms, td::Slice message, + const block::StdAddress& dest_address) { + CHECK(message.size() <= 128); td::BigInt256 dest_addr; dest_addr.import_bits(dest_address.addr.as_bitslice()); vm::CellBuilder cb; @@ -46,11 +48,11 @@ td::Ref TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& .store_long(dest_address.workchain, 8) .store_int256(dest_addr, 256); block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms)); - auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("GIFT").finalize(); - auto message = vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize(); + auto message_inner = cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes(message).finalize(); + auto message_outer = vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize(); std::string seq_no(4, 0); - auto signature = private_key.sign(message->get_hash().as_slice()).move_as_ok(); - return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message)).finalize(); + auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok(); + return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize(); } td::Ref TestWallet::get_init_code() { diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.h b/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.h index f4de1f6ae6..921e3b3afe 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TestWallet.h @@ -28,7 +28,8 @@ class TestWallet { static td::Ref get_init_state(const td::Ed25519::PublicKey& public_key); static td::Ref get_init_message(const td::Ed25519::PrivateKey& private_key); static td::Ref make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno, - td::int64 gramms, const block::StdAddress& dest_address); + td::int64 gramms, td::Slice message, + const block::StdAddress& dest_address); static td::Ref get_init_code(); static vm::CellHash get_init_code_hash(); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp index 7b48876f93..ea0c6c81e9 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.cpp @@ -41,8 +41,6 @@ #include "td/utils/tests.h" #include "td/utils/port/path.h" -namespace ton {} // namespace ton - namespace tonlib { template @@ -152,6 +150,11 @@ class GetTransactionHistory : public td::actor::Actor { } void start_up() override { + if (lt_ == 0) { + promise_.set_value(block::TransactionList::Info()); + stop(); + return; + } client_.send_query( ton::lite_api::liteServer_getTransactions( count_, ton::create_tl_object(address_.workchain, address_.addr), lt_, @@ -171,7 +174,7 @@ class GetRawAccountState : public td::actor::Actor { block::StdAddress address_; td::Promise promise_; ExtClient client_; - LastBlockInfo last_block_; + LastBlockState last_block_; void with_account_state(td::Result> r_account_state) { promise_.set_result(TRY_VM(do_with_account_state(std::move(r_account_state)))); @@ -182,7 +185,7 @@ class GetRawAccountState : public td::actor::Actor { td::Result> r_account_state) { TRY_RESULT(raw_account_state, std::move(r_account_state)); auto account_state = create_account_state(std::move(raw_account_state)); - TRY_RESULT(info, account_state.validate(last_block_.id, address_)); + TRY_RESULT(info, account_state.validate(last_block_.last_block_id, address_)); auto serialized_state = account_state.state.clone(); RawAccountState res; res.info = std::move(info); @@ -225,14 +228,14 @@ class GetRawAccountState : public td::actor::Actor { } void start_up() override { - client_.with_last_block([self = this](td::Result r_last_block) { + client_.with_last_block([self = this](td::Result r_last_block) { if (r_last_block.is_error()) { return self->check(r_last_block.move_as_error()); } self->last_block_ = r_last_block.move_as_ok(); self->client_.send_query( - ton::lite_api::liteServer_getAccountState(ton::create_tl_lite_block_id(self->last_block_.id), + ton::lite_api::liteServer_getAccountState(ton::create_tl_lite_block_id(self->last_block_.last_block_id), ton::create_tl_object( self->address_.workchain, self->address_.addr)), [self](auto r_state) { self->with_account_state(std::move(r_state)); }); @@ -307,24 +310,36 @@ void TonlibClient::init_ext_client() { td::make_unique(td::actor::actor_shared())); } } + +void TonlibClient::update_last_block_state(LastBlockState state) { + last_block_storage_.save_state("none", state); +} + void TonlibClient::init_last_block() { ref_cnt_++; class Callback : public LastBlock::Callback { public: Callback(td::actor::ActorShared client) : client_(std::move(client)) { } - void on_state_changes(LastBlock::State state) override { - //TODO + void on_state_changed(LastBlockState state) override { + send_closure(client_, &TonlibClient::update_last_block_state, std::move(state)); } private: td::actor::ActorShared client_; }; - LastBlock::State state; - //state.zero_state_id = ton::ZeroStateIdExt(config_.zero_state_id.id.workchain, config_.zero_state_id.root_hash, - //config_.zero_state_id.file_hash), - state.last_block_id = config_.zero_state_id; - state.last_key_block_id = config_.zero_state_id; + LastBlockState state; + + auto r_state = last_block_storage_.get_state("none"); + if (r_state.is_error()) { + LOG(WARNING) << "Unknown LastBlockState: " << r_state.error(); + state.zero_state_id = ton::ZeroStateIdExt(config_.zero_state_id.id.workchain, config_.zero_state_id.root_hash, + config_.zero_state_id.file_hash), + state.last_block_id = config_.zero_state_id; + state.last_key_block_id = config_.zero_state_id; + } else { + state = r_state.move_as_ok(); + } raw_last_block_ = td::actor::create_actor("LastBlock", get_client_ref(), std::move(state), td::make_unique(td::actor::actor_shared(this))); @@ -469,6 +484,7 @@ td::Status TonlibClient::do_request(const tonlib_api::init& request, return td::Status::Error(400, "Field options must not be empty"); } TRY_STATUS(key_storage_.set_directory(request.options_->keystore_directory_)); + TRY_STATUS(last_block_storage_.set_directory(request.options_->keystore_directory_)); use_callbacks_for_network_ = request.options_->use_callbacks_for_network_; if (!request.options_->config_.empty()) { TRY_STATUS(set_config(std::move(request.options_->config_))); @@ -570,10 +586,25 @@ td::Result> to_raw_message_or_th if (!tlb::csr_unpack(message.info, msg_info)) { return td::Status::Error("Failed to unpack CommonMsgInfo::int_msg_info"); } + TRY_RESULT(balance, to_balance(msg_info.value)); TRY_RESULT(src, to_std_address(msg_info.src)); TRY_RESULT(dest, to_std_address(msg_info.dest)); - return tonlib_api::make_object(std::move(src), std::move(dest), balance); + td::Ref body; + if (message.body->prefetch_long(1) == 0) { + body = std::move(message.body); + body.write().advance(1); + } else { + body = vm::load_cell_slice_ref(message.body->prefetch_ref()); + } + std::string body_message; + if (body->size() % 8 == 0) { + body_message = std::string(body->size() / 8, 0); + body->prefetch_bytes(td::MutableSlice(body_message).ubegin(), body->size() / 8); + } + + return tonlib_api::make_object(std::move(src), std::move(dest), balance, + std::move(body_message)); } case block::gen::CommonMsgInfo::ext_in_msg_info: { block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info; @@ -581,7 +612,7 @@ td::Result> to_raw_message_or_th return td::Status::Error("Failed to unpack CommonMsgInfo::ext_in_msg_info"); } TRY_RESULT(dest, to_std_address(msg_info.dest)); - return tonlib_api::make_object("", std::move(dest), 0); + return tonlib_api::make_object("", std::move(dest), 0, ""); } case block::gen::CommonMsgInfo::ext_out_msg_info: { block::gen::CommonMsgInfo::Record_ext_out_msg_info msg_info; @@ -589,7 +620,7 @@ td::Result> to_raw_message_or_th return td::Status::Error("Failed to unpack CommonMsgInfo::ext_out_msg_info"); } TRY_RESULT(src, to_std_address(msg_info.src)); - return tonlib_api::make_object(std::move(src), "", 0); + return tonlib_api::make_object(std::move(src), "", 0, ""); } } @@ -626,7 +657,7 @@ td::Result> to_raw_transacti if (is_just == trans.r1.in_msg->fetch_long_eof) { return td::Status::Error("Failed to parse long"); } - if (is_just == 1) { + if (is_just == -1) { auto msg = trans.r1.in_msg->prefetch_ref(); TRY_RESULT(in_msg_copy, to_raw_message(trans.r1.in_msg->prefetch_ref())); in_msg = std::move(in_msg_copy); @@ -702,7 +733,7 @@ td::Result> to_generic_ RawAccountState&& raw_state) { if (raw_state.code.is_null()) { return tonlib_api::make_object( - tonlib_api::make_object(raw_state.balance, empty_transaction_id(), + tonlib_api::make_object(raw_state.balance, to_transaction_id(raw_state.info), raw_state.sync_utime)); } @@ -827,21 +858,24 @@ td::Status TonlibClient::do_request(const tonlib_api::testWallet_sendGrams& requ if (!request.private_key_) { return td::Status::Error(400, "Field private_key must not be empty"); } + if (request.message_.size() > 128) { + return td::Status::Error(400, "Message is too long"); + } TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_)); account_address.bounceable = false; TRY_RESULT(input_key, from_tonlib(*request.private_key_)); auto address = GenericAccount::get_address( 0 /*zerochain*/, TestWallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy()))); TRY_RESULT(private_key, key_storage_.load_private_key(std::move(input_key))); - return do_request( - tonlib_api::raw_sendMessage(tonlib_api::make_object(address.rserialize()), "", - vm::std_boc_serialize(TestWallet::make_a_gift_message( - td::Ed25519::PrivateKey(std::move(private_key.private_key)), - request.seqno_, request.amount_, account_address)) - .move_as_ok() - .as_slice() - .str()), - std::move(promise)); + return do_request(tonlib_api::raw_sendMessage( + tonlib_api::make_object(address.rserialize()), "", + vm::std_boc_serialize(TestWallet::make_a_gift_message( + td::Ed25519::PrivateKey(std::move(private_key.private_key)), + request.seqno_, request.amount_, request.message_, account_address)) + .move_as_ok() + .as_slice() + .str()), + std::move(promise)); } td::Status TonlibClient::do_request(tonlib_api::testWallet_getAccountState& request, @@ -868,16 +902,19 @@ td::Status TonlibClient::do_request(const tonlib_api::testGiver_sendGrams& reque if (!request.destination_) { return td::Status::Error(400, "Field destination must not be empty"); } + if (request.message_.size() > 128) { + return td::Status::Error(400, "Message is too long"); + } TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_)); account_address.bounceable = false; - return do_request( - tonlib_api::raw_sendMessage( - tonlib_api::make_object(TestGiver::address().rserialize()), "", - vm::std_boc_serialize(TestGiver::make_a_gift_message(request.seqno_, request.amount_, account_address)) - .move_as_ok() - .as_slice() - .str()), - std::move(promise)); + return do_request(tonlib_api::raw_sendMessage( + tonlib_api::make_object(TestGiver::address().rserialize()), "", + vm::std_boc_serialize(TestGiver::make_a_gift_message(request.seqno_, request.amount_, + request.message_, account_address)) + .move_as_ok() + .as_slice() + .str()), + std::move(promise)); } td::Status TonlibClient::do_request(const tonlib_api::testGiver_getAccountState& request, @@ -920,7 +957,7 @@ td::Status TonlibClient::do_request(tonlib_api::generic_sendGrams& request, "GetAccountState", client_.get_client(), std::move(account_address), [promise = std::move(promise), self = this, actor_id = td::actor::actor_id(), private_key = std::move(request.private_key_), destination = std::move(request.destination_), - amount = request.amount_](td::Result r_state) mutable { + amount = request.amount_, message = std::move(request.message_)](td::Result r_state) mutable { if (r_state.is_error()) { return promise.set_error(r_state.move_as_error()); } @@ -930,40 +967,41 @@ td::Status TonlibClient::do_request(tonlib_api::generic_sendGrams& request, } auto state = rr_state.move_as_ok(); - downcast_call(*state, - td::overloaded( - [&](tonlib_api::generic_accountStateTestGiver& test_giver_state) { - send_lambda(actor_id, [promise = std::move(promise), self, - query = tonlib_api::testGiver_sendGrams( - std::move(destination), test_giver_state.account_state_->seqno_, - amount)]() mutable { - LOG(INFO) << "Send " << to_string(query); - auto status = self->do_request(query, std::move(promise)); - if (status.is_error()) { - CHECK(promise); - promise.set_error(std::move(status)); - } - }); - return; - }, - [&](tonlib_api::generic_accountStateTestWallet& test_wallet_state) { - send_lambda(actor_id, [promise = std::move(promise), self, - query = tonlib_api::testWallet_sendGrams( - std::move(private_key), std::move(destination), - test_wallet_state.account_state_->seqno_, amount)]() mutable { - auto status = self->do_request(query, std::move(promise)); - if (status.is_error()) { - CHECK(promise); - promise.set_error(std::move(status)); - } - }); - }, - [&](tonlib_api::generic_accountStateUninited&) { - promise.set_error(td::Status::Error(400, "Account is not inited")); - }, - [&](tonlib_api::generic_accountStateRaw&) { - promise.set_error(td::Status::Error(400, "Unknown account type")); - })); + downcast_call(*state, td::overloaded( + [&](tonlib_api::generic_accountStateTestGiver& test_giver_state) { + send_lambda(actor_id, + [promise = std::move(promise), self, + query = tonlib_api::testGiver_sendGrams( + std::move(destination), test_giver_state.account_state_->seqno_, + amount, std::move(message))]() mutable { + LOG(INFO) << "Send " << to_string(query); + auto status = self->do_request(query, std::move(promise)); + if (status.is_error()) { + CHECK(promise); + promise.set_error(std::move(status)); + } + }); + return; + }, + [&](tonlib_api::generic_accountStateTestWallet& test_wallet_state) { + send_lambda(actor_id, [promise = std::move(promise), self, + query = tonlib_api::testWallet_sendGrams( + std::move(private_key), std::move(destination), + test_wallet_state.account_state_->seqno_, amount, + std::move(message))]() mutable { + auto status = self->do_request(query, std::move(promise)); + if (status.is_error()) { + CHECK(promise); + promise.set_error(std::move(status)); + } + }); + }, + [&](tonlib_api::generic_accountStateUninited&) { + promise.set_error(td::Status::Error(400, "Account is not inited")); + }, + [&](tonlib_api::generic_accountStateRaw&) { + promise.set_error(td::Status::Error(400, "Unknown account type")); + })); }) .release(); return td::Status::OK(); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h index 0e36a28921..a45fd6fdfc 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h +++ b/submodules/ton/tonlib-src/tonlib/tonlib/TonlibClient.h @@ -24,6 +24,7 @@ #include "tonlib/ExtClient.h" #include "tonlib/ExtClientOutbound.h" #include "tonlib/KeyStorage.h" +#include "tonlib/LastBlockStorage.h" #include "td/actor/actor.h" @@ -50,6 +51,7 @@ class TonlibClient : public td::actor::Actor { // KeyStorage KeyStorage key_storage_; + LastBlockStorage last_block_storage_; // network td::actor::ActorOwn raw_client_; @@ -73,6 +75,7 @@ class TonlibClient : public td::actor::Actor { } } + void update_last_block_state(LastBlockState state); void on_result(td::uint64 id, object_ptr response); static bool is_static_request(td::int32 id); static bool is_uninited_request(td::int32 id); diff --git a/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp b/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp index cdbec51be9..f6ce8883a9 100644 --- a/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp +++ b/submodules/ton/tonlib-src/tonlib/tonlib/tonlib-cli.cpp @@ -6,6 +6,7 @@ #include "td/utils/port/signals.h" #include "td/utils/port/path.h" #include "td/utils/Random.h" +#include "td/utils/as.h" #include "terminal/terminal.h" @@ -327,6 +328,8 @@ class TonlibCli : public td::actor::Actor { << "\n"; for (size_t i = 0; i < keys_.size(); i++) { td::TerminalIO::out() << " #" << i << ": " << keys_[i].public_key << "\n"; + td::TerminalIO::out() << " " << to_account_address(PSLICE() << i, false).move_as_ok().address->account_address_ + << "\n"; } } @@ -598,13 +601,21 @@ class TonlibCli : public td::actor::Actor { } void transfer(Address from, Address to, td::uint64 grams, td::Slice password) { + td::TerminalIO::out() << "Enter message (could be empty)"; + cont_ = [this, from = std::move(from), to = std::move(to), grams, + password = password.str()](td::Slice message) mutable { + this->transfer(std::move(from), std::move(to), grams, password, message); + }; + return; + } + void transfer(Address from, Address to, td::uint64 grams, td::Slice password, td::Slice message) { using tonlib_api::make_object; auto key = !from.secret.empty() ? make_object( make_object(from.public_key, from.secret.copy()), td::SecureString(password)) : nullptr; send_query(make_object(std::move(key), std::move(from.address), - std::move(to.address), grams), + std::move(to.address), grams, message.str()), [](auto r_res) { if (r_res.is_error()) { td::TerminalIO::out() << "Can't get state: " << r_res.error() << "\n";