mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-03 21:16:35 +00:00
Update tonlib [skip ci]
This commit is contained in:
parent
fa3bb5d9c5
commit
beab635aba
@ -43,8 +43,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
@property (nonatomic, readonly) int64_t value;
|
@property (nonatomic, readonly) int64_t value;
|
||||||
@property (nonatomic, strong, readonly) NSString * _Nonnull source;
|
@property (nonatomic, strong, readonly) NSString * _Nonnull source;
|
||||||
@property (nonatomic, strong, readonly) NSString * _Nonnull destination;
|
@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
|
@end
|
||||||
|
|
||||||
@ -80,7 +81,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
- (MTSignal *)getTestGiverAddress;
|
- (MTSignal *)getTestGiverAddress;
|
||||||
- (MTSignal *)testGiverSendGramsWithAccountState:(TONAccountState *)accountState accountAddress:(NSString *)accountAddress amount:(int64_t)amount;
|
- (MTSignal *)testGiverSendGramsWithAccountState:(TONAccountState *)accountState accountAddress:(NSString *)accountAddress amount:(int64_t)amount;
|
||||||
- (MTSignal *)getAccountStateWithAddress:(NSString *)accountAddress;
|
- (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 *)exportKey:(TONKey *)key localPassword:(NSData *)localPassword;
|
||||||
- (MTSignal *)importKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword wordList:(NSArray<NSString *> *)wordList;
|
- (MTSignal *)importKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword wordList:(NSArray<NSString *> *)wordList;
|
||||||
- (MTSignal *)deleteKeyWithPublicKey:(NSString *)publicKey;
|
- (MTSignal *)deleteKeyWithPublicKey:(NSString *)publicKey;
|
||||||
|
|||||||
@ -43,10 +43,14 @@ static TONTransactionMessage * _Nullable parseTransactionMessage(tonlib_api::obj
|
|||||||
}
|
}
|
||||||
NSString *source = readString(message->source_);
|
NSString *source = readString(message->source_);
|
||||||
NSString *destination = readString(message->source_);
|
NSString *destination = readString(message->source_);
|
||||||
|
NSString *textMessage = readString(message->message_);
|
||||||
if (source == nil || destination == nil) {
|
if (source == nil || destination == nil) {
|
||||||
return 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
|
@implementation TONKey
|
||||||
@ -91,12 +95,13 @@ static TONTransactionMessage * _Nullable parseTransactionMessage(tonlib_api::obj
|
|||||||
|
|
||||||
@implementation TONTransactionMessage
|
@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];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
_value = value;
|
_value = value;
|
||||||
_source = source;
|
_source = source;
|
||||||
_destination = destination;
|
_destination = destination;
|
||||||
|
_textMessage = textMessage;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -449,7 +454,12 @@ typedef enum {
|
|||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
auto query = make_object<tonlib_api::testGiver_sendGrams>(make_object<tonlib_api::accountAddress>(accountAddress.UTF8String), accountState.seqno, amount);
|
auto query = make_object<tonlib_api::testGiver_sendGrams>(make_object<tonlib_api::accountAddress>(
|
||||||
|
accountAddress.UTF8String),
|
||||||
|
accountState.seqno,
|
||||||
|
amount,
|
||||||
|
std::string()
|
||||||
|
);
|
||||||
_client->send({ requestId, std::move(query) });
|
_client->send({ requestId, std::move(query) });
|
||||||
|
|
||||||
return [[MTBlockDisposable alloc] initWithBlock:^{
|
return [[MTBlockDisposable alloc] initWithBlock:^{
|
||||||
@ -493,13 +503,18 @@ typedef enum {
|
|||||||
}] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]];
|
}] 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<MTDisposable>(MTSubscriber *subscriber) {
|
return [[[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) {
|
||||||
NSData *publicKeyData = [key.publicKey dataUsingEncoding:NSUTF8StringEncoding];
|
NSData *publicKeyData = [key.publicKey dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
if (publicKeyData == nil) {
|
if (publicKeyData == nil) {
|
||||||
[subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in sendGramsFromKey"]];
|
[subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in sendGramsFromKey"]];
|
||||||
return [[MTBlockDisposable alloc] initWithBlock:^{}];
|
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;
|
uint64_t requestId = _nextRequestId;
|
||||||
_nextRequestId += 1;
|
_nextRequestId += 1;
|
||||||
@ -523,7 +538,8 @@ typedef enum {
|
|||||||
),
|
),
|
||||||
make_object<tonlib_api::accountAddress>(fromAddress.UTF8String),
|
make_object<tonlib_api::accountAddress>(fromAddress.UTF8String),
|
||||||
make_object<tonlib_api::accountAddress>(address.UTF8String),
|
make_object<tonlib_api::accountAddress>(address.UTF8String),
|
||||||
amount
|
amount,
|
||||||
|
makeString(textMessageData)
|
||||||
);
|
);
|
||||||
_client->send({ requestId, std::move(query) });
|
_client->send({ requestId, std::move(query) });
|
||||||
|
|
||||||
|
|||||||
@ -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
|
return Signal { subscriber in
|
||||||
let disposable = MetaDisposable()
|
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
|
self.impl.with { impl in
|
||||||
impl.withInstance { ton in
|
impl.withInstance { ton in
|
||||||
let cancel = ton.createKey(withLocalPassword: serverSalt, mnemonicPassword: Data()).start(next: { key in
|
let cancel = ton.createKey(withLocalPassword: serverSalt, mnemonicPassword: Data()).start(next: { key in
|
||||||
@ -85,13 +108,11 @@ public final class TonInstance {
|
|||||||
assertionFailure()
|
assertionFailure()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let cancel = ton.export(key, localPassword: serverSalt).start(next: { wordList in
|
let _ = self.exportKey(key: key, serverSalt: serverSalt).start(next: { wordList in
|
||||||
guard let wordList = wordList as? [String] else {
|
|
||||||
assertionFailure()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
subscriber.putNext((WalletInfo(publicKey: WalletPublicKey(rawValue: key.publicKey), encryptedSecret: EncryptedWalletSecret(rawValue: encryptedSecretData)), wordList))
|
subscriber.putNext((WalletInfo(publicKey: WalletPublicKey(rawValue: key.publicKey), encryptedSecret: EncryptedWalletSecret(rawValue: encryptedSecretData)), wordList))
|
||||||
subscriber.putCompletion()
|
subscriber.putCompletion()
|
||||||
|
}, error: { _ in
|
||||||
|
preconditionFailure()
|
||||||
})
|
})
|
||||||
}, error: { _ in
|
}, error: { _ in
|
||||||
}, completed: {
|
}, completed: {
|
||||||
@ -195,30 +216,20 @@ public final class TonInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func walletBalance(publicKey: WalletPublicKey) -> Signal<WalletBalance, NoError> {
|
fileprivate func getWalletState(address: String) -> Signal<WalletState, NoError> {
|
||||||
return Signal { subscriber in
|
return Signal { subscriber in
|
||||||
let disposable = MetaDisposable()
|
let disposable = MetaDisposable()
|
||||||
|
|
||||||
self.impl.with { impl in
|
self.impl.with { impl in
|
||||||
impl.withInstance { ton in
|
impl.withInstance { ton in
|
||||||
let cancel = ton.getTestWalletAccountAddress(withPublicKey: publicKey.rawValue).start(next: { address in
|
let cancel = ton.getAccountState(withAddress: address).start(next: { state in
|
||||||
guard let address = address as? String else {
|
guard let state = state as? TONAccountState else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let cancel = ton.getAccountState(withAddress: address).start(next: { state in
|
subscriber.putNext(WalletState(balance: state.balance, lastTransactionId: state.lastTransactionId.flatMap(WalletTransactionId.init(tonTransactionId:))))
|
||||||
guard let state = state as? TONAccountState else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
subscriber.putNext(WalletBalance(rawValue: state.balance))
|
|
||||||
}, error: { _ in
|
|
||||||
}, completed: {
|
|
||||||
subscriber.putCompletion()
|
|
||||||
})
|
|
||||||
disposable.set(ActionDisposable {
|
|
||||||
cancel?.dispose()
|
|
||||||
})
|
|
||||||
}, error: { _ in
|
}, error: { _ in
|
||||||
}, completed: {
|
}, completed: {
|
||||||
|
subscriber.putCompletion()
|
||||||
})
|
})
|
||||||
disposable.set(ActionDisposable {
|
disposable.set(ActionDisposable {
|
||||||
cancel?.dispose()
|
cancel?.dispose()
|
||||||
@ -282,17 +293,39 @@ public final class TonInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func getGramsFromTestGiver(address: String, amount: Int64) -> Signal<Void, GetGramsFromTestGiverError> {
|
fileprivate func getTestGiverAccountState() -> Signal<TONAccountState?, NoError> {
|
||||||
return Signal { subscriber in
|
return Signal { subscriber in
|
||||||
let disposable = MetaDisposable()
|
let disposable = MetaDisposable()
|
||||||
|
|
||||||
self.impl.with { impl in
|
self.impl.with { impl in
|
||||||
impl.withInstance { ton in
|
impl.withInstance { ton in
|
||||||
let cancel = ton.getTestGiverAccountState().start(next: { state in
|
let cancel = ton.getTestGiverAccountState().start(next: { state in
|
||||||
guard let state = state as? TONAccountState else {
|
subscriber.putNext(state as? TONAccountState)
|
||||||
subscriber.putError(.generic)
|
subscriber.putCompletion()
|
||||||
return
|
}, error: { _ in
|
||||||
}
|
subscriber.putNext(nil)
|
||||||
|
subscriber.putCompletion()
|
||||||
|
}, completed: {
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return disposable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func getGramsFromTestGiver(address: String, amount: Int64) -> Signal<Void, GetGramsFromTestGiverError> {
|
||||||
|
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
|
let cancel = ton.testGiverSendGrams(with: state, accountAddress: address, amount: amount).start(next: { _ in
|
||||||
}, error: { _ in
|
}, error: { _ in
|
||||||
subscriber.putError(.generic)
|
subscriber.putError(.generic)
|
||||||
@ -302,21 +335,15 @@ public final class TonInstance {
|
|||||||
disposable.set(ActionDisposable {
|
disposable.set(ActionDisposable {
|
||||||
cancel?.dispose()
|
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<Never, SendGramsFromWalletError> {
|
fileprivate func sendGramsFromWallet(keychain: TonKeychain, serverSalt: Data, walletInfo: WalletInfo, fromAddress: String, toAddress: String, amount: Int64, textMessage: String) -> Signal<Never, SendGramsFromWalletError> {
|
||||||
return keychain.decrypt(walletInfo.encryptedSecret.rawValue)
|
return keychain.decrypt(walletInfo.encryptedSecret.rawValue)
|
||||||
|> introduceError(SendGramsFromWalletError.self)
|
|> introduceError(SendGramsFromWalletError.self)
|
||||||
|> mapToSignal { decryptedSecret -> Signal<Never, SendGramsFromWalletError> in
|
|> mapToSignal { decryptedSecret -> Signal<Never, SendGramsFromWalletError> in
|
||||||
@ -328,7 +355,7 @@ public final class TonInstance {
|
|||||||
|
|
||||||
self.impl.with { impl in
|
self.impl.with { impl in
|
||||||
impl.withInstance { ton 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()
|
preconditionFailure()
|
||||||
}, error: { _ in
|
}, error: { _ in
|
||||||
subscriber.putError(.generic)
|
subscriber.putError(.generic)
|
||||||
@ -526,11 +553,13 @@ public func walletRestoreWords(network: Network, walletInfo: WalletInfo, tonInst
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct WalletBalance: Hashable {
|
public struct WalletState: Equatable {
|
||||||
public var rawValue: Int64
|
public let balance: Int64
|
||||||
|
public let lastTransactionId: WalletTransactionId?
|
||||||
|
|
||||||
public init(rawValue: Int64) {
|
public init(balance: Int64, lastTransactionId: WalletTransactionId?) {
|
||||||
self.rawValue = rawValue
|
self.balance = balance
|
||||||
|
self.lastTransactionId = lastTransactionId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,8 +571,8 @@ public func testGiverWalletAddress(tonInstance: TonInstance) -> Signal<String, N
|
|||||||
return tonInstance.testGiverWalletAddress()
|
return tonInstance.testGiverWalletAddress()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func currentWalletBalance(publicKey: WalletPublicKey, tonInstance: TonInstance) -> Signal<WalletBalance, NoError> {
|
public func getWalletState(address: String, tonInstance: TonInstance) -> Signal<WalletState, NoError> {
|
||||||
return tonInstance.walletBalance(publicKey: publicKey)
|
return tonInstance.getWalletState(address: address)
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum GetGramsFromTestGiverError {
|
public enum GetGramsFromTestGiverError {
|
||||||
@ -559,7 +588,7 @@ public enum SendGramsFromWalletError {
|
|||||||
case secretDecryptionFailed
|
case secretDecryptionFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
public func sendGramsFromWallet(network: Network, tonInstance: TonInstance, keychain: TonKeychain, walletInfo: WalletInfo, toAddress: String, amount: Int64) -> Signal<Never, SendGramsFromWalletError> {
|
public func sendGramsFromWallet(network: Network, tonInstance: TonInstance, keychain: TonKeychain, walletInfo: WalletInfo, toAddress: String, amount: Int64, textMessage: String) -> Signal<Never, SendGramsFromWalletError> {
|
||||||
return getServerWalletSalt(network: network)
|
return getServerWalletSalt(network: network)
|
||||||
|> mapError { _ -> SendGramsFromWalletError in
|
|> mapError { _ -> SendGramsFromWalletError in
|
||||||
return .generic
|
return .generic
|
||||||
@ -568,7 +597,7 @@ public func sendGramsFromWallet(network: Network, tonInstance: TonInstance, keyc
|
|||||||
return walletAddress(publicKey: walletInfo.publicKey, tonInstance: tonInstance)
|
return walletAddress(publicKey: walletInfo.publicKey, tonInstance: tonInstance)
|
||||||
|> introduceError(SendGramsFromWalletError.self)
|
|> introduceError(SendGramsFromWalletError.self)
|
||||||
|> mapToSignal { fromAddress in
|
|> 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 value: Int64
|
||||||
public let source: String
|
public let source: String
|
||||||
public let destination: 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.value = value
|
||||||
self.source = source
|
self.source = source
|
||||||
self.destination = destination
|
self.destination = destination
|
||||||
|
self.textMessage = textMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: WalletTransactionMessage, rhs: WalletTransactionMessage) -> Bool {
|
public static func ==(lhs: WalletTransactionMessage, rhs: WalletTransactionMessage) -> Bool {
|
||||||
@ -604,7 +635,10 @@ public final class WalletTransactionMessage: Equatable {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if lhs.destination != rhs.destination {
|
if lhs.destination != rhs.destination {
|
||||||
return false;
|
return false
|
||||||
|
}
|
||||||
|
if lhs.textMessage != rhs.textMessage {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -612,7 +646,7 @@ public final class WalletTransactionMessage: Equatable {
|
|||||||
|
|
||||||
private extension WalletTransactionMessage {
|
private extension WalletTransactionMessage {
|
||||||
convenience init(tonTransactionMessage: TONTransactionMessage) {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -87,8 +87,8 @@ public final class WalletInfoScreen: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final class WalletInfoBalanceNode: ASDisplayNode {
|
private final class WalletInfoBalanceNode: ASDisplayNode {
|
||||||
private let balanceTextNode: ImmediateTextNode
|
let balanceTextNode: ImmediateTextNode
|
||||||
private let balanceIconNode: ASImageNode
|
let balanceIconNode: ASImageNode
|
||||||
|
|
||||||
var balance: String = " " {
|
var balance: String = " " {
|
||||||
didSet {
|
didSet {
|
||||||
@ -96,6 +96,8 @@ private final class WalletInfoBalanceNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isLoading: Bool = true
|
||||||
|
|
||||||
init(theme: PresentationTheme) {
|
init(theme: PresentationTheme) {
|
||||||
self.balanceTextNode = ImmediateTextNode()
|
self.balanceTextNode = ImmediateTextNode()
|
||||||
self.balanceTextNode.displaysAsynchronously = false
|
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 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 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.balanceTextNode, frame: balanceTextFrame)
|
||||||
transition.updateFrameAdditive(node: self.balanceIconNode, frame: balanceIconFrame)
|
transition.updateFrame(node: self.balanceIconNode, frame: balanceIconFrame)
|
||||||
|
|
||||||
return balanceTextSize.height
|
return balanceTextSize.height
|
||||||
}
|
}
|
||||||
@ -245,10 +252,10 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.balance == nil {
|
if self.balance == nil {
|
||||||
self.balanceNode.isHidden = true
|
self.balanceNode.balanceTextNode.isHidden = true
|
||||||
self.balanceSubtitleNode.isHidden = true
|
self.balanceSubtitleNode.isHidden = true
|
||||||
} else {
|
} else {
|
||||||
self.balanceNode.isHidden = false
|
self.balanceNode.balanceTextNode.isHidden = false
|
||||||
self.balanceSubtitleNode.isHidden = false
|
self.balanceSubtitleNode.isHidden = false
|
||||||
}
|
}
|
||||||
transition.updateFrame(node: self.receiveButtonNode, frame: receiveButtonFrame)
|
transition.updateFrame(node: self.receiveButtonNode, frame: receiveButtonFrame)
|
||||||
@ -272,7 +279,8 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
|
|||||||
func animateIn() {
|
func animateIn() {
|
||||||
self.sendButtonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
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.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)
|
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 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) {
|
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.account = account
|
||||||
self.tonContext = tonContext
|
self.tonContext = tonContext
|
||||||
@ -379,24 +389,28 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
|||||||
self.listNode = ListView()
|
self.listNode = ListView()
|
||||||
self.listNode.verticalScrollIndicatorColor = self.presentationData.theme.list.scrollIndicatorColor
|
self.listNode.verticalScrollIndicatorColor = self.presentationData.theme.list.scrollIndicatorColor
|
||||||
self.listNode.verticalScrollIndicatorFollowsOverscroll = true
|
self.listNode.verticalScrollIndicatorFollowsOverscroll = true
|
||||||
|
self.listNode.isHidden = true
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.backgroundColor = .white
|
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
|
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let firstTime = strongSelf.headerNode.balance == nil
|
strongSelf.headerNode.balanceNode.balance = formatBalanceText(max(0, value.balance))
|
||||||
strongSelf.headerNode.balanceNode.balance = formatBalanceText(max(0, value.rawValue))
|
strongSelf.headerNode.balance = max(0, value.balance)
|
||||||
strongSelf.headerNode.balance = max(0, value.rawValue)
|
|
||||||
if let (layout, navigationHeight) = strongSelf.validLayout {
|
if let (layout, navigationHeight) = strongSelf.validLayout {
|
||||||
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate)
|
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.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
|
self.listNode.visibleBottomContentOffsetChanged = { [weak self] offset in
|
||||||
@ -464,11 +480,22 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
|||||||
let headerHeight: CGFloat = navigationHeight + 260.0
|
let headerHeight: CGFloat = navigationHeight + 260.0
|
||||||
let topInset: CGFloat = headerHeight
|
let topInset: CGFloat = headerHeight
|
||||||
|
|
||||||
let headerFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: headerHeight))
|
let visualHeaderHeight: CGFloat
|
||||||
transition.updateFrame(node: self.headerNode, frame: headerFrame)
|
let visualHeaderOffset: CGFloat
|
||||||
self.headerNode.update(size: headerFrame.size, navigationHeight: navigationHeight, offset: self.listOffset ?? 0.0, transition: transition)
|
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 duration: Double = 0.0
|
||||||
var curve: UInt = 0
|
var curve: UInt = 0
|
||||||
@ -599,8 +626,11 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
|||||||
self.enqueuedTransactions.append(transaction)
|
self.enqueuedTransactions.append(transaction)
|
||||||
self.dequeueTransaction()
|
self.dequeueTransaction()
|
||||||
|
|
||||||
if isFirst {
|
let wasReady = self.isReady
|
||||||
self.listNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
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
|
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 {
|
func formatBalanceText(_ value: Int64) -> String {
|
||||||
|
|||||||
@ -355,7 +355,7 @@ func walletSendScreen(context: AccountContext, tonContext: TonContext, walletInf
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let balance: Signal<WalletBalance?, NoError> = Signal.single(WalletBalance(rawValue: 2500))
|
let balance: Signal<WalletState?, NoError> = Signal.single(WalletState(balance: 2500, lastTransactionId: nil))
|
||||||
|
|
||||||
var focusItemTag: ItemListItemTag?
|
var focusItemTag: ItemListItemTag?
|
||||||
if address == nil {
|
if address == nil {
|
||||||
@ -373,14 +373,14 @@ func walletSendScreen(context: AccountContext, tonContext: TonContext, walletInf
|
|||||||
let amount = amountValue(state.amount)
|
let amount = amountValue(state.amount)
|
||||||
var sendEnabled = false
|
var sendEnabled = false
|
||||||
if let balance = balance {
|
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: {
|
let rightNavigationButton = ItemListNavigationButton(content: .text("Send"), style: .bold, enabled: sendEnabled, action: {
|
||||||
arguments.proceed()
|
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 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))
|
return (controllerState, (listState, arguments))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -176,6 +176,113 @@ td::Status AdnlOutboundConnection::process_packet(td::BufferSlice data) {
|
|||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdnlExtMultiClientImpl::start_up() {
|
||||||
|
for (auto &id : ids_) {
|
||||||
|
add_server(id.first, id.second, [](td::Result<td::Unit> R) {});
|
||||||
|
}
|
||||||
|
ids_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdnlExtMultiClientImpl::add_server(AdnlNodeIdFull dst, td::IPAddress dst_addr, td::Promise<td::Unit> 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<Client>(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<td::Unit> 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<td::BufferSlice> promise) {
|
||||||
|
if (total_ready_ == 0) {
|
||||||
|
promise.set_error(td::Status::Error(ErrorCode::notready, "conn not ready"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<td::uint32> 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<td::uint32>(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<AdnlExtClient::Callback> AdnlExtMultiClientImpl::make_callback(td::uint32 g) {
|
||||||
|
class Cb : public Callback {
|
||||||
|
public:
|
||||||
|
Cb(td::actor::ActorId<AdnlExtMultiClientImpl> 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<AdnlExtMultiClientImpl> id_;
|
||||||
|
td::uint32 idx_;
|
||||||
|
};
|
||||||
|
return std::make_unique<Cb>(actor_id(this), g);
|
||||||
|
}
|
||||||
|
|
||||||
|
td::actor::ActorOwn<AdnlExtMultiClient> AdnlExtMultiClient::create(
|
||||||
|
std::vector<std::pair<AdnlNodeIdFull, td::IPAddress>> ids, std::unique_ptr<AdnlExtClient::Callback> callback) {
|
||||||
|
return td::actor::create_actor<AdnlExtMultiClientImpl>("extmulticlient", std::move(ids), std::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace adnl
|
} // namespace adnl
|
||||||
|
|
||||||
} // namespace ton
|
} // namespace ton
|
||||||
|
|||||||
@ -43,6 +43,14 @@ class AdnlExtClient : public td::actor::Actor {
|
|||||||
std::unique_ptr<AdnlExtClient::Callback> callback);
|
std::unique_ptr<AdnlExtClient::Callback> callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AdnlExtMultiClient : public AdnlExtClient {
|
||||||
|
public:
|
||||||
|
virtual void add_server(AdnlNodeIdFull dst, td::IPAddress dst_addr, td::Promise<td::Unit> promise) = 0;
|
||||||
|
virtual void del_server(td::IPAddress dst_addr, td::Promise<td::Unit> promise) = 0;
|
||||||
|
static td::actor::ActorOwn<AdnlExtMultiClient> create(std::vector<std::pair<AdnlNodeIdFull, td::IPAddress>> ids,
|
||||||
|
std::unique_ptr<AdnlExtClient::Callback> callback);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace adnl
|
} // namespace adnl
|
||||||
|
|
||||||
} // namespace ton
|
} // namespace ton
|
||||||
|
|||||||
@ -140,6 +140,52 @@ class AdnlExtClientImpl : public AdnlExtClient {
|
|||||||
void try_stop();
|
void try_stop();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AdnlExtMultiClientImpl : public AdnlExtMultiClient {
|
||||||
|
public:
|
||||||
|
AdnlExtMultiClientImpl(std::vector<std::pair<AdnlNodeIdFull, td::IPAddress>> ids,
|
||||||
|
std::unique_ptr<AdnlExtClient::Callback> callback)
|
||||||
|
: ids_(std::move(ids)), callback_(std::move(callback)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_up() override;
|
||||||
|
|
||||||
|
void add_server(AdnlNodeIdFull dst, td::IPAddress dst_addr, td::Promise<td::Unit> promise) override;
|
||||||
|
void del_server(td::IPAddress dst_addr, td::Promise<td::Unit> promise) override;
|
||||||
|
|
||||||
|
void check_ready(td::Promise<td::Unit> 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<td::BufferSlice> promise) override;
|
||||||
|
|
||||||
|
void client_ready(td::uint32 idx, bool value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Callback> make_callback(td::uint32 g);
|
||||||
|
|
||||||
|
struct Client {
|
||||||
|
Client(td::actor::ActorOwn<AdnlExtClient> 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<AdnlExtClient> client;
|
||||||
|
AdnlNodeIdFull pubkey;
|
||||||
|
td::IPAddress addr;
|
||||||
|
td::uint32 generation;
|
||||||
|
bool ready = false;
|
||||||
|
};
|
||||||
|
td::uint32 total_ready_ = 0;
|
||||||
|
|
||||||
|
td::uint32 generation_ = 0;
|
||||||
|
std::map<td::uint32, std::unique_ptr<Client>> clients_;
|
||||||
|
|
||||||
|
std::vector<std::pair<AdnlNodeIdFull, td::IPAddress>> ids_;
|
||||||
|
std::unique_ptr<AdnlExtClient::Callback> callback_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace adnl
|
} // namespace adnl
|
||||||
|
|
||||||
} // namespace ton
|
} // namespace ton
|
||||||
|
|||||||
@ -25,15 +25,40 @@
|
|||||||
|
|
||||||
namespace td {
|
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 {
|
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) {
|
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)
|
PerfWarningTimer::PerfWarningTimer(string name, double max_duration)
|
||||||
|
|||||||
@ -24,14 +24,22 @@ namespace td {
|
|||||||
|
|
||||||
class Timer {
|
class Timer {
|
||||||
public:
|
public:
|
||||||
Timer();
|
Timer() : Timer(false) {
|
||||||
|
}
|
||||||
|
explicit Timer(bool is_paused);
|
||||||
|
Timer(const Timer &other) = default;
|
||||||
|
Timer &operator=(const Timer &other) = default;
|
||||||
|
|
||||||
double elapsed() const;
|
double elapsed() const;
|
||||||
|
void pause();
|
||||||
|
void resume();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend StringBuilder &operator<<(StringBuilder &string_builder, const Timer &timer);
|
friend StringBuilder &operator<<(StringBuilder &string_builder, const Timer &timer);
|
||||||
|
|
||||||
|
double elapsed_{0};
|
||||||
double start_time_;
|
double start_time_;
|
||||||
|
bool is_paused_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
class PerfWarningTimer {
|
class PerfWarningTimer {
|
||||||
|
|||||||
@ -53,17 +53,20 @@ SecureString create_empty<SecureString>(size_t size) {
|
|||||||
template <class T>
|
template <class T>
|
||||||
Result<T> read_file_impl(CSlice path, int64 size, int64 offset) {
|
Result<T> read_file_impl(CSlice path, int64 size, int64 offset) {
|
||||||
TRY_RESULT(from_file, FileFd::open(path, FileFd::Read));
|
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) {
|
if (size == -1) {
|
||||||
TRY_RESULT(file_size, from_file.get_size());
|
size = file_size - offset;
|
||||||
size = file_size;
|
} else if (size >= 0) {
|
||||||
|
if (size + offset > file_size) {
|
||||||
|
size = file_size - offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
return Status::Error("Failed to read file: invalid size");
|
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<T>(narrow_cast<size_t>(size));
|
auto content = create_empty<T>(narrow_cast<size_t>(size));
|
||||||
TRY_RESULT(got_size, from_file.pread(as_mutable_slice(content), offset));
|
TRY_RESULT(got_size, from_file.pread(as_mutable_slice(content), offset));
|
||||||
if (got_size != static_cast<size_t>(size)) {
|
if (got_size != static_cast<size_t>(size)) {
|
||||||
|
|||||||
@ -7643,21 +7643,21 @@ engine_validator_config::engine_validator_config()
|
|||||||
, dht_()
|
, dht_()
|
||||||
, validators_()
|
, validators_()
|
||||||
, fullnode_()
|
, fullnode_()
|
||||||
, fullnodeslave_()
|
, fullnodeslaves_()
|
||||||
, fullnodemasters_()
|
, fullnodemasters_()
|
||||||
, liteservers_()
|
, liteservers_()
|
||||||
, control_()
|
, control_()
|
||||||
, gc_()
|
, gc_()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
engine_validator_config::engine_validator_config(std::int32_t out_port_, std::vector<object_ptr<engine_Addr>> &&addrs_, std::vector<object_ptr<engine_adnl>> &&adnl_, std::vector<object_ptr<engine_dht>> &&dht_, std::vector<object_ptr<engine_validator>> &&validators_, td::Bits256 const &fullnode_, object_ptr<engine_validator_fullNodeSlave> &&fullnodeslave_, std::vector<object_ptr<engine_validator_fullNodeMaster>> &&fullnodemasters_, std::vector<object_ptr<engine_liteServer>> &&liteservers_, std::vector<object_ptr<engine_controlInterface>> &&control_, object_ptr<engine_gc> &&gc_)
|
engine_validator_config::engine_validator_config(std::int32_t out_port_, std::vector<object_ptr<engine_Addr>> &&addrs_, std::vector<object_ptr<engine_adnl>> &&adnl_, std::vector<object_ptr<engine_dht>> &&dht_, std::vector<object_ptr<engine_validator>> &&validators_, td::Bits256 const &fullnode_, std::vector<object_ptr<engine_validator_fullNodeSlave>> &&fullnodeslaves_, std::vector<object_ptr<engine_validator_fullNodeMaster>> &&fullnodemasters_, std::vector<object_ptr<engine_liteServer>> &&liteservers_, std::vector<object_ptr<engine_controlInterface>> &&control_, object_ptr<engine_gc> &&gc_)
|
||||||
: out_port_(out_port_)
|
: out_port_(out_port_)
|
||||||
, addrs_(std::move(addrs_))
|
, addrs_(std::move(addrs_))
|
||||||
, adnl_(std::move(adnl_))
|
, adnl_(std::move(adnl_))
|
||||||
, dht_(std::move(dht_))
|
, dht_(std::move(dht_))
|
||||||
, validators_(std::move(validators_))
|
, validators_(std::move(validators_))
|
||||||
, fullnode_(fullnode_)
|
, fullnode_(fullnode_)
|
||||||
, fullnodeslave_(std::move(fullnodeslave_))
|
, fullnodeslaves_(std::move(fullnodeslaves_))
|
||||||
, fullnodemasters_(std::move(fullnodemasters_))
|
, fullnodemasters_(std::move(fullnodemasters_))
|
||||||
, liteservers_(std::move(liteservers_))
|
, liteservers_(std::move(liteservers_))
|
||||||
, control_(std::move(control_))
|
, control_(std::move(control_))
|
||||||
@ -7678,7 +7678,7 @@ engine_validator_config::engine_validator_config(td::TlParser &p)
|
|||||||
, dht_(TlFetchVector<TlFetchObject<engine_dht>>::parse(p))
|
, dht_(TlFetchVector<TlFetchObject<engine_dht>>::parse(p))
|
||||||
, validators_(TlFetchVector<TlFetchObject<engine_validator>>::parse(p))
|
, validators_(TlFetchVector<TlFetchObject<engine_validator>>::parse(p))
|
||||||
, fullnode_(TlFetchInt256::parse(p))
|
, fullnode_(TlFetchInt256::parse(p))
|
||||||
, fullnodeslave_(TlFetchObject<engine_validator_fullNodeSlave>::parse(p))
|
, fullnodeslaves_(TlFetchVector<TlFetchObject<engine_validator_fullNodeSlave>>::parse(p))
|
||||||
, fullnodemasters_(TlFetchVector<TlFetchObject<engine_validator_fullNodeMaster>>::parse(p))
|
, fullnodemasters_(TlFetchVector<TlFetchObject<engine_validator_fullNodeMaster>>::parse(p))
|
||||||
, liteservers_(TlFetchVector<TlFetchObject<engine_liteServer>>::parse(p))
|
, liteservers_(TlFetchVector<TlFetchObject<engine_liteServer>>::parse(p))
|
||||||
, control_(TlFetchVector<TlFetchObject<engine_controlInterface>>::parse(p))
|
, control_(TlFetchVector<TlFetchObject<engine_controlInterface>>::parse(p))
|
||||||
@ -7694,7 +7694,7 @@ void engine_validator_config::store(td::TlStorerCalcLength &s) const {
|
|||||||
TlStoreVector<TlStoreObject>::store(dht_, s);
|
TlStoreVector<TlStoreObject>::store(dht_, s);
|
||||||
TlStoreVector<TlStoreObject>::store(validators_, s);
|
TlStoreVector<TlStoreObject>::store(validators_, s);
|
||||||
TlStoreBinary::store(fullnode_, s);
|
TlStoreBinary::store(fullnode_, s);
|
||||||
TlStoreObject::store(fullnodeslave_, s);
|
TlStoreVector<TlStoreObject>::store(fullnodeslaves_, s);
|
||||||
TlStoreVector<TlStoreObject>::store(fullnodemasters_, s);
|
TlStoreVector<TlStoreObject>::store(fullnodemasters_, s);
|
||||||
TlStoreVector<TlStoreObject>::store(liteservers_, s);
|
TlStoreVector<TlStoreObject>::store(liteservers_, s);
|
||||||
TlStoreVector<TlStoreObject>::store(control_, s);
|
TlStoreVector<TlStoreObject>::store(control_, s);
|
||||||
@ -7709,7 +7709,7 @@ void engine_validator_config::store(td::TlStorerUnsafe &s) const {
|
|||||||
TlStoreVector<TlStoreObject>::store(dht_, s);
|
TlStoreVector<TlStoreObject>::store(dht_, s);
|
||||||
TlStoreVector<TlStoreObject>::store(validators_, s);
|
TlStoreVector<TlStoreObject>::store(validators_, s);
|
||||||
TlStoreBinary::store(fullnode_, s);
|
TlStoreBinary::store(fullnode_, s);
|
||||||
TlStoreObject::store(fullnodeslave_, s);
|
TlStoreVector<TlStoreObject>::store(fullnodeslaves_, s);
|
||||||
TlStoreVector<TlStoreObject>::store(fullnodemasters_, s);
|
TlStoreVector<TlStoreObject>::store(fullnodemasters_, s);
|
||||||
TlStoreVector<TlStoreObject>::store(liteservers_, s);
|
TlStoreVector<TlStoreObject>::store(liteservers_, s);
|
||||||
TlStoreVector<TlStoreObject>::store(control_, s);
|
TlStoreVector<TlStoreObject>::store(control_, s);
|
||||||
@ -7725,7 +7725,7 @@ void engine_validator_config::store(td::TlStorerToString &s, const char *field_n
|
|||||||
{ const std::vector<object_ptr<engine_dht>> &v = dht_; const std::uint32_t multiplicity = static_cast<std::uint32_t>(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<object_ptr<engine_dht>> &v = dht_; const std::uint32_t multiplicity = static_cast<std::uint32_t>(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<object_ptr<engine_validator>> &v = validators_; const std::uint32_t multiplicity = static_cast<std::uint32_t>(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(); }
|
{ const std::vector<object_ptr<engine_validator>> &v = validators_; const std::uint32_t multiplicity = static_cast<std::uint32_t>(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_);
|
s.store_field("fullnode", fullnode_);
|
||||||
if (fullnodeslave_ == nullptr) { s.store_field("fullnodeslave", "null"); } else { fullnodeslave_->store(s, "fullnodeslave"); }
|
{ const std::vector<object_ptr<engine_validator_fullNodeSlave>> &v = fullnodeslaves_; const std::uint32_t multiplicity = static_cast<std::uint32_t>(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<object_ptr<engine_validator_fullNodeMaster>> &v = fullnodemasters_; const std::uint32_t multiplicity = static_cast<std::uint32_t>(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<object_ptr<engine_validator_fullNodeMaster>> &v = fullnodemasters_; const std::uint32_t multiplicity = static_cast<std::uint32_t>(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<object_ptr<engine_liteServer>> &v = liteservers_; const std::uint32_t multiplicity = static_cast<std::uint32_t>(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<object_ptr<engine_liteServer>> &v = liteservers_; const std::uint32_t multiplicity = static_cast<std::uint32_t>(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<object_ptr<engine_controlInterface>> &v = control_; const std::uint32_t multiplicity = static_cast<std::uint32_t>(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(); }
|
{ const std::vector<object_ptr<engine_controlInterface>> &v = control_; const std::uint32_t multiplicity = static_cast<std::uint32_t>(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(); }
|
||||||
|
|||||||
@ -4214,7 +4214,7 @@ class engine_validator_config final : public Object {
|
|||||||
std::vector<object_ptr<engine_dht>> dht_;
|
std::vector<object_ptr<engine_dht>> dht_;
|
||||||
std::vector<object_ptr<engine_validator>> validators_;
|
std::vector<object_ptr<engine_validator>> validators_;
|
||||||
td::Bits256 fullnode_;
|
td::Bits256 fullnode_;
|
||||||
object_ptr<engine_validator_fullNodeSlave> fullnodeslave_;
|
std::vector<object_ptr<engine_validator_fullNodeSlave>> fullnodeslaves_;
|
||||||
std::vector<object_ptr<engine_validator_fullNodeMaster>> fullnodemasters_;
|
std::vector<object_ptr<engine_validator_fullNodeMaster>> fullnodemasters_;
|
||||||
std::vector<object_ptr<engine_liteServer>> liteservers_;
|
std::vector<object_ptr<engine_liteServer>> liteservers_;
|
||||||
std::vector<object_ptr<engine_controlInterface>> control_;
|
std::vector<object_ptr<engine_controlInterface>> control_;
|
||||||
@ -4222,9 +4222,9 @@ class engine_validator_config final : public Object {
|
|||||||
|
|
||||||
engine_validator_config();
|
engine_validator_config();
|
||||||
|
|
||||||
engine_validator_config(std::int32_t out_port_, std::vector<object_ptr<engine_Addr>> &&addrs_, std::vector<object_ptr<engine_adnl>> &&adnl_, std::vector<object_ptr<engine_dht>> &&dht_, std::vector<object_ptr<engine_validator>> &&validators_, td::Bits256 const &fullnode_, object_ptr<engine_validator_fullNodeSlave> &&fullnodeslave_, std::vector<object_ptr<engine_validator_fullNodeMaster>> &&fullnodemasters_, std::vector<object_ptr<engine_liteServer>> &&liteservers_, std::vector<object_ptr<engine_controlInterface>> &&control_, object_ptr<engine_gc> &&gc_);
|
engine_validator_config(std::int32_t out_port_, std::vector<object_ptr<engine_Addr>> &&addrs_, std::vector<object_ptr<engine_adnl>> &&adnl_, std::vector<object_ptr<engine_dht>> &&dht_, std::vector<object_ptr<engine_validator>> &&validators_, td::Bits256 const &fullnode_, std::vector<object_ptr<engine_validator_fullNodeSlave>> &&fullnodeslaves_, std::vector<object_ptr<engine_validator_fullNodeMaster>> &&fullnodemasters_, std::vector<object_ptr<engine_liteServer>> &&liteservers_, std::vector<object_ptr<engine_controlInterface>> &&control_, object_ptr<engine_gc> &&gc_);
|
||||||
|
|
||||||
static const std::int32_t ID = 17126390;
|
static const std::int32_t ID = -826140252;
|
||||||
std::int32_t get_id() const final {
|
std::int32_t get_id() const final {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -625,7 +625,7 @@ Result<int32> tl_constructor_from_string(ton_api::Object *object, const std::str
|
|||||||
{"engine.adnlProxy.config", 1848000769},
|
{"engine.adnlProxy.config", 1848000769},
|
||||||
{"engine.adnlProxy.port", -117344950},
|
{"engine.adnlProxy.port", -117344950},
|
||||||
{"engine.dht.config", -197295930},
|
{"engine.dht.config", -197295930},
|
||||||
{"engine.validator.config", 17126390},
|
{"engine.validator.config", -826140252},
|
||||||
{"engine.validator.controlQueryError", 1999018527},
|
{"engine.validator.controlQueryError", 1999018527},
|
||||||
{"engine.validator.dhtServerStatus", -1323440290},
|
{"engine.validator.dhtServerStatus", -1323440290},
|
||||||
{"engine.validator.dhtServersStatus", 725155112},
|
{"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) {
|
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("dht", ToJson(object.dht_));
|
||||||
jo << ctie("validators", ToJson(object.validators_));
|
jo << ctie("validators", ToJson(object.validators_));
|
||||||
jo << ctie("fullnode", ToJson(object.fullnode_));
|
jo << ctie("fullnode", ToJson(object.fullnode_));
|
||||||
if (object.fullnodeslave_) {
|
jo << ctie("fullnodeslaves", ToJson(object.fullnodeslaves_));
|
||||||
jo << ctie("fullnodeslave", ToJson(object.fullnodeslave_));
|
|
||||||
}
|
|
||||||
jo << ctie("fullnodemasters", ToJson(object.fullnodemasters_));
|
jo << ctie("fullnodemasters", ToJson(object.fullnodemasters_));
|
||||||
jo << ctie("liteservers", ToJson(object.liteservers_));
|
jo << ctie("liteservers", ToJson(object.liteservers_));
|
||||||
jo << ctie("control", ToJson(object.control_));
|
jo << ctie("control", ToJson(object.control_));
|
||||||
|
|||||||
@ -413,12 +413,14 @@ raw_message::raw_message()
|
|||||||
: source_()
|
: source_()
|
||||||
, destination_()
|
, destination_()
|
||||||
, value_()
|
, 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_))
|
: source_(std::move(source_))
|
||||||
, destination_(std::move(destination_))
|
, destination_(std::move(destination_))
|
||||||
, value_(value_)
|
, value_(value_)
|
||||||
|
, message_(std::move(message_))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
const std::int32_t raw_message::ID;
|
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("source", source_);
|
||||||
s.store_field("destination", destination_);
|
s.store_field("destination", destination_);
|
||||||
s.store_field("value", value_);
|
s.store_field("value", value_);
|
||||||
|
s.store_bytes_field("message", message_);
|
||||||
s.store_class_end();
|
s.store_class_end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -741,13 +744,15 @@ generic_sendGrams::generic_sendGrams()
|
|||||||
, source_()
|
, source_()
|
||||||
, destination_()
|
, destination_()
|
||||||
, amount_()
|
, amount_()
|
||||||
|
, message_()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
generic_sendGrams::generic_sendGrams(object_ptr<inputKey> &&private_key_, object_ptr<accountAddress> &&source_, object_ptr<accountAddress> &&destination_, std::int64_t amount_)
|
generic_sendGrams::generic_sendGrams(object_ptr<inputKey> &&private_key_, object_ptr<accountAddress> &&source_, object_ptr<accountAddress> &&destination_, std::int64_t amount_, std::string const &message_)
|
||||||
: private_key_(std::move(private_key_))
|
: private_key_(std::move(private_key_))
|
||||||
, source_(std::move(source_))
|
, source_(std::move(source_))
|
||||||
, destination_(std::move(destination_))
|
, destination_(std::move(destination_))
|
||||||
, amount_(amount_)
|
, amount_(amount_)
|
||||||
|
, message_(std::move(message_))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
const std::int32_t generic_sendGrams::ID;
|
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 (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"); }
|
if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); }
|
||||||
s.store_field("amount", amount_);
|
s.store_field("amount", amount_);
|
||||||
|
s.store_bytes_field("message", message_);
|
||||||
s.store_class_end();
|
s.store_class_end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1058,12 +1064,14 @@ testGiver_sendGrams::testGiver_sendGrams()
|
|||||||
: destination_()
|
: destination_()
|
||||||
, seqno_()
|
, seqno_()
|
||||||
, amount_()
|
, amount_()
|
||||||
|
, message_()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
testGiver_sendGrams::testGiver_sendGrams(object_ptr<accountAddress> &&destination_, std::int32_t seqno_, std::int64_t amount_)
|
testGiver_sendGrams::testGiver_sendGrams(object_ptr<accountAddress> &&destination_, std::int32_t seqno_, std::int64_t amount_, std::string const &message_)
|
||||||
: destination_(std::move(destination_))
|
: destination_(std::move(destination_))
|
||||||
, seqno_(seqno_)
|
, seqno_(seqno_)
|
||||||
, amount_(amount_)
|
, amount_(amount_)
|
||||||
|
, message_(std::move(message_))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
const std::int32_t testGiver_sendGrams::ID;
|
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"); }
|
if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); }
|
||||||
s.store_field("seqno", seqno_);
|
s.store_field("seqno", seqno_);
|
||||||
s.store_field("amount", amount_);
|
s.store_field("amount", amount_);
|
||||||
|
s.store_bytes_field("message", message_);
|
||||||
s.store_class_end();
|
s.store_class_end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1137,13 +1146,15 @@ testWallet_sendGrams::testWallet_sendGrams()
|
|||||||
, destination_()
|
, destination_()
|
||||||
, seqno_()
|
, seqno_()
|
||||||
, amount_()
|
, amount_()
|
||||||
|
, message_()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
testWallet_sendGrams::testWallet_sendGrams(object_ptr<inputKey> &&private_key_, object_ptr<accountAddress> &&destination_, std::int32_t seqno_, std::int64_t amount_)
|
testWallet_sendGrams::testWallet_sendGrams(object_ptr<inputKey> &&private_key_, object_ptr<accountAddress> &&destination_, std::int32_t seqno_, std::int64_t amount_, std::string const &message_)
|
||||||
: private_key_(std::move(private_key_))
|
: private_key_(std::move(private_key_))
|
||||||
, destination_(std::move(destination_))
|
, destination_(std::move(destination_))
|
||||||
, seqno_(seqno_)
|
, seqno_(seqno_)
|
||||||
, amount_(amount_)
|
, amount_(amount_)
|
||||||
|
, message_(std::move(message_))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
const std::int32_t testWallet_sendGrams::ID;
|
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"); }
|
if (destination_ == nullptr) { s.store_field("destination", "null"); } else { destination_->store(s, "destination"); }
|
||||||
s.store_field("seqno", seqno_);
|
s.store_field("seqno", seqno_);
|
||||||
s.store_field("amount", amount_);
|
s.store_field("amount", amount_);
|
||||||
|
s.store_bytes_field("message", message_);
|
||||||
s.store_class_end();
|
s.store_class_end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -442,12 +442,13 @@ class raw_message final : public Object {
|
|||||||
std::string source_;
|
std::string source_;
|
||||||
std::string destination_;
|
std::string destination_;
|
||||||
std::int64_t value_;
|
std::int64_t value_;
|
||||||
|
std::string message_;
|
||||||
|
|
||||||
raw_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 {
|
std::int32_t get_id() const final {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
@ -717,12 +718,13 @@ class generic_sendGrams final : public Function {
|
|||||||
object_ptr<accountAddress> source_;
|
object_ptr<accountAddress> source_;
|
||||||
object_ptr<accountAddress> destination_;
|
object_ptr<accountAddress> destination_;
|
||||||
std::int64_t amount_;
|
std::int64_t amount_;
|
||||||
|
std::string message_;
|
||||||
|
|
||||||
generic_sendGrams();
|
generic_sendGrams();
|
||||||
|
|
||||||
generic_sendGrams(object_ptr<inputKey> &&private_key_, object_ptr<accountAddress> &&source_, object_ptr<accountAddress> &&destination_, std::int64_t amount_);
|
generic_sendGrams(object_ptr<inputKey> &&private_key_, object_ptr<accountAddress> &&source_, object_ptr<accountAddress> &&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 {
|
std::int32_t get_id() const final {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
@ -1012,12 +1014,13 @@ class testGiver_sendGrams final : public Function {
|
|||||||
object_ptr<accountAddress> destination_;
|
object_ptr<accountAddress> destination_;
|
||||||
std::int32_t seqno_;
|
std::int32_t seqno_;
|
||||||
std::int64_t amount_;
|
std::int64_t amount_;
|
||||||
|
std::string message_;
|
||||||
|
|
||||||
testGiver_sendGrams();
|
testGiver_sendGrams();
|
||||||
|
|
||||||
testGiver_sendGrams(object_ptr<accountAddress> &&destination_, std::int32_t seqno_, std::int64_t amount_);
|
testGiver_sendGrams(object_ptr<accountAddress> &&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 {
|
std::int32_t get_id() const final {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
@ -1087,12 +1090,13 @@ class testWallet_sendGrams final : public Function {
|
|||||||
object_ptr<accountAddress> destination_;
|
object_ptr<accountAddress> destination_;
|
||||||
std::int32_t seqno_;
|
std::int32_t seqno_;
|
||||||
std::int64_t amount_;
|
std::int64_t amount_;
|
||||||
|
std::string message_;
|
||||||
|
|
||||||
testWallet_sendGrams();
|
testWallet_sendGrams();
|
||||||
|
|
||||||
testWallet_sendGrams(object_ptr<inputKey> &&private_key_, object_ptr<accountAddress> &&destination_, std::int32_t seqno_, std::int64_t amount_);
|
testWallet_sendGrams(object_ptr<inputKey> &&private_key_, object_ptr<accountAddress> &&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 {
|
std::int32_t get_id() const final {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,7 +60,7 @@ Result<int32> tl_constructor_from_string(tonlib_api::Object *object, const std::
|
|||||||
{"internal.transactionId", -989527262},
|
{"internal.transactionId", -989527262},
|
||||||
{"raw.accountState", 461615898},
|
{"raw.accountState", 461615898},
|
||||||
{"raw.initialAccountState", 777456197},
|
{"raw.initialAccountState", 777456197},
|
||||||
{"raw.message", -1131081640},
|
{"raw.message", -259956097},
|
||||||
{"raw.transaction", -1159530820},
|
{"raw.transaction", -1159530820},
|
||||||
{"raw.transactions", 240548986},
|
{"raw.transactions", 240548986},
|
||||||
{"testGiver.accountState", 860930426},
|
{"testGiver.accountState", 860930426},
|
||||||
@ -84,7 +84,7 @@ Result<int32> tl_constructor_from_string(tonlib_api::Function *object, const std
|
|||||||
{"exportKey", 399723440},
|
{"exportKey", 399723440},
|
||||||
{"exportPemKey", -2047752448},
|
{"exportPemKey", -2047752448},
|
||||||
{"generic.getAccountState", -657000446},
|
{"generic.getAccountState", -657000446},
|
||||||
{"generic.sendGrams", 799772985},
|
{"generic.sendGrams", 1523427648},
|
||||||
{"getBip39Hints", -1889640982},
|
{"getBip39Hints", -1889640982},
|
||||||
{"importEncryptedKey", 656724958},
|
{"importEncryptedKey", 656724958},
|
||||||
{"importKey", -1607900903},
|
{"importKey", -1607900903},
|
||||||
@ -100,11 +100,11 @@ Result<int32> tl_constructor_from_string(tonlib_api::Function *object, const std
|
|||||||
{"runTests", -2039925427},
|
{"runTests", -2039925427},
|
||||||
{"testGiver.getAccountAddress", -540100768},
|
{"testGiver.getAccountAddress", -540100768},
|
||||||
{"testGiver.getAccountState", 267738275},
|
{"testGiver.getAccountState", 267738275},
|
||||||
{"testGiver.sendGrams", -178493799},
|
{"testGiver.sendGrams", -1361914347},
|
||||||
{"testWallet.getAccountAddress", -1557748223},
|
{"testWallet.getAccountAddress", -1557748223},
|
||||||
{"testWallet.getAccountState", 654082364},
|
{"testWallet.getAccountState", 654082364},
|
||||||
{"testWallet.init", 419055225},
|
{"testWallet.init", 419055225},
|
||||||
{"testWallet.sendGrams", -1716705044}
|
{"testWallet.sendGrams", 43200674}
|
||||||
};
|
};
|
||||||
auto it = m.find(str);
|
auto it = m.find(str);
|
||||||
if (it == m.end()) {
|
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_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();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
Status from_json(tonlib_api::raw_transaction &to, JsonObject &from) {
|
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_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();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
Status from_json(tonlib_api::getBip39Hints &to, JsonObject &from) {
|
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_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();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
Status from_json(tonlib_api::testWallet_getAccountAddress &to, JsonObject &from) {
|
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_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();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
void to_json(JsonValueScope &jv, const tonlib_api::accountAddress &object) {
|
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("source", ToJson(object.source_));
|
||||||
jo << ctie("destination", ToJson(object.destination_));
|
jo << ctie("destination", ToJson(object.destination_));
|
||||||
jo << ctie("value", ToJson(JsonInt64{object.value_}));
|
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) {
|
void to_json(JsonValueScope &jv, const tonlib_api::raw_transaction &object) {
|
||||||
auto jo = jv.enter_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("destination", ToJson(object.destination_));
|
||||||
}
|
}
|
||||||
jo << ctie("amount", ToJson(JsonInt64{object.amount_}));
|
jo << ctie("amount", ToJson(JsonInt64{object.amount_}));
|
||||||
|
jo << ctie("message", ToJson(JsonBytes{object.message_}));
|
||||||
}
|
}
|
||||||
void to_json(JsonValueScope &jv, const tonlib_api::getBip39Hints &object) {
|
void to_json(JsonValueScope &jv, const tonlib_api::getBip39Hints &object) {
|
||||||
auto jo = jv.enter_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("seqno", ToJson(object.seqno_));
|
||||||
jo << ctie("amount", ToJson(JsonInt64{object.amount_}));
|
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) {
|
void to_json(JsonValueScope &jv, const tonlib_api::testWallet_getAccountAddress &object) {
|
||||||
auto jo = jv.enter_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("seqno", ToJson(object.seqno_));
|
||||||
jo << ctie("amount", ToJson(JsonInt64{object.amount_}));
|
jo << ctie("amount", ToJson(JsonInt64{object.amount_}));
|
||||||
|
jo << ctie("message", ToJson(JsonBytes{object.message_}));
|
||||||
}
|
}
|
||||||
} // namespace tonlib_api
|
} // namespace tonlib_api
|
||||||
} // namespace ton
|
} // namespace ton
|
||||||
|
|||||||
@ -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.fullNodeSlave ip:int port:int adnl:PublicKey = engine.validator.FullNodeSlave;
|
||||||
engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector engine.adnl)
|
engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector engine.adnl)
|
||||||
dht:(vector engine.dht)
|
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)
|
fullnodemasters:(vector engine.validator.fullNodeMaster)
|
||||||
liteservers:(vector engine.liteServer) control:(vector engine.controlInterface)
|
liteservers:(vector engine.liteServer) control:(vector engine.controlInterface)
|
||||||
gc:engine.gc = engine.validator.Config;
|
gc:engine.gc = engine.validator.Config;
|
||||||
|
|||||||
Binary file not shown.
@ -32,7 +32,7 @@ internal.transactionId lt:int64 hash:bytes = internal.TransactionId;
|
|||||||
|
|
||||||
raw.initialAccountState code:bytes data:bytes = raw.InitialAccountState;
|
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.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.message> = raw.Transaction;
|
raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 in_msg:raw.message out_msgs:vector<raw.message> = raw.Transaction;
|
||||||
raw.transactions transactions:vector<raw.Transaction> previous_transaction_id:internal.transactionId = raw.Transactions;
|
raw.transactions transactions:vector<raw.Transaction> 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.init private_key:inputKey = Ok;
|
||||||
testWallet.getAccountAddress initital_account_state:testWallet.initialAccountState = AccountAddress;
|
testWallet.getAccountAddress initital_account_state:testWallet.initialAccountState = AccountAddress;
|
||||||
testWallet.getAccountState account_address:accountAddress = testWallet.AccountState;
|
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.getAccountState = testGiver.AccountState;
|
||||||
testGiver.getAccountAddress = AccountAddress;
|
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.getAccountAddress initital_account_state:generic.InitialAccountState = AccountAddress;
|
||||||
generic.getAccountState account_address:accountAddress = generic.AccountState;
|
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;
|
onLiteServerQueryResult id:int64 bytes:bytes = Ok;
|
||||||
onLiteServerQueryError id:int64 error:error = Ok;
|
onLiteServerQueryError id:int64 error:error = Ok;
|
||||||
|
|||||||
Binary file not shown.
@ -13,6 +13,7 @@ set(TONLIB_SOURCE
|
|||||||
tonlib/GenericAccount.cpp
|
tonlib/GenericAccount.cpp
|
||||||
tonlib/KeyStorage.cpp
|
tonlib/KeyStorage.cpp
|
||||||
tonlib/LastBlock.cpp
|
tonlib/LastBlock.cpp
|
||||||
|
tonlib/LastBlockStorage.cpp
|
||||||
tonlib/TestGiver.cpp
|
tonlib/TestGiver.cpp
|
||||||
tonlib/TestWallet.cpp
|
tonlib/TestWallet.cpp
|
||||||
tonlib/TonlibClient.cpp
|
tonlib/TonlibClient.cpp
|
||||||
@ -26,6 +27,7 @@ set(TONLIB_SOURCE
|
|||||||
tonlib/GenericAccount.h
|
tonlib/GenericAccount.h
|
||||||
tonlib/KeyStorage.h
|
tonlib/KeyStorage.h
|
||||||
tonlib/LastBlock.h
|
tonlib/LastBlock.h
|
||||||
|
tonlib/LastBlockStorage.h
|
||||||
tonlib/TestGiver.h
|
tonlib/TestGiver.h
|
||||||
tonlib/TestWallet.h
|
tonlib/TestWallet.h
|
||||||
tonlib/TonlibCallback.h
|
tonlib/TonlibCallback.h
|
||||||
|
|||||||
Binary file not shown.
@ -127,8 +127,8 @@ TEST(Tonlib, TestGiver) {
|
|||||||
|
|
||||||
auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data;
|
auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data;
|
||||||
|
|
||||||
auto res = GenericAccount::create_ext_message(TestGiver::address(), {},
|
auto res = GenericAccount::create_ext_message(
|
||||||
TestGiver::make_a_gift_message(0, 1000000000ll * 6666 / 1000, address));
|
TestGiver::address(), {}, TestGiver::make_a_gift_message(0, 1000000000ll * 6666 / 1000, "GIFT", address));
|
||||||
vm::CellSlice(vm::NoVm(), res).print_rec(std::cerr);
|
vm::CellSlice(vm::NoVm(), res).print_rec(std::cerr);
|
||||||
CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == res->get_hash());
|
CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == res->get_hash());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -118,7 +118,7 @@ void transfer_grams(Client& client, std::string from, std::string to, td::int64
|
|||||||
auto balance = get_balance(client, to);
|
auto balance = get_balance(client, to);
|
||||||
sync_send(client, tonlib_api::make_object<tonlib_api::generic_sendGrams>(
|
sync_send(client, tonlib_api::make_object<tonlib_api::generic_sendGrams>(
|
||||||
std::move(input_key), tonlib_api::make_object<tonlib_api::accountAddress>(from),
|
std::move(input_key), tonlib_api::make_object<tonlib_api::accountAddress>(from),
|
||||||
tonlib_api::make_object<tonlib_api::accountAddress>(to), amount))
|
tonlib_api::make_object<tonlib_api::accountAddress>(to), amount, "GIFT"))
|
||||||
.ensure();
|
.ensure();
|
||||||
while (balance == get_balance(client, to)) {
|
while (balance == get_balance(client, to)) {
|
||||||
client.receive(1);
|
client.receive(1);
|
||||||
@ -270,7 +270,7 @@ int main(int argc, char* argv[]) {
|
|||||||
{
|
{
|
||||||
sync_send(client, make_object<tonlib_api::testGiver_sendGrams>(
|
sync_send(client, make_object<tonlib_api::testGiver_sendGrams>(
|
||||||
make_object<tonlib_api::accountAddress>(wallet_addr.rserialize()), seqno,
|
make_object<tonlib_api::accountAddress>(wallet_addr.rserialize()), seqno,
|
||||||
1000000000ll * 6666 / 1000))
|
1000000000ll * 6666 / 1000, "GIFT"))
|
||||||
.ensure();
|
.ensure();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,9 +307,10 @@ int main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
sync_send(client, make_object<tonlib_api::generic_sendGrams>(
|
sync_send(client,
|
||||||
create_input_key(), make_object<tonlib_api::accountAddress>(wallet_addr.rserialize()),
|
make_object<tonlib_api::generic_sendGrams>(
|
||||||
make_object<tonlib_api::accountAddress>(test_giver_address), 1000000000ll * 3333 / 1000))
|
create_input_key(), make_object<tonlib_api::accountAddress>(wallet_addr.rserialize()),
|
||||||
|
make_object<tonlib_api::accountAddress>(test_giver_address), 1000000000ll * 3333 / 1000, "GIFT"))
|
||||||
.ensure();
|
.ensure();
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tonlib/LastBlock.h"
|
|
||||||
|
|
||||||
namespace tonlib {
|
|
||||||
class BlockchainInfoStorage {
|
|
||||||
td::Status set_directory(std::string directory);
|
|
||||||
td::Result<LastBlock::State> get_state(ZeroStateIdExt);
|
|
||||||
void save_state(LastBlock::State state);
|
|
||||||
};
|
|
||||||
} // namespace tonlib
|
|
||||||
@ -21,10 +21,10 @@
|
|||||||
#include "tonlib/LastBlock.h"
|
#include "tonlib/LastBlock.h"
|
||||||
|
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
void ExtClient::with_last_block(td::Promise<LastBlockInfo> promise) {
|
void ExtClient::with_last_block(td::Promise<LastBlockState> promise) {
|
||||||
auto query_id = last_block_queries_.create(std::move(promise));
|
auto query_id = last_block_queries_.create(std::move(promise));
|
||||||
td::Promise<LastBlockInfo> P = [query_id, self = this,
|
td::Promise<LastBlockState> P = [query_id, self = this,
|
||||||
actor_id = td::actor::actor_id()](td::Result<LastBlockInfo> result) {
|
actor_id = td::actor::actor_id()](td::Result<LastBlockState> result) {
|
||||||
send_lambda(actor_id, [self, query_id, result = std::move(result)]() mutable {
|
send_lambda(actor_id, [self, query_id, result = std::move(result)]() mutable {
|
||||||
self->last_block_queries_.extract(query_id).set_result(std::move(result));
|
self->last_block_queries_.extract(query_id).set_result(std::move(result));
|
||||||
});
|
});
|
||||||
|
|||||||
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
class LastBlock;
|
class LastBlock;
|
||||||
struct LastBlockInfo;
|
struct LastBlockState;
|
||||||
struct ExtClientRef {
|
struct ExtClientRef {
|
||||||
td::actor::ActorId<ton::adnl::AdnlExtClient> andl_ext_client_;
|
td::actor::ActorId<ton::adnl::AdnlExtClient> andl_ext_client_;
|
||||||
td::actor::ActorId<LastBlock> last_block_actor_;
|
td::actor::ActorId<LastBlock> last_block_actor_;
|
||||||
@ -50,7 +50,7 @@ class ExtClient {
|
|||||||
return client_;
|
return client_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void with_last_block(td::Promise<LastBlockInfo> promise);
|
void with_last_block(td::Promise<LastBlockState> promise);
|
||||||
|
|
||||||
template <class QueryT>
|
template <class QueryT>
|
||||||
void send_query(QueryT query, td::Promise<typename QueryT::ReturnType> promise) {
|
void send_query(QueryT query, td::Promise<typename QueryT::ReturnType> promise) {
|
||||||
@ -75,7 +75,7 @@ class ExtClient {
|
|||||||
private:
|
private:
|
||||||
ExtClientRef client_;
|
ExtClientRef client_;
|
||||||
td::Container<td::Promise<td::BufferSlice>> queries_;
|
td::Container<td::Promise<td::BufferSlice>> queries_;
|
||||||
td::Container<td::Promise<LastBlockInfo>> last_block_queries_;
|
td::Container<td::Promise<LastBlockState>> last_block_queries_;
|
||||||
|
|
||||||
void send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise);
|
void send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -28,7 +28,7 @@ td::Ref<vm::Cell> GenericAccount::get_init_state(td::Ref<vm::Cell> code, td::Ref
|
|||||||
.finalize();
|
.finalize();
|
||||||
}
|
}
|
||||||
block::StdAddress GenericAccount::get_address(ton::WorkchainId workchain_id, const td::Ref<vm::Cell>& init_state) {
|
block::StdAddress GenericAccount::get_address(ton::WorkchainId workchain_id, const td::Ref<vm::Cell>& 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<vm::Cell> GenericAccount::create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
td::Ref<vm::Cell> GenericAccount::create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
||||||
td::Ref<vm::Cell> body) {
|
td::Ref<vm::Cell> body) {
|
||||||
|
|||||||
@ -23,13 +23,23 @@
|
|||||||
#include "lite-client/lite-client-common.h"
|
#include "lite-client/lite-client-common.h"
|
||||||
|
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
LastBlock::LastBlock(ExtClientRef client, State state, td::unique_ptr<Callback> 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> callback)
|
||||||
: state_(std::move(state)), callback_(std::move(callback)) {
|
: state_(std::move(state)), callback_(std::move(callback)) {
|
||||||
client_.set_client(client);
|
client_.set_client(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastBlock::get_last_block(td::Promise<LastBlockInfo> promise) {
|
void LastBlock::get_last_block(td::Promise<LastBlockState> promise) {
|
||||||
if (promises_.empty()) {
|
if (promises_.empty()) {
|
||||||
|
total_sync_ = td::Timer();
|
||||||
|
validate_ = td::Timer(true);
|
||||||
|
queries_ = 0;
|
||||||
|
LOG(INFO) << "Begin last block synchronization " << state_;
|
||||||
do_get_last_block();
|
do_get_last_block();
|
||||||
}
|
}
|
||||||
promises_.push_back(std::move(promise));
|
promises_.push_back(std::move(promise));
|
||||||
@ -41,6 +51,7 @@ void LastBlock::do_get_last_block() {
|
|||||||
//return;
|
//return;
|
||||||
|
|
||||||
//liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof;
|
//liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof;
|
||||||
|
queries_++;
|
||||||
client_.send_query(
|
client_.send_query(
|
||||||
ton::lite_api::liteServer_getBlockProof(0, create_tl_lite_block_id(state_.last_key_block_id), nullptr),
|
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) {
|
[this, from = state_.last_key_block_id](auto r_block_proof) {
|
||||||
@ -51,21 +62,30 @@ void LastBlock::do_get_last_block() {
|
|||||||
td::Result<bool> LastBlock::process_block_proof(
|
td::Result<bool> LastBlock::process_block_proof(
|
||||||
ton::BlockIdExt from,
|
ton::BlockIdExt from,
|
||||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
||||||
|
validate_.resume();
|
||||||
|
SCOPE_EXIT {
|
||||||
|
validate_.pause();
|
||||||
|
};
|
||||||
|
|
||||||
TRY_RESULT(block_proof, std::move(r_block_proof));
|
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)));
|
TRY_RESULT(chain, liteclient::deserialize_proof_chain(std::move(block_proof)));
|
||||||
if (chain->from != from) {
|
if (chain->from != from) {
|
||||||
return td::Status::Error(PSLICE() << "block proof chain starts from block " << chain->from.to_str()
|
return td::Status::Error(PSLICE() << "block proof chain starts from block " << chain->from.to_str()
|
||||||
<< ", not from requested block " << from.to_str());
|
<< ", not from requested block " << from.to_str());
|
||||||
}
|
}
|
||||||
TRY_STATUS(chain->validate());
|
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) {
|
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) {
|
if (chain->has_utime) {
|
||||||
update_utime(chain->last_utime);
|
update_utime(chain->last_utime);
|
||||||
}
|
}
|
||||||
|
if (is_changed) {
|
||||||
|
callback_->on_state_changed(state_);
|
||||||
|
}
|
||||||
return chain->complete;
|
return chain->complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,17 +93,20 @@ void LastBlock::on_block_proof(
|
|||||||
ton::BlockIdExt from,
|
ton::BlockIdExt from,
|
||||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
||||||
auto r_is_ready = process_block_proof(from, std::move(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()) {
|
if (r_is_ready.is_error()) {
|
||||||
LOG(WARNING) << "Failed liteServer_getBlockProof " << r_is_ready.error();
|
LOG(WARNING) << "Error during last block synchronization " << r_is_ready.error();
|
||||||
return;
|
is_ready = true;
|
||||||
|
} else {
|
||||||
|
is_ready = r_is_ready.move_as_ok();
|
||||||
}
|
}
|
||||||
auto is_ready = r_is_ready.move_as_ok();
|
|
||||||
if (is_ready) {
|
if (is_ready) {
|
||||||
|
LOG(INFO) << "End last block synchronization " << state_ << "\n"
|
||||||
|
<< " net queries: " << queries_ << "\n"
|
||||||
|
<< " total: " << total_sync_ << " validation: " << validate_;
|
||||||
for (auto& promise : promises_) {
|
for (auto& promise : promises_) {
|
||||||
LastBlockInfo res;
|
auto state = state_;
|
||||||
res.id = state_.last_block_id;
|
promise.set_value(std::move(state));
|
||||||
res.utime = state_.utime;
|
|
||||||
promise.set_value(std::move(res));
|
|
||||||
}
|
}
|
||||||
promises_.clear();
|
promises_.clear();
|
||||||
} else {
|
} else {
|
||||||
@ -101,10 +124,8 @@ void LastBlock::on_masterchain_info(
|
|||||||
LOG(WARNING) << "Failed liteServer_getMasterchainInfo " << r_info.error();
|
LOG(WARNING) << "Failed liteServer_getMasterchainInfo " << r_info.error();
|
||||||
}
|
}
|
||||||
for (auto& promise : promises_) {
|
for (auto& promise : promises_) {
|
||||||
LastBlockInfo res;
|
auto state = state_;
|
||||||
res.id = state_.last_block_id;
|
promise.set_value(std::move(state));
|
||||||
res.utime = state_.utime;
|
|
||||||
promise.set_value(std::move(res));
|
|
||||||
}
|
}
|
||||||
promises_.clear();
|
promises_.clear();
|
||||||
}
|
}
|
||||||
@ -131,25 +152,30 @@ void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id) {
|
|||||||
// One will have to restart ton client
|
// 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()) {
|
if (!mc_block_id.is_valid()) {
|
||||||
LOG(ERROR) << "Ignore invalid masterchain block";
|
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) {
|
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;
|
state_.last_block_id = mc_block_id;
|
||||||
LOG(INFO) << "Update masterchain block id: " << state_.last_block_id.to_str();
|
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()) {
|
if (!mc_key_block_id.is_valid()) {
|
||||||
LOG(ERROR) << "Ignore invalid masterchain block";
|
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) {
|
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;
|
state_.last_key_block_id = mc_key_block_id;
|
||||||
LOG(INFO) << "Update masterchain key block id: " << state_.last_key_block_id.to_str();
|
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) {
|
void LastBlock::update_utime(td::int64 utime) {
|
||||||
|
|||||||
@ -22,35 +22,114 @@
|
|||||||
#include "tonlib/ExtClient.h"
|
#include "tonlib/ExtClient.h"
|
||||||
|
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
struct LastBlockInfo {
|
td::StringBuilder &operator<<(td::StringBuilder &sb, const LastBlockState &state);
|
||||||
ton::BlockIdExt id;
|
template <unsigned int N, class StorerT>
|
||||||
|
void store(const td::BitArray<N> &arr, StorerT &storer) {
|
||||||
|
storer.store_binary(arr);
|
||||||
|
}
|
||||||
|
template <unsigned int N, class ParserT>
|
||||||
|
void parse(td::BitArray<N> &arr, ParserT &parser) {
|
||||||
|
arr = parser.template fetch_binary<td::BitArray<N>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class StorerT>
|
||||||
|
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 <class ParserT>
|
||||||
|
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 <class StorerT>
|
||||||
|
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 <class ParserT>
|
||||||
|
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 <class StorerT>
|
||||||
|
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 <class ParserT>
|
||||||
|
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};
|
td::int64 utime{0};
|
||||||
|
|
||||||
|
template <class StorerT>
|
||||||
|
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 <class ParserT>
|
||||||
|
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 {
|
class LastBlock : public td::actor::Actor {
|
||||||
public:
|
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 {
|
class Callback {
|
||||||
public:
|
public:
|
||||||
virtual ~Callback() {
|
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> callback);
|
explicit LastBlock(ExtClientRef client, LastBlockState state, td::unique_ptr<Callback> callback);
|
||||||
void get_last_block(td::Promise<LastBlockInfo> promise);
|
void get_last_block(td::Promise<LastBlockState> promise);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ExtClient client_;
|
ExtClient client_;
|
||||||
State state_;
|
LastBlockState state_;
|
||||||
td::unique_ptr<Callback> callback_;
|
td::unique_ptr<Callback> callback_;
|
||||||
|
|
||||||
std::vector<td::Promise<LastBlockInfo>> promises_;
|
// stats
|
||||||
|
td::Timer total_sync_;
|
||||||
|
td::Timer validate_;
|
||||||
|
td::uint32 queries_;
|
||||||
|
|
||||||
|
std::vector<td::Promise<LastBlockState>> promises_;
|
||||||
|
|
||||||
void do_get_last_block();
|
void do_get_last_block();
|
||||||
void on_masterchain_info(td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_masterchainInfo>> r_info);
|
void on_masterchain_info(td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_masterchainInfo>> r_info);
|
||||||
@ -62,8 +141,8 @@ class LastBlock : public td::actor::Actor {
|
|||||||
|
|
||||||
void update_zero_state(ton::ZeroStateIdExt zero_state_id);
|
void update_zero_state(ton::ZeroStateIdExt zero_state_id);
|
||||||
|
|
||||||
void update_mc_last_block(ton::BlockIdExt mc_block_id);
|
bool 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_key_block(ton::BlockIdExt mc_key_block_id);
|
||||||
void update_utime(td::int64 utime);
|
void update_utime(td::int64 utime);
|
||||||
};
|
};
|
||||||
} // namespace tonlib
|
} // namespace tonlib
|
||||||
|
|||||||
44
submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.cpp
Normal file
44
submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.cpp
Normal file
@ -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<LastBlockState> 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<td::uint64>(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::uint64>(td::MutableSlice(y).data()) = td::crc64(x);
|
||||||
|
td::atomic_write_file(get_file_name(name), y);
|
||||||
|
}
|
||||||
|
} // namespace tonlib
|
||||||
16
submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.h
Normal file
16
submodules/ton/tonlib-src/tonlib/tonlib/LastBlockStorage.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "tonlib/LastBlock.h"
|
||||||
|
|
||||||
|
namespace tonlib {
|
||||||
|
class LastBlockStorage {
|
||||||
|
public:
|
||||||
|
td::Status set_directory(std::string directory);
|
||||||
|
td::Result<LastBlockState> 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
|
||||||
@ -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());
|
return vm::CellHash::from_slice(td::base64_decode("wDkZp0yR4xo+9+BnuAPfGVjBzK6FPzqdv2DwRq3z3KE=").move_as_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Ref<vm::Cell> TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms,
|
td::Ref<vm::Cell> TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message,
|
||||||
const block::StdAddress& dest_address) {
|
const block::StdAddress& dest_address) {
|
||||||
|
CHECK(message.size() <= 128);
|
||||||
td::BigInt256 dest_addr;
|
td::BigInt256 dest_addr;
|
||||||
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
||||||
vm::CellBuilder cb;
|
vm::CellBuilder cb;
|
||||||
@ -44,7 +45,7 @@ td::Ref<vm::Cell> TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gr
|
|||||||
.store_int256(dest_addr, 256);
|
.store_int256(dest_addr, 256);
|
||||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
|
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();
|
return vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).finalize();
|
||||||
}
|
}
|
||||||
} // namespace tonlib
|
} // namespace tonlib
|
||||||
|
|||||||
@ -23,7 +23,7 @@ class TestGiver {
|
|||||||
public:
|
public:
|
||||||
static const block::StdAddress& address();
|
static const block::StdAddress& address();
|
||||||
static vm::CellHash get_init_code_hash();
|
static vm::CellHash get_init_code_hash();
|
||||||
static td::Ref<vm::Cell> make_a_gift_message(td::uint32 seqno, td::uint64 gramms,
|
static td::Ref<vm::Cell> make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message,
|
||||||
const block::StdAddress& dest_address);
|
const block::StdAddress& dest_address);
|
||||||
};
|
};
|
||||||
} // namespace tonlib
|
} // namespace tonlib
|
||||||
|
|||||||
@ -38,7 +38,9 @@ td::Ref<vm::Cell> TestWallet::get_init_message(const td::Ed25519::PrivateKey& pr
|
|||||||
}
|
}
|
||||||
|
|
||||||
td::Ref<vm::Cell> TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
td::Ref<vm::Cell> 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;
|
td::BigInt256 dest_addr;
|
||||||
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
||||||
vm::CellBuilder cb;
|
vm::CellBuilder cb;
|
||||||
@ -46,11 +48,11 @@ td::Ref<vm::Cell> TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey&
|
|||||||
.store_long(dest_address.workchain, 8)
|
.store_long(dest_address.workchain, 8)
|
||||||
.store_int256(dest_addr, 256);
|
.store_int256(dest_addr, 256);
|
||||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
|
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();
|
||||||
auto message = vm::CellBuilder().store_long(seqno, 32).store_long(1, 8).store_ref(message_inner).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);
|
std::string seq_no(4, 0);
|
||||||
auto signature = private_key.sign(message->get_hash().as_slice()).move_as_ok();
|
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)).finalize();
|
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Ref<vm::Cell> TestWallet::get_init_code() {
|
td::Ref<vm::Cell> TestWallet::get_init_code() {
|
||||||
|
|||||||
@ -28,7 +28,8 @@ class TestWallet {
|
|||||||
static td::Ref<vm::Cell> get_init_state(const td::Ed25519::PublicKey& public_key);
|
static td::Ref<vm::Cell> get_init_state(const td::Ed25519::PublicKey& public_key);
|
||||||
static td::Ref<vm::Cell> get_init_message(const td::Ed25519::PrivateKey& private_key);
|
static td::Ref<vm::Cell> get_init_message(const td::Ed25519::PrivateKey& private_key);
|
||||||
static td::Ref<vm::Cell> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
static td::Ref<vm::Cell> 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<vm::Cell> get_init_code();
|
static td::Ref<vm::Cell> get_init_code();
|
||||||
static vm::CellHash get_init_code_hash();
|
static vm::CellHash get_init_code_hash();
|
||||||
|
|||||||
@ -41,8 +41,6 @@
|
|||||||
#include "td/utils/tests.h"
|
#include "td/utils/tests.h"
|
||||||
#include "td/utils/port/path.h"
|
#include "td/utils/port/path.h"
|
||||||
|
|
||||||
namespace ton {} // namespace ton
|
|
||||||
|
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
|
|
||||||
template <class F>
|
template <class F>
|
||||||
@ -152,6 +150,11 @@ class GetTransactionHistory : public td::actor::Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void start_up() override {
|
void start_up() override {
|
||||||
|
if (lt_ == 0) {
|
||||||
|
promise_.set_value(block::TransactionList::Info());
|
||||||
|
stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
client_.send_query(
|
client_.send_query(
|
||||||
ton::lite_api::liteServer_getTransactions(
|
ton::lite_api::liteServer_getTransactions(
|
||||||
count_, ton::create_tl_object<ton::lite_api::liteServer_accountId>(address_.workchain, address_.addr), lt_,
|
count_, ton::create_tl_object<ton::lite_api::liteServer_accountId>(address_.workchain, address_.addr), lt_,
|
||||||
@ -171,7 +174,7 @@ class GetRawAccountState : public td::actor::Actor {
|
|||||||
block::StdAddress address_;
|
block::StdAddress address_;
|
||||||
td::Promise<RawAccountState> promise_;
|
td::Promise<RawAccountState> promise_;
|
||||||
ExtClient client_;
|
ExtClient client_;
|
||||||
LastBlockInfo last_block_;
|
LastBlockState last_block_;
|
||||||
|
|
||||||
void with_account_state(td::Result<ton::tl_object_ptr<ton::lite_api::liteServer_accountState>> r_account_state) {
|
void with_account_state(td::Result<ton::tl_object_ptr<ton::lite_api::liteServer_accountState>> r_account_state) {
|
||||||
promise_.set_result(TRY_VM(do_with_account_state(std::move(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<ton::tl_object_ptr<ton::lite_api::liteServer_accountState>> r_account_state) {
|
td::Result<ton::tl_object_ptr<ton::lite_api::liteServer_accountState>> r_account_state) {
|
||||||
TRY_RESULT(raw_account_state, std::move(r_account_state));
|
TRY_RESULT(raw_account_state, std::move(r_account_state));
|
||||||
auto account_state = create_account_state(std::move(raw_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();
|
auto serialized_state = account_state.state.clone();
|
||||||
RawAccountState res;
|
RawAccountState res;
|
||||||
res.info = std::move(info);
|
res.info = std::move(info);
|
||||||
@ -225,14 +228,14 @@ class GetRawAccountState : public td::actor::Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void start_up() override {
|
void start_up() override {
|
||||||
client_.with_last_block([self = this](td::Result<LastBlockInfo> r_last_block) {
|
client_.with_last_block([self = this](td::Result<LastBlockState> r_last_block) {
|
||||||
if (r_last_block.is_error()) {
|
if (r_last_block.is_error()) {
|
||||||
return self->check(r_last_block.move_as_error());
|
return self->check(r_last_block.move_as_error());
|
||||||
}
|
}
|
||||||
self->last_block_ = r_last_block.move_as_ok();
|
self->last_block_ = r_last_block.move_as_ok();
|
||||||
|
|
||||||
self->client_.send_query(
|
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<ton::lite_api::liteServer_accountId>(
|
ton::create_tl_object<ton::lite_api::liteServer_accountId>(
|
||||||
self->address_.workchain, self->address_.addr)),
|
self->address_.workchain, self->address_.addr)),
|
||||||
[self](auto r_state) { self->with_account_state(std::move(r_state)); });
|
[self](auto r_state) { self->with_account_state(std::move(r_state)); });
|
||||||
@ -307,24 +310,36 @@ void TonlibClient::init_ext_client() {
|
|||||||
td::make_unique<Callback>(td::actor::actor_shared()));
|
td::make_unique<Callback>(td::actor::actor_shared()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TonlibClient::update_last_block_state(LastBlockState state) {
|
||||||
|
last_block_storage_.save_state("none", state);
|
||||||
|
}
|
||||||
|
|
||||||
void TonlibClient::init_last_block() {
|
void TonlibClient::init_last_block() {
|
||||||
ref_cnt_++;
|
ref_cnt_++;
|
||||||
class Callback : public LastBlock::Callback {
|
class Callback : public LastBlock::Callback {
|
||||||
public:
|
public:
|
||||||
Callback(td::actor::ActorShared<TonlibClient> client) : client_(std::move(client)) {
|
Callback(td::actor::ActorShared<TonlibClient> client) : client_(std::move(client)) {
|
||||||
}
|
}
|
||||||
void on_state_changes(LastBlock::State state) override {
|
void on_state_changed(LastBlockState state) override {
|
||||||
//TODO
|
send_closure(client_, &TonlibClient::update_last_block_state, std::move(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
td::actor::ActorShared<TonlibClient> client_;
|
td::actor::ActorShared<TonlibClient> client_;
|
||||||
};
|
};
|
||||||
LastBlock::State state;
|
LastBlockState 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),
|
auto r_state = last_block_storage_.get_state("none");
|
||||||
state.last_block_id = config_.zero_state_id;
|
if (r_state.is_error()) {
|
||||||
state.last_key_block_id = config_.zero_state_id;
|
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>("LastBlock", get_client_ref(), std::move(state),
|
raw_last_block_ = td::actor::create_actor<LastBlock>("LastBlock", get_client_ref(), std::move(state),
|
||||||
td::make_unique<Callback>(td::actor::actor_shared(this)));
|
td::make_unique<Callback>(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");
|
return td::Status::Error(400, "Field options must not be empty");
|
||||||
}
|
}
|
||||||
TRY_STATUS(key_storage_.set_directory(request.options_->keystore_directory_));
|
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_;
|
use_callbacks_for_network_ = request.options_->use_callbacks_for_network_;
|
||||||
if (!request.options_->config_.empty()) {
|
if (!request.options_->config_.empty()) {
|
||||||
TRY_STATUS(set_config(std::move(request.options_->config_)));
|
TRY_STATUS(set_config(std::move(request.options_->config_)));
|
||||||
@ -570,10 +586,25 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_message>> to_raw_message_or_th
|
|||||||
if (!tlb::csr_unpack(message.info, msg_info)) {
|
if (!tlb::csr_unpack(message.info, msg_info)) {
|
||||||
return td::Status::Error("Failed to unpack CommonMsgInfo::int_msg_info");
|
return td::Status::Error("Failed to unpack CommonMsgInfo::int_msg_info");
|
||||||
}
|
}
|
||||||
|
|
||||||
TRY_RESULT(balance, to_balance(msg_info.value));
|
TRY_RESULT(balance, to_balance(msg_info.value));
|
||||||
TRY_RESULT(src, to_std_address(msg_info.src));
|
TRY_RESULT(src, to_std_address(msg_info.src));
|
||||||
TRY_RESULT(dest, to_std_address(msg_info.dest));
|
TRY_RESULT(dest, to_std_address(msg_info.dest));
|
||||||
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), std::move(dest), balance);
|
td::Ref<vm::CellSlice> 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<tonlib_api::raw_message>(std::move(src), std::move(dest), balance,
|
||||||
|
std::move(body_message));
|
||||||
}
|
}
|
||||||
case block::gen::CommonMsgInfo::ext_in_msg_info: {
|
case block::gen::CommonMsgInfo::ext_in_msg_info: {
|
||||||
block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info;
|
block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info;
|
||||||
@ -581,7 +612,7 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_message>> to_raw_message_or_th
|
|||||||
return td::Status::Error("Failed to unpack CommonMsgInfo::ext_in_msg_info");
|
return td::Status::Error("Failed to unpack CommonMsgInfo::ext_in_msg_info");
|
||||||
}
|
}
|
||||||
TRY_RESULT(dest, to_std_address(msg_info.dest));
|
TRY_RESULT(dest, to_std_address(msg_info.dest));
|
||||||
return tonlib_api::make_object<tonlib_api::raw_message>("", std::move(dest), 0);
|
return tonlib_api::make_object<tonlib_api::raw_message>("", std::move(dest), 0, "");
|
||||||
}
|
}
|
||||||
case block::gen::CommonMsgInfo::ext_out_msg_info: {
|
case block::gen::CommonMsgInfo::ext_out_msg_info: {
|
||||||
block::gen::CommonMsgInfo::Record_ext_out_msg_info msg_info;
|
block::gen::CommonMsgInfo::Record_ext_out_msg_info msg_info;
|
||||||
@ -589,7 +620,7 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_message>> to_raw_message_or_th
|
|||||||
return td::Status::Error("Failed to unpack CommonMsgInfo::ext_out_msg_info");
|
return td::Status::Error("Failed to unpack CommonMsgInfo::ext_out_msg_info");
|
||||||
}
|
}
|
||||||
TRY_RESULT(src, to_std_address(msg_info.src));
|
TRY_RESULT(src, to_std_address(msg_info.src));
|
||||||
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), "", 0);
|
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), "", 0, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,7 +657,7 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_transaction>> to_raw_transacti
|
|||||||
if (is_just == trans.r1.in_msg->fetch_long_eof) {
|
if (is_just == trans.r1.in_msg->fetch_long_eof) {
|
||||||
return td::Status::Error("Failed to parse long");
|
return td::Status::Error("Failed to parse long");
|
||||||
}
|
}
|
||||||
if (is_just == 1) {
|
if (is_just == -1) {
|
||||||
auto msg = trans.r1.in_msg->prefetch_ref();
|
auto msg = trans.r1.in_msg->prefetch_ref();
|
||||||
TRY_RESULT(in_msg_copy, to_raw_message(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);
|
in_msg = std::move(in_msg_copy);
|
||||||
@ -702,7 +733,7 @@ td::Result<tonlib_api::object_ptr<tonlib_api::generic_AccountState>> to_generic_
|
|||||||
RawAccountState&& raw_state) {
|
RawAccountState&& raw_state) {
|
||||||
if (raw_state.code.is_null()) {
|
if (raw_state.code.is_null()) {
|
||||||
return tonlib_api::make_object<tonlib_api::generic_accountStateUninited>(
|
return tonlib_api::make_object<tonlib_api::generic_accountStateUninited>(
|
||||||
tonlib_api::make_object<tonlib_api::uninited_accountState>(raw_state.balance, empty_transaction_id(),
|
tonlib_api::make_object<tonlib_api::uninited_accountState>(raw_state.balance, to_transaction_id(raw_state.info),
|
||||||
raw_state.sync_utime));
|
raw_state.sync_utime));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -827,21 +858,24 @@ td::Status TonlibClient::do_request(const tonlib_api::testWallet_sendGrams& requ
|
|||||||
if (!request.private_key_) {
|
if (!request.private_key_) {
|
||||||
return td::Status::Error(400, "Field private_key must not be empty");
|
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_));
|
TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_));
|
||||||
account_address.bounceable = false;
|
account_address.bounceable = false;
|
||||||
TRY_RESULT(input_key, from_tonlib(*request.private_key_));
|
TRY_RESULT(input_key, from_tonlib(*request.private_key_));
|
||||||
auto address = GenericAccount::get_address(
|
auto address = GenericAccount::get_address(
|
||||||
0 /*zerochain*/, TestWallet::get_init_state(td::Ed25519::PublicKey(input_key.key.public_key.copy())));
|
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)));
|
TRY_RESULT(private_key, key_storage_.load_private_key(std::move(input_key)));
|
||||||
return do_request(
|
return do_request(tonlib_api::raw_sendMessage(
|
||||||
tonlib_api::raw_sendMessage(tonlib_api::make_object<tonlib_api::accountAddress>(address.rserialize()), "",
|
tonlib_api::make_object<tonlib_api::accountAddress>(address.rserialize()), "",
|
||||||
vm::std_boc_serialize(TestWallet::make_a_gift_message(
|
vm::std_boc_serialize(TestWallet::make_a_gift_message(
|
||||||
td::Ed25519::PrivateKey(std::move(private_key.private_key)),
|
td::Ed25519::PrivateKey(std::move(private_key.private_key)),
|
||||||
request.seqno_, request.amount_, account_address))
|
request.seqno_, request.amount_, request.message_, account_address))
|
||||||
.move_as_ok()
|
.move_as_ok()
|
||||||
.as_slice()
|
.as_slice()
|
||||||
.str()),
|
.str()),
|
||||||
std::move(promise));
|
std::move(promise));
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Status TonlibClient::do_request(tonlib_api::testWallet_getAccountState& request,
|
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_) {
|
if (!request.destination_) {
|
||||||
return td::Status::Error(400, "Field destination must not be empty");
|
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_));
|
TRY_RESULT(account_address, block::StdAddress::parse(request.destination_->account_address_));
|
||||||
account_address.bounceable = false;
|
account_address.bounceable = false;
|
||||||
return do_request(
|
return do_request(tonlib_api::raw_sendMessage(
|
||||||
tonlib_api::raw_sendMessage(
|
tonlib_api::make_object<tonlib_api::accountAddress>(TestGiver::address().rserialize()), "",
|
||||||
tonlib_api::make_object<tonlib_api::accountAddress>(TestGiver::address().rserialize()), "",
|
vm::std_boc_serialize(TestGiver::make_a_gift_message(request.seqno_, request.amount_,
|
||||||
vm::std_boc_serialize(TestGiver::make_a_gift_message(request.seqno_, request.amount_, account_address))
|
request.message_, account_address))
|
||||||
.move_as_ok()
|
.move_as_ok()
|
||||||
.as_slice()
|
.as_slice()
|
||||||
.str()),
|
.str()),
|
||||||
std::move(promise));
|
std::move(promise));
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Status TonlibClient::do_request(const tonlib_api::testGiver_getAccountState& request,
|
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),
|
"GetAccountState", client_.get_client(), std::move(account_address),
|
||||||
[promise = std::move(promise), self = this, actor_id = td::actor::actor_id(),
|
[promise = std::move(promise), self = this, actor_id = td::actor::actor_id(),
|
||||||
private_key = std::move(request.private_key_), destination = std::move(request.destination_),
|
private_key = std::move(request.private_key_), destination = std::move(request.destination_),
|
||||||
amount = request.amount_](td::Result<RawAccountState> r_state) mutable {
|
amount = request.amount_, message = std::move(request.message_)](td::Result<RawAccountState> r_state) mutable {
|
||||||
if (r_state.is_error()) {
|
if (r_state.is_error()) {
|
||||||
return promise.set_error(r_state.move_as_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();
|
auto state = rr_state.move_as_ok();
|
||||||
|
|
||||||
downcast_call(*state,
|
downcast_call(*state, td::overloaded(
|
||||||
td::overloaded(
|
[&](tonlib_api::generic_accountStateTestGiver& test_giver_state) {
|
||||||
[&](tonlib_api::generic_accountStateTestGiver& test_giver_state) {
|
send_lambda(actor_id,
|
||||||
send_lambda(actor_id, [promise = std::move(promise), self,
|
[promise = std::move(promise), self,
|
||||||
query = tonlib_api::testGiver_sendGrams(
|
query = tonlib_api::testGiver_sendGrams(
|
||||||
std::move(destination), test_giver_state.account_state_->seqno_,
|
std::move(destination), test_giver_state.account_state_->seqno_,
|
||||||
amount)]() mutable {
|
amount, std::move(message))]() mutable {
|
||||||
LOG(INFO) << "Send " << to_string(query);
|
LOG(INFO) << "Send " << to_string(query);
|
||||||
auto status = self->do_request(query, std::move(promise));
|
auto status = self->do_request(query, std::move(promise));
|
||||||
if (status.is_error()) {
|
if (status.is_error()) {
|
||||||
CHECK(promise);
|
CHECK(promise);
|
||||||
promise.set_error(std::move(status));
|
promise.set_error(std::move(status));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
[&](tonlib_api::generic_accountStateTestWallet& test_wallet_state) {
|
[&](tonlib_api::generic_accountStateTestWallet& test_wallet_state) {
|
||||||
send_lambda(actor_id, [promise = std::move(promise), self,
|
send_lambda(actor_id, [promise = std::move(promise), self,
|
||||||
query = tonlib_api::testWallet_sendGrams(
|
query = tonlib_api::testWallet_sendGrams(
|
||||||
std::move(private_key), std::move(destination),
|
std::move(private_key), std::move(destination),
|
||||||
test_wallet_state.account_state_->seqno_, amount)]() mutable {
|
test_wallet_state.account_state_->seqno_, amount,
|
||||||
auto status = self->do_request(query, std::move(promise));
|
std::move(message))]() mutable {
|
||||||
if (status.is_error()) {
|
auto status = self->do_request(query, std::move(promise));
|
||||||
CHECK(promise);
|
if (status.is_error()) {
|
||||||
promise.set_error(std::move(status));
|
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_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"));
|
[&](tonlib_api::generic_accountStateRaw&) {
|
||||||
}));
|
promise.set_error(td::Status::Error(400, "Unknown account type"));
|
||||||
|
}));
|
||||||
})
|
})
|
||||||
.release();
|
.release();
|
||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
#include "tonlib/ExtClient.h"
|
#include "tonlib/ExtClient.h"
|
||||||
#include "tonlib/ExtClientOutbound.h"
|
#include "tonlib/ExtClientOutbound.h"
|
||||||
#include "tonlib/KeyStorage.h"
|
#include "tonlib/KeyStorage.h"
|
||||||
|
#include "tonlib/LastBlockStorage.h"
|
||||||
|
|
||||||
#include "td/actor/actor.h"
|
#include "td/actor/actor.h"
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ class TonlibClient : public td::actor::Actor {
|
|||||||
|
|
||||||
// KeyStorage
|
// KeyStorage
|
||||||
KeyStorage key_storage_;
|
KeyStorage key_storage_;
|
||||||
|
LastBlockStorage last_block_storage_;
|
||||||
|
|
||||||
// network
|
// network
|
||||||
td::actor::ActorOwn<ton::adnl::AdnlExtClient> raw_client_;
|
td::actor::ActorOwn<ton::adnl::AdnlExtClient> 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<tonlib_api::Object> response);
|
void on_result(td::uint64 id, object_ptr<tonlib_api::Object> response);
|
||||||
static bool is_static_request(td::int32 id);
|
static bool is_static_request(td::int32 id);
|
||||||
static bool is_uninited_request(td::int32 id);
|
static bool is_uninited_request(td::int32 id);
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "td/utils/port/signals.h"
|
#include "td/utils/port/signals.h"
|
||||||
#include "td/utils/port/path.h"
|
#include "td/utils/port/path.h"
|
||||||
#include "td/utils/Random.h"
|
#include "td/utils/Random.h"
|
||||||
|
#include "td/utils/as.h"
|
||||||
|
|
||||||
#include "terminal/terminal.h"
|
#include "terminal/terminal.h"
|
||||||
|
|
||||||
@ -327,6 +328,8 @@ class TonlibCli : public td::actor::Actor {
|
|||||||
<< "\n";
|
<< "\n";
|
||||||
for (size_t i = 0; i < keys_.size(); i++) {
|
for (size_t i = 0; i < keys_.size(); i++) {
|
||||||
td::TerminalIO::out() << " #" << i << ": " << keys_[i].public_key << "\n";
|
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) {
|
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;
|
using tonlib_api::make_object;
|
||||||
auto key = !from.secret.empty()
|
auto key = !from.secret.empty()
|
||||||
? make_object<tonlib_api::inputKey>(
|
? make_object<tonlib_api::inputKey>(
|
||||||
make_object<tonlib_api::key>(from.public_key, from.secret.copy()), td::SecureString(password))
|
make_object<tonlib_api::key>(from.public_key, from.secret.copy()), td::SecureString(password))
|
||||||
: nullptr;
|
: nullptr;
|
||||||
send_query(make_object<tonlib_api::generic_sendGrams>(std::move(key), std::move(from.address),
|
send_query(make_object<tonlib_api::generic_sendGrams>(std::move(key), std::move(from.address),
|
||||||
std::move(to.address), grams),
|
std::move(to.address), grams, message.str()),
|
||||||
[](auto r_res) {
|
[](auto r_res) {
|
||||||
if (r_res.is_error()) {
|
if (r_res.is_error()) {
|
||||||
td::TerminalIO::out() << "Can't get state: " << r_res.error() << "\n";
|
td::TerminalIO::out() << "Can't get state: " << r_res.error() << "\n";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user