mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Wallet errors
This commit is contained in:
parent
d27fb1fdce
commit
2328a24d3f
@ -4780,6 +4780,7 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"Wallet.Info.Send" = "Send";
|
||||
"Wallet.Info.RefreshErrorTitle" = "An Error Occurred";
|
||||
"Wallet.Info.RefreshErrorText" = "The wallet state can not be retrieved at this time. Please try again later.";
|
||||
"Wallet.Info.RefreshErrorNetworkText" = "The wallet state can not be retrieved at this time. Please try again later.";
|
||||
"Wallet.Info.UnknownTransaction" = "Empty Transaction";
|
||||
"Wallet.Info.TransactionTo" = "to";
|
||||
"Wallet.Info.TransactionFrom" = "from";
|
||||
@ -4881,8 +4882,12 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"Wallet.Words.NotDoneOk" = "OK, Sorry";
|
||||
"Wallet.Words.NotDoneResponse" = "Apologies Accepted";
|
||||
|
||||
"Wallet.Send.NetworkError" = "Network Error";
|
||||
"Wallet.Send.ErrorNotEnoughFunds" = "Not Enough Funds";
|
||||
"Wallet.Send.ErrorInvalidAddress" = "Invalid wallet address. Please correct and try again.";
|
||||
"Wallet.Send.ErrorDecryptionFailed" = "Please make sure that your device has a passcode set in iOS Settings and try again.";
|
||||
"Wallet.Send.UninitializedTitle" = "Warning";
|
||||
"Wallet.Send.UninitializedText" = "This address belongs to an empty wallet. Are you sure you want to transfer grams to it?";
|
||||
"Wallet.Send.SendAnyway" = "Send Anyway";
|
||||
|
||||
"Wallet.Receive.CreateInvoice" = "Create Invoice";
|
||||
|
@ -47,32 +47,47 @@ private func fetchRawData(prefix: String) -> Signal<Data, FetchError> {
|
||||
}
|
||||
|
||||
@available(iOS 10.0, *)
|
||||
public func cloudDataAdditionalAddressSource(phoneNumber: Signal<String?, NoError>) -> Signal<MTBackupDatacenterData, NoError> {
|
||||
return phoneNumber
|
||||
|> take(1)
|
||||
|> mapToSignal { phoneNumber -> Signal<MTBackupDatacenterData, NoError> in
|
||||
var prefix = ""
|
||||
if let phoneNumber = phoneNumber, phoneNumber.count >= 1 {
|
||||
prefix = String(phoneNumber[phoneNumber.startIndex ..< phoneNumber.index(after: phoneNumber.startIndex)])
|
||||
}
|
||||
return fetchRawData(prefix: prefix)
|
||||
|> map { data -> MTBackupDatacenterData? in
|
||||
if let datacenterData = MTIPDataDecode(data, phoneNumber ?? "") {
|
||||
return datacenterData
|
||||
} else {
|
||||
return nil
|
||||
private final class CloudDataPrefixContext {
|
||||
private let prefix: String
|
||||
private let value = Promise<Data?>()
|
||||
|
||||
private var lastRequestTimestamp: Double?
|
||||
|
||||
init(prefix: String) {
|
||||
self.prefix = prefix
|
||||
}
|
||||
|
||||
private func fetch() {
|
||||
let fetchSignal = (
|
||||
fetchRawData(prefix: self.prefix)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { error -> Signal<Data?, NoError> in
|
||||
switch error {
|
||||
case .networkUnavailable:
|
||||
return .complete()
|
||||
default:
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|> restart
|
||||
)
|
||||
|> take(1)
|
||||
self.value.set(fetchSignal)
|
||||
}
|
||||
|
||||
func get() -> Signal<Data?, NoError> {
|
||||
var shouldFetch = false
|
||||
let timestamp = CFAbsoluteTimeGetCurrent()
|
||||
if let lastRequestTimestamp = self.lastRequestTimestamp {
|
||||
shouldFetch = timestamp >= lastRequestTimestamp + 1.0 * 60.0
|
||||
} else {
|
||||
shouldFetch = true
|
||||
}
|
||||
|> `catch` { error -> Signal<MTBackupDatacenterData?, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
|> mapToSignal { data -> Signal<MTBackupDatacenterData, NoError> in
|
||||
if let data = data {
|
||||
return .single(data)
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
if shouldFetch {
|
||||
self.lastRequestTimestamp = timestamp
|
||||
self.fetch()
|
||||
}
|
||||
return self.value.get()
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,32 +95,25 @@ public func cloudDataAdditionalAddressSource(phoneNumber: Signal<String?, NoErro
|
||||
private final class CloudDataContextObject {
|
||||
private let queue: Queue
|
||||
|
||||
private var prefixContexts: [String: CloudDataPrefixContext] = [:]
|
||||
|
||||
init(queue: Queue) {
|
||||
self.queue = queue
|
||||
|
||||
let container = CKContainer.default()
|
||||
let publicDatabase = container.database(with: .public)
|
||||
|
||||
/*let changesOperation = CKFetchDatabaseChangesOperation(previousServerChangeToken: nil)
|
||||
changesOperation.fetchAllChanges = true
|
||||
changesOperation.recordZoneWithIDChangedBlock = { _ in
|
||||
print("recordZoneWithIDChangedBlock")
|
||||
}
|
||||
|
||||
func get(prefix: String) -> Signal<Data?, NoError> {
|
||||
let context: CloudDataPrefixContext
|
||||
if let current = self.prefixContexts[prefix] {
|
||||
context = current
|
||||
} else {
|
||||
context = CloudDataPrefixContext(prefix: prefix)
|
||||
}
|
||||
changesOperation.recordZoneWithIDWasDeletedBlock = { _ in
|
||||
|
||||
}
|
||||
changesOperation.changeTokenUpdatedBlock = { _ in
|
||||
print("changeTokenUpdatedBlock")
|
||||
}
|
||||
changesOperation.fetchDatabaseChangesCompletionBlock = { serverChangeToken, isMoreComing, error in
|
||||
print("done")
|
||||
}
|
||||
publicDatabase.add(changesOperation)*/
|
||||
return context.get()
|
||||
}
|
||||
}
|
||||
|
||||
public protocol CloudDataContext {
|
||||
|
||||
func get(phoneNumber: Signal<String?, NoError>) -> Signal<MTBackupDatacenterData, NoError>
|
||||
}
|
||||
|
||||
@available(iOS 10.0, *)
|
||||
@ -119,4 +127,29 @@ public final class CloudDataContextImpl: CloudDataContext {
|
||||
return CloudDataContextObject(queue: queue)
|
||||
})
|
||||
}
|
||||
|
||||
public func get(phoneNumber: Signal<String?, NoError>) -> Signal<MTBackupDatacenterData, NoError> {
|
||||
return phoneNumber
|
||||
|> take(1)
|
||||
|> mapToSignal { phoneNumber -> Signal<MTBackupDatacenterData, NoError> in
|
||||
var prefix = ""
|
||||
if let phoneNumber = phoneNumber, phoneNumber.count >= 1 {
|
||||
prefix = String(phoneNumber[phoneNumber.startIndex ..< phoneNumber.index(after: phoneNumber.startIndex)])
|
||||
}
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
self.impl.with { impl in
|
||||
disposable.set(impl.get(prefix: prefix).start(next: { data in
|
||||
if let data = data, let datacenterData = MTIPDataDecode(data, phoneNumber ?? "") {
|
||||
subscriber.putNext(datacenterData)
|
||||
subscriber.putCompletion()
|
||||
} else {
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
}))
|
||||
}
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -392,7 +392,7 @@ public func createPollController(context: AccountContext, peerId: PeerId, comple
|
||||
controller?.present(c, in: .window(.root), with: a)
|
||||
}
|
||||
dismissImpl = { [weak controller] in
|
||||
controller?.view.endEditing(true)
|
||||
//controller?.view.endEditing(true)
|
||||
controller?.dismiss()
|
||||
}
|
||||
ensureTextVisibleImpl = { [weak controller] in
|
||||
|
@ -401,8 +401,8 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
}
|
||||
|
||||
if self.currentTopVisibleOverlayContainerStatusBar !== topVisibleOverlayContainerWithStatusBar {
|
||||
self.currentTopVisibleOverlayContainerStatusBar = topVisibleOverlayContainerWithStatusBar
|
||||
animateStatusBarStyleTransition = true
|
||||
self.currentTopVisibleOverlayContainerStatusBar = topVisibleOverlayContainerWithStatusBar
|
||||
}
|
||||
|
||||
var previousModalContainer: NavigationModalContainer?
|
||||
|
@ -375,9 +375,9 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture
|
||||
|
||||
if !self.areControlsHidden {
|
||||
if transition < 0.5 {
|
||||
self.statusBar?.updateAlpha(0.0, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||
self.statusBar?.statusBarStyle = .Ignore
|
||||
} else {
|
||||
self.statusBar?.updateAlpha(1.0, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||
self.statusBar?.statusBarStyle = .White
|
||||
}
|
||||
self.navigationBar?.alpha = transition
|
||||
self.footerNode.alpha = transition
|
||||
|
@ -307,7 +307,6 @@ static NSString *makeRandomPadding() {
|
||||
if (![datacenterData isKindOfClass:[MTBackupDatacenterData class]]) {
|
||||
return [MTSignal complete];
|
||||
}
|
||||
MTBackupDatacenterData *datacenterData = MTIPDataDecode(finalData, phoneNumber);
|
||||
if (datacenterData != nil && [self checkIpData:datacenterData timestamp:(int32_t)[currentContext globalTime] source:@"resolveExternal"]) {
|
||||
return [MTSignal single:datacenterData];
|
||||
} else {
|
||||
|
@ -964,6 +964,9 @@ static NSData *decrypt_TL_data(unsigned char buffer[256]) {
|
||||
@end
|
||||
|
||||
MTBackupDatacenterData *MTIPDataDecode(NSData *data, NSString *phoneNumber) {
|
||||
if (data.length < 256) {
|
||||
return nil;
|
||||
}
|
||||
unsigned char buffer[256];
|
||||
memcpy(buffer, data.bytes, 256);
|
||||
NSData *result = decrypt_TL_data(buffer);
|
||||
|
@ -92,6 +92,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (MTSignal *)exportKey:(TONKey *)key localPassword:(NSData *)localPassword;
|
||||
- (MTSignal *)importKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword wordList:(NSArray<NSString *> *)wordList;
|
||||
- (MTSignal *)deleteKey:(TONKey *)key;
|
||||
- (MTSignal *)deleteAllKeys;
|
||||
- (MTSignal *)getTransactionListWithAddress:(NSString * _Nonnull)address lt:(int64_t)lt hash:(NSData * _Nonnull)hash;
|
||||
|
||||
@end
|
||||
|
@ -328,7 +328,9 @@ typedef enum {
|
||||
false,
|
||||
false
|
||||
),
|
||||
keystoreDirectory.UTF8String
|
||||
make_object<tonlib_api::keyStoreTypeDirectory>(
|
||||
keystoreDirectory.UTF8String
|
||||
)
|
||||
));
|
||||
_client->send({ requestId, std::move(query) });
|
||||
|
||||
@ -636,6 +638,28 @@ typedef enum {
|
||||
}] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]];
|
||||
}
|
||||
|
||||
- (MTSignal *)deleteAllKeys {
|
||||
return [[[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) {
|
||||
uint64_t requestId = _nextRequestId;
|
||||
_nextRequestId += 1;
|
||||
|
||||
_requestHandlers[@(requestId)] = [[TONRequestHandler alloc] initWithCompletion:^(tonlib_api::object_ptr<tonlib_api::Object> &object) {
|
||||
if (object->get_id() == tonlib_api::error::ID) {
|
||||
auto error = tonlib_api::move_object_as<tonlib_api::error>(object);
|
||||
[subscriber putError:[[TONError alloc] initWithText:[[NSString alloc] initWithUTF8String:error->message_.c_str()]]];
|
||||
} else {
|
||||
[subscriber putCompletion];
|
||||
}
|
||||
}];
|
||||
|
||||
auto query = make_object<tonlib_api::deleteAllKeys>();
|
||||
_client->send({ requestId, std::move(query) });
|
||||
|
||||
return [[MTBlockDisposable alloc] initWithBlock:^{
|
||||
}];
|
||||
}] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]];
|
||||
}
|
||||
|
||||
- (MTSignal *)getTransactionListWithAddress:(NSString * _Nonnull)address lt:(int64_t)lt hash:(NSData * _Nonnull)hash {
|
||||
return [[[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) {
|
||||
NSData *addressData = [address dataUsingEncoding:NSUTF8StringEncoding];
|
||||
|
@ -135,6 +135,55 @@ public func retry<T, E>(_ delayIncrement: Double, maxDelay: Double, onQueue queu
|
||||
}
|
||||
}
|
||||
|
||||
public func retry<T, E>(retryOnError: @escaping (E) -> Bool, delayIncrement: Double, maxDelay: Double, maxRetries: Int, onQueue queue: Queue) -> (_ signal: Signal<T, E>) -> Signal<T, E> {
|
||||
return { signal in
|
||||
return Signal { subscriber in
|
||||
let shouldRetry = Atomic(value: true)
|
||||
let currentDelay = Atomic<(Double, Int)>(value: (0.0, 0))
|
||||
let currentDisposable = MetaDisposable()
|
||||
|
||||
let start = recursiveFunction { recurse in
|
||||
let currentShouldRetry = shouldRetry.with { value in
|
||||
return value
|
||||
}
|
||||
if currentShouldRetry {
|
||||
let disposable = signal.start(next: { next in
|
||||
subscriber.putNext(next)
|
||||
}, error: { error in
|
||||
if !retryOnError(error) {
|
||||
subscriber.putError(error)
|
||||
} else {
|
||||
let (delay, count) = currentDelay.modify { value, count in
|
||||
return (min(maxDelay, value + delayIncrement), count + 1)
|
||||
}
|
||||
|
||||
if count >= maxRetries {
|
||||
subscriber.putError(error)
|
||||
} else {
|
||||
let time: DispatchTime = DispatchTime.now() + Double(delay)
|
||||
queue.queue.asyncAfter(deadline: time, execute: {
|
||||
recurse()
|
||||
})
|
||||
}
|
||||
}
|
||||
}, completed: {
|
||||
let _ = shouldRetry.swap(false)
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
currentDisposable.set(disposable)
|
||||
}
|
||||
}
|
||||
|
||||
start()
|
||||
|
||||
return ActionDisposable {
|
||||
currentDisposable.dispose()
|
||||
let _ = shouldRetry.swap(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func restartIfError<T, E>(_ signal: Signal<T, E>) -> Signal<T, NoError> {
|
||||
return Signal<T, NoError> { subscriber in
|
||||
let shouldRetry = Atomic(value: true)
|
||||
|
@ -417,6 +417,8 @@ public struct NetworkInitializationArguments {
|
||||
}
|
||||
}
|
||||
|
||||
private let cloudDataContext = makeCloudDataContext()
|
||||
|
||||
func initializedNetwork(arguments: NetworkInitializationArguments, supplementary: Bool, datacenterId: Int, keychain: Keychain, basePath: String, testingEnvironment: Bool, languageCode: String?, proxySettings: ProxySettings?, networkSettings: NetworkSettings?, phoneNumber: String?) -> Signal<Network, NoError> {
|
||||
return Signal { subscriber in
|
||||
let queue = Queue()
|
||||
@ -484,17 +486,18 @@ func initializedNetwork(arguments: NetworkInitializationArguments, supplementary
|
||||
var wrappedAdditionalSource: MTSignal?
|
||||
|
||||
if #available(iOS 10.0, *) {
|
||||
let additionalSource = cloudDataAdditionalAddressSource(phoneNumber: .single(phoneNumber ?? ""))
|
||||
wrappedAdditionalSource = MTSignal(generator: { subscriber in
|
||||
let disposable = additionalSource.start(next: { value in
|
||||
subscriber?.putNext(value)
|
||||
}, completed: {
|
||||
subscriber?.putCompletion()
|
||||
if let cloudDataContext = cloudDataContext {
|
||||
wrappedAdditionalSource = MTSignal(generator: { subscriber in
|
||||
let disposable = cloudDataContext.get(phoneNumber: .single(phoneNumber)).start(next: { value in
|
||||
subscriber?.putNext(value)
|
||||
}, completed: {
|
||||
subscriber?.putCompletion()
|
||||
})
|
||||
return MTBlockDisposable(block: {
|
||||
disposable.dispose()
|
||||
})
|
||||
})
|
||||
return MTBlockDisposable(block: {
|
||||
disposable.dispose()
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
context.setDiscoverBackupAddressListSignal(MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber))
|
||||
@ -1010,7 +1013,8 @@ public final class Network: NSObject, MTRequestMessageServiceDelegate {
|
||||
}
|
||||
|
||||
public func retryRequest<T>(signal: Signal<T, MTRpcError>) -> Signal<T, NoError> {
|
||||
return signal |> retry(0.2, maxDelay: 5.0, onQueue: Queue.concurrentDefaultQueue())
|
||||
return signal
|
||||
|> retry(0.2, maxDelay: 5.0, onQueue: Queue.concurrentDefaultQueue())
|
||||
}
|
||||
|
||||
class Keychain: NSObject, MTKeychain {
|
||||
@ -1045,7 +1049,7 @@ class Keychain: NSObject, MTKeychain {
|
||||
}
|
||||
}
|
||||
|
||||
public func makeCloudDataContext() -> Any? {
|
||||
func makeCloudDataContext() -> CloudDataContext? {
|
||||
if #available(iOS 10.0, *) {
|
||||
return CloudDataContextImpl()
|
||||
} else {
|
||||
|
@ -219,8 +219,16 @@ public final class TonInstance {
|
||||
return
|
||||
}
|
||||
subscriber.putNext(state)
|
||||
}, error: { _ in
|
||||
subscriber.putError(.generic)
|
||||
}, error: { error in
|
||||
if let error = error as? TONError {
|
||||
if error.text.hasPrefix("LITE_SERVER_") {
|
||||
subscriber.putError(.network)
|
||||
} else {
|
||||
subscriber.putError(.generic)
|
||||
}
|
||||
} else {
|
||||
subscriber.putError(.generic)
|
||||
}
|
||||
}, completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
@ -241,7 +249,7 @@ public final class TonInstance {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func walletLastTransactionId(address: String) -> Signal<WalletTransactionId?, NoError> {
|
||||
fileprivate func walletLastTransactionId(address: String) -> Signal<WalletTransactionId?, WalletLastTransactionIdError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
@ -253,7 +261,16 @@ public final class TonInstance {
|
||||
return
|
||||
}
|
||||
subscriber.putNext(state.lastTransactionId.flatMap(WalletTransactionId.init(tonTransactionId:)))
|
||||
}, error: { _ in
|
||||
}, error: { error in
|
||||
if let error = error as? TONError {
|
||||
if error.text.hasPrefix("ДITE_SERVER_") {
|
||||
subscriber.putError(.network)
|
||||
} else {
|
||||
subscriber.putError(.generic)
|
||||
}
|
||||
} else {
|
||||
subscriber.putError(.generic)
|
||||
}
|
||||
}, completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
@ -279,7 +296,16 @@ public final class TonInstance {
|
||||
return
|
||||
}
|
||||
subscriber.putNext(transactions.map(WalletTransaction.init(tonTransaction:)))
|
||||
}, error: { _ in
|
||||
}, error: { error in
|
||||
if let error = error as? TONError {
|
||||
if error.text.hasPrefix("LITE_SERVER_") {
|
||||
subscriber.putError(.network)
|
||||
} else {
|
||||
subscriber.putError(.generic)
|
||||
}
|
||||
} else {
|
||||
subscriber.putError(.generic)
|
||||
}
|
||||
}, completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
@ -308,10 +334,16 @@ public final class TonInstance {
|
||||
subscriber.putCompletion()
|
||||
}, error: { error in
|
||||
if let error = error as? TONError {
|
||||
if error.text == "Failed to parse account address" {
|
||||
if error.text.hasPrefix("INVALID_ACCOUNT_ADDRESS") {
|
||||
subscriber.putError(.invalidAddress)
|
||||
} else if error.text.hasPrefix("DANGEROUS_TRANSACTION") {
|
||||
subscriber.putError(.destinationIsNotInitialized)
|
||||
} else if error.text.hasPrefix("MESSAGE_TOO_LONG") {
|
||||
subscriber.putError(.messageTooLong)
|
||||
} else if error.text.hasPrefix("NOT_ENOUGH_FUNDS") {
|
||||
subscriber.putError(.notEnoughFunds)
|
||||
} else if error.text.hasPrefix("LITE_SERVER_") {
|
||||
subscriber.putError(.network)
|
||||
} else {
|
||||
subscriber.putError(.generic)
|
||||
}
|
||||
@ -364,6 +396,29 @@ public final class TonInstance {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func deleteAllLocalWalletsData() -> Signal<Never, DeleteAllLocalWalletsDataError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
self.impl.with { impl in
|
||||
impl.withInstance { ton in
|
||||
let cancel = ton.deleteAllKeys().start(next: { _ in
|
||||
assertionFailure()
|
||||
}, error: { _ in
|
||||
subscriber.putError(.generic)
|
||||
}, completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
disposable.set(ActionDisposable {
|
||||
cancel?.dispose()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func deleteLocalWalletData(walletInfo: WalletInfo, keychain: TonKeychain, serverSalt: Data) -> Signal<Never, DeleteLocalWalletDataError> {
|
||||
return keychain.decrypt(walletInfo.encryptedSecret)
|
||||
|> mapError { error -> DeleteLocalWalletDataError in
|
||||
@ -580,6 +635,24 @@ public func importWallet(postbox: Postbox, network: Network, tonInstance: TonIns
|
||||
}
|
||||
}
|
||||
|
||||
public enum DeleteAllLocalWalletsDataError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public func deleteAllLocalWalletsData(postbox: Postbox, network: Network, tonInstance: TonInstance) -> Signal<Never, DeleteAllLocalWalletsDataError> {
|
||||
return tonInstance.deleteAllLocalWalletsData()
|
||||
|> then(
|
||||
postbox.transaction { transaction -> Void in
|
||||
transaction.updatePreferencesEntry(key: PreferencesKeys.walletCollection, { current in
|
||||
let walletCollection = (current as? WalletCollection) ?? WalletCollection(wallets: [])
|
||||
return walletCollection
|
||||
})
|
||||
}
|
||||
|> castError(DeleteAllLocalWalletsDataError.self)
|
||||
|> ignoreValues
|
||||
)
|
||||
}
|
||||
|
||||
public enum DeleteLocalWalletDataError {
|
||||
case generic
|
||||
case secretDecryptionFailed(TonKeychainDecryptDataError)
|
||||
@ -642,6 +715,7 @@ public func walletAddress(publicKey: WalletPublicKey, tonInstance: TonInstance)
|
||||
|
||||
private enum GetWalletStateError {
|
||||
case generic
|
||||
case network
|
||||
}
|
||||
|
||||
private func getWalletState(address: String, tonInstance: TonInstance) -> Signal<(WalletState, Int64), GetWalletStateError> {
|
||||
@ -650,6 +724,7 @@ private func getWalletState(address: String, tonInstance: TonInstance) -> Signal
|
||||
|
||||
public enum GetCombinedWalletStateError {
|
||||
case generic
|
||||
case network
|
||||
}
|
||||
|
||||
public enum CombinedWalletStateResult {
|
||||
@ -682,8 +757,19 @@ public func getCombinedWalletState(postbox: Postbox, subject: CombinedWalletStat
|
||||
|> castError(GetCombinedWalletStateError.self)
|
||||
|> mapToSignal { address -> Signal<CombinedWalletStateResult, GetCombinedWalletStateError> in
|
||||
return getWalletState(address: address, tonInstance: tonInstance)
|
||||
|> mapError { _ -> GetCombinedWalletStateError in
|
||||
return .generic
|
||||
|> retryTonRequest(isNetworkError: { error in
|
||||
if case .network = error {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
|> mapError { error -> GetCombinedWalletStateError in
|
||||
if case .network = error {
|
||||
return .network
|
||||
} else {
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
|> mapToSignal { walletState, syncUtime -> Signal<CombinedWalletStateResult, GetCombinedWalletStateError> in
|
||||
let topTransactions: Signal<[WalletTransaction], GetCombinedWalletStateError>
|
||||
@ -691,8 +777,12 @@ public func getCombinedWalletState(postbox: Postbox, subject: CombinedWalletStat
|
||||
topTransactions = .single(cachedState?.topTransactions ?? [])
|
||||
} else {
|
||||
topTransactions = getWalletTransactions(address: address, previousId: nil, tonInstance: tonInstance)
|
||||
|> mapError { _ -> GetCombinedWalletStateError in
|
||||
return .generic
|
||||
|> mapError { error -> GetCombinedWalletStateError in
|
||||
if case .network = error {
|
||||
return .network
|
||||
} else {
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
}
|
||||
return topTransactions
|
||||
@ -744,6 +834,9 @@ public enum SendGramsFromWalletError {
|
||||
case secretDecryptionFailed
|
||||
case invalidAddress
|
||||
case destinationIsNotInitialized
|
||||
case messageTooLong
|
||||
case notEnoughFunds
|
||||
case network
|
||||
}
|
||||
|
||||
public func sendGramsFromWallet(network: Network, tonInstance: TonInstance, walletInfo: WalletInfo, decryptedSecret: Data, serverSalt: Data, toAddress: String, amount: Int64, textMessage: String, forceIfDestinationNotInitialized: Bool, timeout: Int32, randomId: Int64) -> Signal<Never, SendGramsFromWalletError> {
|
||||
@ -862,6 +955,7 @@ private extension WalletTransaction {
|
||||
|
||||
public enum GetWalletTransactionsError {
|
||||
case generic
|
||||
case network
|
||||
}
|
||||
|
||||
public func getWalletTransactions(address: String, previousId: WalletTransactionId?, tonInstance: TonInstance) -> Signal<[WalletTransaction], GetWalletTransactionsError> {
|
||||
@ -885,18 +979,50 @@ public func getWalletTransactions(address: String, previousId: WalletTransaction
|
||||
}
|
||||
}
|
||||
|
||||
private func retryTonRequest<T, E>(isNetworkError: @escaping (E) -> Bool) -> (Signal<T, E>) -> Signal<T, E> {
|
||||
return { signal in
|
||||
return signal
|
||||
|> retry(retryOnError: isNetworkError, delayIncrement: 0.2, maxDelay: 5.0, maxRetries: 3, onQueue: Queue.concurrentDefaultQueue())
|
||||
}
|
||||
}
|
||||
|
||||
private enum WalletLastTransactionIdError {
|
||||
case generic
|
||||
case network
|
||||
}
|
||||
|
||||
private func getWalletTransactionsOnce(address: String, previousId: WalletTransactionId?, tonInstance: TonInstance) -> Signal<[WalletTransaction], GetWalletTransactionsError> {
|
||||
let previousIdValue: Signal<WalletTransactionId?, GetWalletTransactionsError>
|
||||
if let previousId = previousId {
|
||||
previousIdValue = .single(previousId)
|
||||
} else {
|
||||
previousIdValue = tonInstance.walletLastTransactionId(address: address)
|
||||
|> castError(GetWalletTransactionsError.self)
|
||||
|> retryTonRequest(isNetworkError: { error in
|
||||
if case .network = error {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
|> mapError { error -> GetWalletTransactionsError in
|
||||
if case .network = error {
|
||||
return .network
|
||||
} else {
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
}
|
||||
return previousIdValue
|
||||
|> mapToSignal { previousId in
|
||||
if let previousId = previousId {
|
||||
return tonInstance.getWalletTransactions(address: address, previousId: previousId)
|
||||
|> retryTonRequest(isNetworkError: { error in
|
||||
if case .network = error {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return .single([])
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -244,8 +244,6 @@ final class SharedApplicationContext {
|
||||
|
||||
private let deviceToken = Promise<Data?>(nil)
|
||||
|
||||
private var cloudDataContext: Any?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
|
||||
precondition(!testIsLaunched)
|
||||
testIsLaunched = true
|
||||
@ -262,8 +260,6 @@ final class SharedApplicationContext {
|
||||
self.window = window
|
||||
self.nativeWindow = window
|
||||
|
||||
self.cloudDataContext = makeCloudDataContext()
|
||||
|
||||
let clearNotificationsManager = ClearNotificationsManager(getNotificationIds: { completion in
|
||||
if #available(iOS 10.0, *) {
|
||||
UNUserNotificationCenter.current().getDeliveredNotifications(completionHandler: { notifications in
|
||||
|
Binary file not shown.
@ -751,7 +751,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
strongSelf.didSetContentReady = true
|
||||
strongSelf.contentReady.set(.single(true))
|
||||
}
|
||||
}, error: { [weak self] _ in
|
||||
}, error: { [weak self] error in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -780,7 +780,14 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
strongSelf.contentReady.set(.single(true))
|
||||
}
|
||||
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: strongSelf.presentationData.strings.Wallet_Info_RefreshErrorTitle, text: strongSelf.presentationData.strings.Wallet_Info_RefreshErrorText, actions: [
|
||||
let text: String
|
||||
switch error {
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Wallet_Info_RefreshErrorText
|
||||
case .network:
|
||||
text = strongSelf.presentationData.strings.Wallet_Info_RefreshErrorNetworkText
|
||||
}
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: strongSelf.presentationData.strings.Wallet_Info_RefreshErrorTitle, text: text, actions: [
|
||||
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {
|
||||
})
|
||||
], actionLayout: .vertical), nil)
|
||||
|
@ -120,7 +120,7 @@ public func walletSettingsController(context: AccountContext, tonContext: TonCon
|
||||
actionSheet?.dismissAnimated()
|
||||
let controller = OverlayStatusController(theme: presentationData.theme, strings: presentationData.strings, type: .loading(cancelled: nil))
|
||||
presentControllerImpl?(controller, nil)
|
||||
let _ = (deleteLocalWalletData(postbox: context.account.postbox, network: context.account.network, tonInstance: tonContext.instance, keychain: tonContext.keychain, walletInfo: walletInfo)
|
||||
let _ = (deleteAllLocalWalletsData(postbox: context.account.postbox, network: context.account.network, tonInstance: tonContext.instance)
|
||||
|> deliverOnMainQueue).start(error: { [weak controller] _ in
|
||||
controller?.dismiss()
|
||||
}, completed: { [weak controller] in
|
||||
|
@ -142,14 +142,20 @@ public final class WalletSplashScreen: ViewController {
|
||||
switch error {
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
case .network:
|
||||
text = strongSelf.presentationData.strings.Wallet_Send_NetworkError
|
||||
case .notEnoughFunds:
|
||||
text = strongSelf.presentationData.strings.Wallet_Send_ErrorNotEnoughFunds
|
||||
case .messageTooLong:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
case .invalidAddress:
|
||||
text = strongSelf.presentationData.strings.Wallet_Send_ErrorInvalidAddress
|
||||
case .secretDecryptionFailed:
|
||||
text = strongSelf.presentationData.strings.Wallet_Send_ErrorDecryptionFailed
|
||||
case .destinationIsNotInitialized:
|
||||
if !forceIfDestinationNotInitialized {
|
||||
text = "This address belongs to an empty wallet. Are you sure you want to transfer grams to it?"
|
||||
let controller = textAlertController(context: strongSelf.context, title: "Warning", text: text, actions: [
|
||||
text = strongSelf.presentationData.strings.Wallet_Send_UninitializedText
|
||||
let controller = textAlertController(context: strongSelf.context, title: strongSelf.presentationData.strings.Wallet_Send_UninitializedTitle, text: text, actions: [
|
||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
|
||||
if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
navigationController.popViewController(animated: true)
|
||||
|
@ -3,7 +3,7 @@ import TelegramStringFormatting
|
||||
import UrlEscaping
|
||||
|
||||
let walletAddressLength: Int = 48
|
||||
let walletTextLimit: Int = 124
|
||||
let walletTextLimit: Int = 1024
|
||||
|
||||
func formatAddress(_ address: String) -> String {
|
||||
var address = address
|
||||
|
@ -315,6 +315,8 @@ if (NOT CMAKE_CROSSCOMPILING)
|
||||
GenFif(DEST smartcont/config-code.fif SOURCE smartcont/config-code.fc)
|
||||
GenFif(DEST smartcont/wallet-code.fif SOURCE smartcont/wallet-code.fc)
|
||||
GenFif(DEST smartcont/simple-wallet-code.fif SOURCE smartcont/simple-wallet-code.fc)
|
||||
GenFif(DEST smartcont/highload-wallet-code.fif SOURCE smartcont/highload-wallet-code.fc)
|
||||
GenFif(DEST smartcont/highload-wallet-v2-code.fif SOURCE smartcont/highload-wallet-v2-code.fc)
|
||||
GenFif(DEST smartcont/elector-code.fif SOURCE smartcont/elector-code.fc)
|
||||
endif()
|
||||
|
||||
@ -333,3 +335,6 @@ target_link_libraries(dump-block PUBLIC ton_crypto fift-lib ton_block)
|
||||
if (WINGETOPT_FOUND)
|
||||
target_link_libraries_system(dump-block wingetopt)
|
||||
endif()
|
||||
|
||||
install(TARGETS fift func RUNTIME DESTINATION bin)
|
||||
install(DIRECTORY fift/lib/ DESTINATION lib/fift)
|
||||
|
@ -8891,6 +8891,7 @@ bool TransactionDescr::skip(vm::CellSlice& cs) const {
|
||||
&& cs.advance(2);
|
||||
case trans_split_prepare:
|
||||
return cs.advance(528)
|
||||
&& t_Maybe_TrStoragePhase.skip(cs)
|
||||
&& t_TrComputePhase.skip(cs)
|
||||
&& t_Maybe_Ref_TrActionPhase.skip(cs)
|
||||
&& cs.advance(2);
|
||||
@ -8902,6 +8903,7 @@ bool TransactionDescr::skip(vm::CellSlice& cs) const {
|
||||
&& cs.advance(1);
|
||||
case trans_merge_install:
|
||||
return cs.advance_ext(0x10210)
|
||||
&& t_Maybe_TrStoragePhase.skip(cs)
|
||||
&& t_Maybe_TrCreditPhase.skip(cs)
|
||||
&& t_TrComputePhase.skip(cs)
|
||||
&& t_Maybe_Ref_TrActionPhase.skip(cs)
|
||||
@ -8932,6 +8934,7 @@ bool TransactionDescr::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
&& cs.advance(2);
|
||||
case trans_split_prepare:
|
||||
return cs.advance(528)
|
||||
&& t_Maybe_TrStoragePhase.validate_skip(cs, weak)
|
||||
&& t_TrComputePhase.validate_skip(cs, weak)
|
||||
&& t_Maybe_Ref_TrActionPhase.validate_skip(cs, weak)
|
||||
&& cs.advance(2);
|
||||
@ -8947,6 +8950,7 @@ bool TransactionDescr::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return cs.fetch_ulong(4) == 7
|
||||
&& cs.advance(524)
|
||||
&& t_Transaction.validate_skip_ref(cs, weak)
|
||||
&& t_Maybe_TrStoragePhase.validate_skip(cs, weak)
|
||||
&& t_Maybe_TrCreditPhase.validate_skip(cs, weak)
|
||||
&& t_TrComputePhase.validate_skip(cs, weak)
|
||||
&& t_Maybe_Ref_TrActionPhase.validate_skip(cs, weak)
|
||||
@ -8998,7 +9002,7 @@ bool TransactionDescr::cell_unpack_trans_storage(Ref<vm::Cell> cell_ref, Ref<Cel
|
||||
bool TransactionDescr::unpack(vm::CellSlice& cs, TransactionDescr::Record_trans_tick_tock& data) const {
|
||||
return cs.fetch_ulong(3) == 1
|
||||
&& cs.fetch_bool_to(data.is_tock)
|
||||
&& t_TrStoragePhase.fetch_to(cs, data.storage)
|
||||
&& t_TrStoragePhase.fetch_to(cs, data.storage_ph)
|
||||
&& t_TrComputePhase.fetch_to(cs, data.compute_ph)
|
||||
&& t_Maybe_Ref_TrActionPhase.fetch_to(cs, data.action)
|
||||
&& cs.fetch_bool_to(data.aborted)
|
||||
@ -9014,6 +9018,7 @@ bool TransactionDescr::cell_unpack(Ref<vm::Cell> cell_ref, TransactionDescr::Rec
|
||||
bool TransactionDescr::unpack(vm::CellSlice& cs, TransactionDescr::Record_trans_split_prepare& data) const {
|
||||
return cs.fetch_ulong(4) == 4
|
||||
&& cs.fetch_subslice_to(524, data.split_info)
|
||||
&& t_Maybe_TrStoragePhase.fetch_to(cs, data.storage_ph)
|
||||
&& t_TrComputePhase.fetch_to(cs, data.compute_ph)
|
||||
&& t_Maybe_Ref_TrActionPhase.fetch_to(cs, data.action)
|
||||
&& cs.fetch_bool_to(data.aborted)
|
||||
@ -9082,6 +9087,7 @@ bool TransactionDescr::unpack(vm::CellSlice& cs, TransactionDescr::Record_trans_
|
||||
return cs.fetch_ulong(4) == 7
|
||||
&& cs.fetch_subslice_to(524, data.split_info)
|
||||
&& cs.fetch_ref_to(data.prepare_transaction)
|
||||
&& t_Maybe_TrStoragePhase.fetch_to(cs, data.storage_ph)
|
||||
&& t_Maybe_TrCreditPhase.fetch_to(cs, data.credit_ph)
|
||||
&& t_TrComputePhase.fetch_to(cs, data.compute_ph)
|
||||
&& t_Maybe_Ref_TrActionPhase.fetch_to(cs, data.action)
|
||||
@ -9135,7 +9141,7 @@ bool TransactionDescr::cell_pack_trans_storage(Ref<vm::Cell>& cell_ref, Ref<Cell
|
||||
bool TransactionDescr::pack(vm::CellBuilder& cb, const TransactionDescr::Record_trans_tick_tock& data) const {
|
||||
return cb.store_long_bool(1, 3)
|
||||
&& cb.store_ulong_rchk_bool(data.is_tock, 1)
|
||||
&& t_TrStoragePhase.store_from(cb, data.storage)
|
||||
&& t_TrStoragePhase.store_from(cb, data.storage_ph)
|
||||
&& t_TrComputePhase.store_from(cb, data.compute_ph)
|
||||
&& t_Maybe_Ref_TrActionPhase.store_from(cb, data.action)
|
||||
&& cb.store_ulong_rchk_bool(data.aborted, 1)
|
||||
@ -9150,6 +9156,7 @@ bool TransactionDescr::cell_pack(Ref<vm::Cell>& cell_ref, const TransactionDescr
|
||||
bool TransactionDescr::pack(vm::CellBuilder& cb, const TransactionDescr::Record_trans_split_prepare& data) const {
|
||||
return cb.store_long_bool(4, 4)
|
||||
&& cb.append_cellslice_chk(data.split_info, 524)
|
||||
&& t_Maybe_TrStoragePhase.store_from(cb, data.storage_ph)
|
||||
&& t_TrComputePhase.store_from(cb, data.compute_ph)
|
||||
&& t_Maybe_Ref_TrActionPhase.store_from(cb, data.action)
|
||||
&& cb.store_ulong_rchk_bool(data.aborted, 1)
|
||||
@ -9213,6 +9220,7 @@ bool TransactionDescr::pack(vm::CellBuilder& cb, const TransactionDescr::Record_
|
||||
return cb.store_long_bool(7, 4)
|
||||
&& cb.append_cellslice_chk(data.split_info, 524)
|
||||
&& cb.store_ref_bool(data.prepare_transaction)
|
||||
&& t_Maybe_TrStoragePhase.store_from(cb, data.storage_ph)
|
||||
&& t_Maybe_TrCreditPhase.store_from(cb, data.credit_ph)
|
||||
&& t_TrComputePhase.store_from(cb, data.compute_ph)
|
||||
&& t_Maybe_Ref_TrActionPhase.store_from(cb, data.action)
|
||||
@ -9254,7 +9262,7 @@ bool TransactionDescr::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
|
||||
return cs.advance(3)
|
||||
&& pp.open("trans_tick_tock")
|
||||
&& pp.fetch_uint_field(cs, 1, "is_tock")
|
||||
&& pp.field("storage")
|
||||
&& pp.field("storage_ph")
|
||||
&& t_TrStoragePhase.print_skip(pp, cs)
|
||||
&& pp.field("compute_ph")
|
||||
&& t_TrComputePhase.print_skip(pp, cs)
|
||||
@ -9268,6 +9276,8 @@ bool TransactionDescr::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
|
||||
&& pp.open("trans_split_prepare")
|
||||
&& pp.field("split_info")
|
||||
&& t_SplitMergeInfo.print_skip(pp, cs)
|
||||
&& pp.field("storage_ph")
|
||||
&& t_Maybe_TrStoragePhase.print_skip(pp, cs)
|
||||
&& pp.field("compute_ph")
|
||||
&& t_TrComputePhase.print_skip(pp, cs)
|
||||
&& pp.field("action")
|
||||
@ -9300,6 +9310,8 @@ bool TransactionDescr::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
|
||||
&& t_SplitMergeInfo.print_skip(pp, cs)
|
||||
&& pp.field("prepare_transaction")
|
||||
&& t_Transaction.print_ref(pp, cs.fetch_ref())
|
||||
&& pp.field("storage_ph")
|
||||
&& t_Maybe_TrStoragePhase.print_skip(pp, cs)
|
||||
&& pp.field("credit_ph")
|
||||
&& t_Maybe_TrCreditPhase.print_skip(pp, cs)
|
||||
&& pp.field("compute_ph")
|
||||
@ -14089,11 +14101,13 @@ const StoragePrices t_StoragePrices;
|
||||
//
|
||||
// code for type `GasLimitsPrices`
|
||||
//
|
||||
constexpr unsigned char GasLimitsPrices::cons_tag[2];
|
||||
constexpr unsigned char GasLimitsPrices::cons_tag[3];
|
||||
|
||||
int GasLimitsPrices::get_tag(const vm::CellSlice& cs) const {
|
||||
switch (cs.bselect(6, 0x180000000000000ULL)) {
|
||||
switch (cs.bselect(6, 0x1b0000000000000ULL)) {
|
||||
case 0:
|
||||
return gas_flat_pfx;
|
||||
case 2:
|
||||
return cs.bit_at(6) ? gas_prices_ext : gas_prices;
|
||||
default:
|
||||
return -1;
|
||||
@ -14106,6 +14120,8 @@ int GasLimitsPrices::check_tag(const vm::CellSlice& cs) const {
|
||||
return cs.prefetch_ulong(8) == 0xdd ? gas_prices : -1;
|
||||
case gas_prices_ext:
|
||||
return cs.prefetch_ulong(8) == 0xde ? gas_prices_ext : -1;
|
||||
case gas_flat_pfx:
|
||||
return cs.prefetch_ulong(8) == 0xd1 ? gas_flat_pfx : -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -14116,6 +14132,9 @@ bool GasLimitsPrices::skip(vm::CellSlice& cs) const {
|
||||
return cs.advance(392);
|
||||
case gas_prices_ext:
|
||||
return cs.advance(456);
|
||||
case gas_flat_pfx:
|
||||
return cs.advance(136)
|
||||
&& skip(cs);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -14128,6 +14147,10 @@ bool GasLimitsPrices::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
case gas_prices_ext:
|
||||
return cs.fetch_ulong(8) == 0xde
|
||||
&& cs.advance(448);
|
||||
case gas_flat_pfx:
|
||||
return cs.fetch_ulong(8) == 0xd1
|
||||
&& cs.advance(128)
|
||||
&& validate_skip(cs, weak);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -14165,6 +14188,32 @@ bool GasLimitsPrices::cell_unpack(Ref<vm::Cell> cell_ref, GasLimitsPrices::Recor
|
||||
return unpack(cs, data) && cs.empty_ext();
|
||||
}
|
||||
|
||||
bool GasLimitsPrices::unpack(vm::CellSlice& cs, GasLimitsPrices::Record_gas_flat_pfx& data) const {
|
||||
return cs.fetch_ulong(8) == 0xd1
|
||||
&& cs.fetch_uint_to(64, data.flat_gas_limit)
|
||||
&& cs.fetch_uint_to(64, data.flat_gas_price)
|
||||
&& fetch_to(cs, data.other);
|
||||
}
|
||||
|
||||
bool GasLimitsPrices::unpack_gas_flat_pfx(vm::CellSlice& cs, unsigned long long& flat_gas_limit, unsigned long long& flat_gas_price, Ref<CellSlice>& other) const {
|
||||
return cs.fetch_ulong(8) == 0xd1
|
||||
&& cs.fetch_uint_to(64, flat_gas_limit)
|
||||
&& cs.fetch_uint_to(64, flat_gas_price)
|
||||
&& fetch_to(cs, other);
|
||||
}
|
||||
|
||||
bool GasLimitsPrices::cell_unpack(Ref<vm::Cell> cell_ref, GasLimitsPrices::Record_gas_flat_pfx& data) const {
|
||||
if (cell_ref.is_null()) { return false; }
|
||||
auto cs = load_cell_slice(std::move(cell_ref));
|
||||
return unpack(cs, data) && cs.empty_ext();
|
||||
}
|
||||
|
||||
bool GasLimitsPrices::cell_unpack_gas_flat_pfx(Ref<vm::Cell> cell_ref, unsigned long long& flat_gas_limit, unsigned long long& flat_gas_price, Ref<CellSlice>& other) const {
|
||||
if (cell_ref.is_null()) { return false; }
|
||||
auto cs = load_cell_slice(std::move(cell_ref));
|
||||
return unpack_gas_flat_pfx(cs, flat_gas_limit, flat_gas_price, other) && cs.empty_ext();
|
||||
}
|
||||
|
||||
bool GasLimitsPrices::pack(vm::CellBuilder& cb, const GasLimitsPrices::Record_gas_prices& data) const {
|
||||
return cb.store_long_bool(0xdd, 8)
|
||||
&& cb.store_ulong_rchk_bool(data.gas_price, 64)
|
||||
@ -14196,6 +14245,30 @@ bool GasLimitsPrices::cell_pack(Ref<vm::Cell>& cell_ref, const GasLimitsPrices::
|
||||
return pack(cb, data) && std::move(cb).finalize_to(cell_ref);
|
||||
}
|
||||
|
||||
bool GasLimitsPrices::pack(vm::CellBuilder& cb, const GasLimitsPrices::Record_gas_flat_pfx& data) const {
|
||||
return cb.store_long_bool(0xd1, 8)
|
||||
&& cb.store_ulong_rchk_bool(data.flat_gas_limit, 64)
|
||||
&& cb.store_ulong_rchk_bool(data.flat_gas_price, 64)
|
||||
&& store_from(cb, data.other);
|
||||
}
|
||||
|
||||
bool GasLimitsPrices::pack_gas_flat_pfx(vm::CellBuilder& cb, unsigned long long flat_gas_limit, unsigned long long flat_gas_price, Ref<CellSlice> other) const {
|
||||
return cb.store_long_bool(0xd1, 8)
|
||||
&& cb.store_ulong_rchk_bool(flat_gas_limit, 64)
|
||||
&& cb.store_ulong_rchk_bool(flat_gas_price, 64)
|
||||
&& store_from(cb, other);
|
||||
}
|
||||
|
||||
bool GasLimitsPrices::cell_pack(Ref<vm::Cell>& cell_ref, const GasLimitsPrices::Record_gas_flat_pfx& data) const {
|
||||
vm::CellBuilder cb;
|
||||
return pack(cb, data) && std::move(cb).finalize_to(cell_ref);
|
||||
}
|
||||
|
||||
bool GasLimitsPrices::cell_pack_gas_flat_pfx(Ref<vm::Cell>& cell_ref, unsigned long long flat_gas_limit, unsigned long long flat_gas_price, Ref<CellSlice> other) const {
|
||||
vm::CellBuilder cb;
|
||||
return pack_gas_flat_pfx(cb, flat_gas_limit, flat_gas_price, std::move(other)) && std::move(cb).finalize_to(cell_ref);
|
||||
}
|
||||
|
||||
bool GasLimitsPrices::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
|
||||
switch (get_tag(cs)) {
|
||||
case gas_prices:
|
||||
@ -14219,6 +14292,14 @@ bool GasLimitsPrices::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
|
||||
&& pp.fetch_uint_field(cs, 64, "freeze_due_limit")
|
||||
&& pp.fetch_uint_field(cs, 64, "delete_due_limit")
|
||||
&& pp.close();
|
||||
case gas_flat_pfx:
|
||||
return cs.fetch_ulong(8) == 0xd1
|
||||
&& pp.open("gas_flat_pfx")
|
||||
&& pp.fetch_uint_field(cs, 64, "flat_gas_limit")
|
||||
&& pp.fetch_uint_field(cs, 64, "flat_gas_price")
|
||||
&& pp.field("other")
|
||||
&& print_skip(pp, cs)
|
||||
&& pp.close();
|
||||
}
|
||||
return pp.fail("unknown constructor for GasLimitsPrices");
|
||||
}
|
||||
|
@ -3831,24 +3831,25 @@ struct TransactionDescr::Record_trans_ord {
|
||||
struct TransactionDescr::Record_trans_tick_tock {
|
||||
typedef TransactionDescr type_class;
|
||||
bool is_tock; // is_tock : Bool
|
||||
Ref<CellSlice> storage; // storage : TrStoragePhase
|
||||
Ref<CellSlice> storage_ph; // storage_ph : TrStoragePhase
|
||||
Ref<CellSlice> compute_ph; // compute_ph : TrComputePhase
|
||||
Ref<CellSlice> action; // action : Maybe ^TrActionPhase
|
||||
bool aborted; // aborted : Bool
|
||||
bool destroyed; // destroyed : Bool
|
||||
Record_trans_tick_tock() = default;
|
||||
Record_trans_tick_tock(bool _is_tock, Ref<CellSlice> _storage, Ref<CellSlice> _compute_ph, Ref<CellSlice> _action, bool _aborted, bool _destroyed) : is_tock(_is_tock), storage(std::move(_storage)), compute_ph(std::move(_compute_ph)), action(std::move(_action)), aborted(_aborted), destroyed(_destroyed) {}
|
||||
Record_trans_tick_tock(bool _is_tock, Ref<CellSlice> _storage_ph, Ref<CellSlice> _compute_ph, Ref<CellSlice> _action, bool _aborted, bool _destroyed) : is_tock(_is_tock), storage_ph(std::move(_storage_ph)), compute_ph(std::move(_compute_ph)), action(std::move(_action)), aborted(_aborted), destroyed(_destroyed) {}
|
||||
};
|
||||
|
||||
struct TransactionDescr::Record_trans_split_prepare {
|
||||
typedef TransactionDescr type_class;
|
||||
Ref<CellSlice> split_info; // split_info : SplitMergeInfo
|
||||
Ref<CellSlice> storage_ph; // storage_ph : Maybe TrStoragePhase
|
||||
Ref<CellSlice> compute_ph; // compute_ph : TrComputePhase
|
||||
Ref<CellSlice> action; // action : Maybe ^TrActionPhase
|
||||
bool aborted; // aborted : Bool
|
||||
bool destroyed; // destroyed : Bool
|
||||
Record_trans_split_prepare() = default;
|
||||
Record_trans_split_prepare(Ref<CellSlice> _split_info, Ref<CellSlice> _compute_ph, Ref<CellSlice> _action, bool _aborted, bool _destroyed) : split_info(std::move(_split_info)), compute_ph(std::move(_compute_ph)), action(std::move(_action)), aborted(_aborted), destroyed(_destroyed) {}
|
||||
Record_trans_split_prepare(Ref<CellSlice> _split_info, Ref<CellSlice> _storage_ph, Ref<CellSlice> _compute_ph, Ref<CellSlice> _action, bool _aborted, bool _destroyed) : split_info(std::move(_split_info)), storage_ph(std::move(_storage_ph)), compute_ph(std::move(_compute_ph)), action(std::move(_action)), aborted(_aborted), destroyed(_destroyed) {}
|
||||
};
|
||||
|
||||
struct TransactionDescr::Record_trans_split_install {
|
||||
@ -3873,13 +3874,14 @@ struct TransactionDescr::Record_trans_merge_install {
|
||||
typedef TransactionDescr type_class;
|
||||
Ref<CellSlice> split_info; // split_info : SplitMergeInfo
|
||||
Ref<Cell> prepare_transaction; // prepare_transaction : ^Transaction
|
||||
Ref<CellSlice> storage_ph; // storage_ph : Maybe TrStoragePhase
|
||||
Ref<CellSlice> credit_ph; // credit_ph : Maybe TrCreditPhase
|
||||
Ref<CellSlice> compute_ph; // compute_ph : TrComputePhase
|
||||
Ref<CellSlice> action; // action : Maybe ^TrActionPhase
|
||||
bool aborted; // aborted : Bool
|
||||
bool destroyed; // destroyed : Bool
|
||||
Record_trans_merge_install() = default;
|
||||
Record_trans_merge_install(Ref<CellSlice> _split_info, Ref<Cell> _prepare_transaction, Ref<CellSlice> _credit_ph, Ref<CellSlice> _compute_ph, Ref<CellSlice> _action, bool _aborted, bool _destroyed) : split_info(std::move(_split_info)), prepare_transaction(std::move(_prepare_transaction)), credit_ph(std::move(_credit_ph)), compute_ph(std::move(_compute_ph)), action(std::move(_action)), aborted(_aborted), destroyed(_destroyed) {}
|
||||
Record_trans_merge_install(Ref<CellSlice> _split_info, Ref<Cell> _prepare_transaction, Ref<CellSlice> _storage_ph, Ref<CellSlice> _credit_ph, Ref<CellSlice> _compute_ph, Ref<CellSlice> _action, bool _aborted, bool _destroyed) : split_info(std::move(_split_info)), prepare_transaction(std::move(_prepare_transaction)), storage_ph(std::move(_storage_ph)), credit_ph(std::move(_credit_ph)), compute_ph(std::move(_compute_ph)), action(std::move(_action)), aborted(_aborted), destroyed(_destroyed) {}
|
||||
};
|
||||
|
||||
extern const TransactionDescr t_TransactionDescr;
|
||||
@ -6166,11 +6168,12 @@ extern const StoragePrices t_StoragePrices;
|
||||
//
|
||||
|
||||
struct GasLimitsPrices final : TLB_Complex {
|
||||
enum { gas_prices, gas_prices_ext };
|
||||
enum { gas_flat_pfx, gas_prices, gas_prices_ext };
|
||||
static constexpr int cons_len_exact = 8;
|
||||
static constexpr unsigned char cons_tag[2] = { 0xdd, 0xde };
|
||||
static constexpr unsigned char cons_tag[3] = { 0xd1, 0xdd, 0xde };
|
||||
struct Record_gas_prices;
|
||||
struct Record_gas_prices_ext;
|
||||
struct Record_gas_flat_pfx;
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool unpack(vm::CellSlice& cs, Record_gas_prices& data) const;
|
||||
@ -6181,6 +6184,14 @@ struct GasLimitsPrices final : TLB_Complex {
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record_gas_prices_ext& data) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record_gas_prices_ext& data) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record_gas_prices_ext& data) const;
|
||||
bool unpack(vm::CellSlice& cs, Record_gas_flat_pfx& data) const;
|
||||
bool unpack_gas_flat_pfx(vm::CellSlice& cs, unsigned long long& flat_gas_limit, unsigned long long& flat_gas_price, Ref<CellSlice>& other) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record_gas_flat_pfx& data) const;
|
||||
bool cell_unpack_gas_flat_pfx(Ref<vm::Cell> cell_ref, unsigned long long& flat_gas_limit, unsigned long long& flat_gas_price, Ref<CellSlice>& other) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record_gas_flat_pfx& data) const;
|
||||
bool pack_gas_flat_pfx(vm::CellBuilder& cb, unsigned long long flat_gas_limit, unsigned long long flat_gas_price, Ref<CellSlice> other) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record_gas_flat_pfx& data) const;
|
||||
bool cell_pack_gas_flat_pfx(Ref<vm::Cell>& cell_ref, unsigned long long flat_gas_limit, unsigned long long flat_gas_price, Ref<CellSlice> other) const;
|
||||
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
|
||||
std::ostream& print_type(std::ostream& os) const override {
|
||||
return os << "GasLimitsPrices";
|
||||
@ -6214,6 +6225,15 @@ struct GasLimitsPrices::Record_gas_prices_ext {
|
||||
Record_gas_prices_ext(unsigned long long _gas_price, unsigned long long _gas_limit, unsigned long long _special_gas_limit, unsigned long long _gas_credit, unsigned long long _block_gas_limit, unsigned long long _freeze_due_limit, unsigned long long _delete_due_limit) : gas_price(_gas_price), gas_limit(_gas_limit), special_gas_limit(_special_gas_limit), gas_credit(_gas_credit), block_gas_limit(_block_gas_limit), freeze_due_limit(_freeze_due_limit), delete_due_limit(_delete_due_limit) {}
|
||||
};
|
||||
|
||||
struct GasLimitsPrices::Record_gas_flat_pfx {
|
||||
typedef GasLimitsPrices type_class;
|
||||
unsigned long long flat_gas_limit; // flat_gas_limit : uint64
|
||||
unsigned long long flat_gas_price; // flat_gas_price : uint64
|
||||
Ref<CellSlice> other; // other : GasLimitsPrices
|
||||
Record_gas_flat_pfx() = default;
|
||||
Record_gas_flat_pfx(unsigned long long _flat_gas_limit, unsigned long long _flat_gas_price, Ref<CellSlice> _other) : flat_gas_limit(_flat_gas_limit), flat_gas_price(_flat_gas_price), other(std::move(_other)) {}
|
||||
};
|
||||
|
||||
extern const GasLimitsPrices t_GasLimitsPrices;
|
||||
|
||||
//
|
||||
@ -6522,7 +6542,7 @@ extern const ValidatorSignedTempKey t_ValidatorSignedTempKey;
|
||||
//
|
||||
|
||||
struct ConfigParam final : TLB_Complex {
|
||||
enum { cons32, cons33, cons34, cons35, cons36, cons37, config_mc_block_limits, config_block_limits, cons14, cons0, cons1, cons2, cons3, cons4, cons6, cons7, cons9, cons12, cons15, cons16, cons17, cons18, cons31, cons39, cons28, cons8, cons29, config_mc_gas_prices, config_gas_prices, config_mc_fwd_prices, config_fwd_prices };
|
||||
enum { cons32, cons33, cons34, cons35, cons36, cons37, config_mc_block_limits, config_block_limits, cons14, cons0, cons1, cons2, cons3, cons4, cons6, cons7, cons9, cons12, cons15, cons16, cons17, cons18, cons31, cons39, cons28, cons8, config_mc_gas_prices, config_gas_prices, cons29, config_mc_fwd_prices, config_fwd_prices };
|
||||
static constexpr int cons_len_exact = 0;
|
||||
int m_;
|
||||
ConfigParam(int m) : m_(m) {}
|
||||
|
@ -1143,6 +1143,20 @@ bool TrStoragePhase::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
&& t_AccStatusChange.validate_skip(cs, weak); // status_change:AccStatusChange
|
||||
}
|
||||
|
||||
bool TrStoragePhase::get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const {
|
||||
return t_Grams.as_integer_skip_to(cs, storage_fees); // storage_fees_collected:Grams
|
||||
}
|
||||
|
||||
bool TrStoragePhase::maybe_get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const {
|
||||
auto z = cs.fetch_ulong(1);
|
||||
if (!z) {
|
||||
storage_fees = td::make_refint(0);
|
||||
return true;
|
||||
} else {
|
||||
return z == 1 && get_storage_fees(cs, storage_fees);
|
||||
}
|
||||
}
|
||||
|
||||
const TrStoragePhase t_TrStoragePhase;
|
||||
|
||||
bool TrCreditPhase::skip(vm::CellSlice& cs) const {
|
||||
@ -1322,13 +1336,14 @@ bool TransactionDescr::skip(vm::CellSlice& cs) const {
|
||||
&& t_TrStoragePhase.skip(cs); // storage_ph:TrStoragePhase
|
||||
case trans_tick_tock:
|
||||
return cs.advance(4) // trans_tick_tock$001 is_tock:Bool
|
||||
&& t_TrStoragePhase.skip(cs) // storage:TrStoragePhase
|
||||
&& t_TrStoragePhase.skip(cs) // storage_ph:TrStoragePhase
|
||||
&& t_TrComputePhase.skip(cs) // compute_ph:TrComputePhase
|
||||
&& Maybe<RefTo<TrActionPhase>>{}.skip(cs) // action:(Maybe ^TrActionPhase)
|
||||
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
||||
case trans_split_prepare:
|
||||
return cs.advance(4) // trans_split_prepare$0100
|
||||
&& t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo
|
||||
&& Maybe<TrStoragePhase>{}.skip(cs) // storage_ph:(Maybe TrStoragePhase)
|
||||
&& t_TrComputePhase.skip(cs) // compute_ph:TrComputePhase
|
||||
&& Maybe<RefTo<TrActionPhase>>{}.skip(cs) // action:(Maybe ^TrActionPhase)
|
||||
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
||||
@ -1346,6 +1361,7 @@ bool TransactionDescr::skip(vm::CellSlice& cs) const {
|
||||
return cs.advance(4) // trans_merge_install$0111
|
||||
&& t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo
|
||||
&& t_Ref_Transaction.skip(cs) // prepare_transaction:^Transaction
|
||||
&& Maybe<TrStoragePhase>{}.skip(cs) // storage_ph:(Maybe TrStoragePhase)
|
||||
&& Maybe<TrCreditPhase>{}.skip(cs) // credit_ph:(Maybe TrCreditPhase)
|
||||
&& Maybe<TrComputePhase>{}.skip(cs) // compute_ph:TrComputePhase
|
||||
&& Maybe<RefTo<TrActionPhase>>{}.skip(cs) // action:(Maybe ^TrActionPhase)
|
||||
@ -1370,13 +1386,14 @@ bool TransactionDescr::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
&& t_TrStoragePhase.validate_skip(cs, weak); // storage_ph:TrStoragePhase
|
||||
case trans_tick_tock:
|
||||
return cs.advance(4) // trans_tick_tock$001 is_tock:Bool
|
||||
&& t_TrStoragePhase.validate_skip(cs, weak) // storage:TrStoragePhase
|
||||
&& t_TrStoragePhase.validate_skip(cs, weak) // storage_ph:TrStoragePhase
|
||||
&& t_TrComputePhase.validate_skip(cs, weak) // compute_ph:TrComputePhase
|
||||
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase)
|
||||
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
||||
case trans_split_prepare:
|
||||
return cs.advance(4) // trans_split_prepare$0100
|
||||
&& t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo
|
||||
&& Maybe<TrStoragePhase>{}.validate_skip(cs, weak) // storage_ph:(Maybe TrStoragePhase)
|
||||
&& t_TrComputePhase.validate_skip(cs, weak) // compute_ph:TrComputePhase
|
||||
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase)
|
||||
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
||||
@ -1394,6 +1411,7 @@ bool TransactionDescr::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return cs.advance(4) // trans_merge_install$0111
|
||||
&& t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo
|
||||
&& t_Ref_Transaction.validate_skip(cs, weak) // prepare_transaction:^Transaction
|
||||
&& Maybe<TrStoragePhase>{}.validate_skip(cs, weak) // storage_ph:(Maybe TrStoragePhase)
|
||||
&& Maybe<TrCreditPhase>{}.validate_skip(cs, weak) // credit_ph:(Maybe TrCreditPhase)
|
||||
&& Maybe<TrComputePhase>{}.validate_skip(cs, weak) // compute_ph:TrComputePhase
|
||||
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase)
|
||||
@ -1407,6 +1425,53 @@ int TransactionDescr::get_tag(const vm::CellSlice& cs) const {
|
||||
return (t >= 0 && t <= 7) ? (t == 3 ? 2 : t) : -1;
|
||||
}
|
||||
|
||||
bool TransactionDescr::skip_to_storage_phase(vm::CellSlice& cs, bool& found) const {
|
||||
found = false;
|
||||
switch (get_tag(cs)) {
|
||||
case trans_ord:
|
||||
return cs.advance(4 + 1) // trans_ord$0000 storage_first:Bool
|
||||
&& cs.fetch_bool_to(found); // storage_ph:(Maybe TrStoragePhase)
|
||||
case trans_storage:
|
||||
return cs.advance(4) // trans_storage$0001
|
||||
&& (found = true); // storage_ph:TrStoragePhase
|
||||
case trans_tick_tock:
|
||||
return cs.advance(4) // trans_tick_tock$001 is_tock:Bool
|
||||
&& (found = true); // storage_ph:TrStoragePhase
|
||||
case trans_split_prepare:
|
||||
return cs.advance(4) // trans_split_prepare$0100
|
||||
&& t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo
|
||||
&& cs.fetch_bool_to(found); // storage_ph:(Maybe TrStoragePhase)
|
||||
case trans_split_install:
|
||||
return true;
|
||||
case trans_merge_prepare:
|
||||
return cs.advance(4) // trans_merge_prepare$0110
|
||||
&& t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo
|
||||
&& (found = true); // storage_ph:TrStoragePhase
|
||||
case trans_merge_install:
|
||||
return cs.advance(4) // trans_merge_install$0111
|
||||
&& t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo
|
||||
&& t_Ref_Transaction.skip(cs) // prepare_transaction:^Transaction
|
||||
&& cs.fetch_bool_to(found); // storage_ph:(Maybe TrStoragePhase)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TransactionDescr::get_storage_fees(Ref<vm::Cell> cell, td::RefInt256& storage_fees) const {
|
||||
if (cell.is_null()) {
|
||||
return false;
|
||||
}
|
||||
auto cs = vm::load_cell_slice(std::move(cell));
|
||||
bool found;
|
||||
if (!skip_to_storage_phase(cs, found)) {
|
||||
return false;
|
||||
} else if (found) {
|
||||
return t_TrStoragePhase.get_storage_fees(cs, storage_fees);
|
||||
} else {
|
||||
storage_fees = td::make_refint(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const TransactionDescr t_TransactionDescr;
|
||||
|
||||
bool Transaction_aux::skip(vm::CellSlice& cs) const {
|
||||
@ -1447,6 +1512,32 @@ bool Transaction::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
&& RefTo<TransactionDescr>{}.validate_skip(cs, weak); // description:^TransactionDescr
|
||||
}
|
||||
|
||||
bool Transaction::get_storage_fees(Ref<vm::Cell> cell, td::RefInt256& storage_fees) const {
|
||||
Ref<vm::Cell> tdescr;
|
||||
return get_descr(std::move(cell), tdescr) && t_TransactionDescr.get_storage_fees(std::move(tdescr), storage_fees);
|
||||
}
|
||||
|
||||
bool Transaction::get_descr(Ref<vm::Cell> cell, Ref<vm::Cell>& tdescr) const {
|
||||
if (cell.is_null()) {
|
||||
return false;
|
||||
} else {
|
||||
auto cs = vm::load_cell_slice(std::move(cell));
|
||||
return cs.is_valid() && get_descr(cs, tdescr) && cs.empty_ext();
|
||||
}
|
||||
}
|
||||
|
||||
bool Transaction::get_descr(vm::CellSlice& cs, Ref<vm::Cell>& tdescr) const {
|
||||
return cs.advance(
|
||||
4 + 256 + 64 + 256 + 64 + 32 +
|
||||
15) // transaction$0111 account_addr:uint256 lt:uint64 prev_trans_hash:bits256 prev_trans_lt:uint64 now:uint32 outmsg_cnt:uint15
|
||||
&& t_AccountStatus.skip(cs) // orig_status:AccountStatus
|
||||
&& t_AccountStatus.skip(cs) // end_status:AccountStatus
|
||||
&& cs.advance_refs(1) // ^[ in_msg:(Maybe ^Message) out_msgs:(HashmapE 15 ^Message) ]
|
||||
&& t_CurrencyCollection.skip(cs) // total_fees:CurrencyCollection
|
||||
&& cs.advance_refs(1) // state_update:^(MERKLE_UPDATE Account)
|
||||
&& cs.fetch_ref_to(tdescr); // description:^TransactionDescr
|
||||
}
|
||||
|
||||
bool Transaction::get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const {
|
||||
return cs.is_valid() && cs.fetch_ulong(4) == 7 // transaction$0111
|
||||
&&
|
||||
|
@ -614,6 +614,8 @@ extern const AccStatusChange t_AccStatusChange;
|
||||
struct TrStoragePhase final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const;
|
||||
bool maybe_get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const;
|
||||
};
|
||||
|
||||
extern const TrStoragePhase t_TrStoragePhase;
|
||||
@ -693,6 +695,8 @@ struct TransactionDescr final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override;
|
||||
bool skip_to_storage_phase(vm::CellSlice& cs, bool& found) const;
|
||||
bool get_storage_fees(Ref<vm::Cell> cell, td::RefInt256& storage_fees) const;
|
||||
};
|
||||
|
||||
extern const TransactionDescr t_TransactionDescr;
|
||||
@ -708,6 +712,9 @@ struct Transaction final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const;
|
||||
bool get_descr(Ref<vm::Cell> cell, Ref<vm::Cell>& tdescr) const;
|
||||
bool get_descr(vm::CellSlice& cs, Ref<vm::Cell>& tdescr) const;
|
||||
bool get_storage_fees(Ref<vm::Cell> cell, td::RefInt256& storage_fees) const;
|
||||
};
|
||||
|
||||
extern const Transaction t_Transaction;
|
||||
|
@ -368,14 +368,14 @@ std::unique_ptr<MsgProcessedUptoCollection> MsgProcessedUptoCollection::unpack(t
|
||||
return v && v->valid ? std::move(v) : std::unique_ptr<MsgProcessedUptoCollection>{};
|
||||
}
|
||||
|
||||
bool MsgProcessedUpto::contains(const MsgProcessedUpto& other) const& {
|
||||
bool MsgProcessedUpto::contains(const MsgProcessedUpto& other) const & {
|
||||
return ton::shard_is_ancestor(shard, other.shard) && mc_seqno >= other.mc_seqno &&
|
||||
(last_inmsg_lt > other.last_inmsg_lt ||
|
||||
(last_inmsg_lt == other.last_inmsg_lt && !(last_inmsg_hash < other.last_inmsg_hash)));
|
||||
}
|
||||
|
||||
bool MsgProcessedUpto::contains(ton::ShardId other_shard, ton::LogicalTime other_lt, td::ConstBitPtr other_hash,
|
||||
ton::BlockSeqno other_mc_seqno) const& {
|
||||
ton::BlockSeqno other_mc_seqno) const & {
|
||||
return ton::shard_is_ancestor(shard, other_shard) && mc_seqno >= other_mc_seqno &&
|
||||
(last_inmsg_lt > other_lt || (last_inmsg_lt == other_lt && !(last_inmsg_hash < other_hash)));
|
||||
}
|
||||
@ -552,7 +552,9 @@ bool MsgProcessedUpto::already_processed(const EnqueuedMsgDescr& msg) const {
|
||||
if (msg.lt_ == last_inmsg_lt && last_inmsg_hash < msg.hash_) {
|
||||
return false;
|
||||
}
|
||||
if (ton::shard_contains(shard, msg.cur_prefix_.account_id_prefix)) {
|
||||
if (msg.same_workchain() && ton::shard_contains(shard, msg.cur_prefix_.account_id_prefix)) {
|
||||
// this branch is needed only for messages generated in the same shard
|
||||
// (such messages could have been processed without a reference from the masterchain)
|
||||
// ? enable this branch only if an extra boolean parameter is set ?
|
||||
return true;
|
||||
}
|
||||
|
@ -145,6 +145,9 @@ struct EnqueuedMsgDescr {
|
||||
return false;
|
||||
}
|
||||
bool unpack(vm::CellSlice& cs);
|
||||
bool same_workchain() const {
|
||||
return cur_prefix_.workchain == next_prefix_.workchain;
|
||||
}
|
||||
};
|
||||
|
||||
using compute_shard_end_lt_func_t = std::function<ton::LogicalTime(ton::AccountIdPrefixFull)>;
|
||||
|
@ -325,7 +325,7 @@ trans_ord$0000 credit_first:Bool
|
||||
trans_storage$0001 storage_ph:TrStoragePhase
|
||||
= TransactionDescr;
|
||||
|
||||
trans_tick_tock$001 is_tock:Bool storage:TrStoragePhase
|
||||
trans_tick_tock$001 is_tock:Bool storage_ph:TrStoragePhase
|
||||
compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)
|
||||
aborted:Bool destroyed:Bool = TransactionDescr;
|
||||
//
|
||||
@ -333,6 +333,7 @@ split_merge_info$_ cur_shard_pfx_len:(## 6)
|
||||
acc_split_depth:(## 6) this_addr:bits256 sibling_addr:bits256
|
||||
= SplitMergeInfo;
|
||||
trans_split_prepare$0100 split_info:SplitMergeInfo
|
||||
storage_ph:(Maybe TrStoragePhase)
|
||||
compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)
|
||||
aborted:Bool destroyed:Bool
|
||||
= TransactionDescr;
|
||||
@ -345,6 +346,7 @@ trans_merge_prepare$0110 split_info:SplitMergeInfo
|
||||
= TransactionDescr;
|
||||
trans_merge_install$0111 split_info:SplitMergeInfo
|
||||
prepare_transaction:^Transaction
|
||||
storage_ph:(Maybe TrStoragePhase)
|
||||
credit_ph:(Maybe TrCreditPhase)
|
||||
compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)
|
||||
aborted:Bool destroyed:Bool
|
||||
@ -609,6 +611,9 @@ gas_prices_ext#de gas_price:uint64 gas_limit:uint64 special_gas_limit:uint64 gas
|
||||
block_gas_limit:uint64 freeze_due_limit:uint64 delete_due_limit:uint64
|
||||
= GasLimitsPrices;
|
||||
|
||||
gas_flat_pfx#d1 flat_gas_limit:uint64 flat_gas_price:uint64 other:GasLimitsPrices
|
||||
= GasLimitsPrices;
|
||||
|
||||
config_mc_gas_prices#_ GasLimitsPrices = ConfigParam 20;
|
||||
config_gas_prices#_ GasLimitsPrices = ConfigParam 21;
|
||||
|
||||
|
@ -672,9 +672,56 @@ bool Transaction::prepare_credit_phase() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ComputePhaseConfig::parse_GasLimitsPrices(Ref<vm::Cell> cell, td::RefInt256& freeze_due_limit,
|
||||
td::RefInt256& delete_due_limit) {
|
||||
return cell.not_null() &&
|
||||
parse_GasLimitsPrices(vm::load_cell_slice_ref(std::move(cell)), freeze_due_limit, delete_due_limit);
|
||||
}
|
||||
|
||||
bool ComputePhaseConfig::parse_GasLimitsPrices(Ref<vm::CellSlice> cs, td::RefInt256& freeze_due_limit,
|
||||
td::RefInt256& delete_due_limit) {
|
||||
if (cs.is_null()) {
|
||||
return false;
|
||||
}
|
||||
block::gen::GasLimitsPrices::Record_gas_flat_pfx flat;
|
||||
if (tlb::csr_unpack(cs, flat)) {
|
||||
bool ok = parse_GasLimitsPrices(std::move(flat.other), freeze_due_limit, delete_due_limit);
|
||||
flat_gas_limit = flat.flat_gas_limit;
|
||||
flat_gas_price = flat.flat_gas_price;
|
||||
return ok;
|
||||
}
|
||||
flat_gas_limit = flat_gas_price = 0;
|
||||
auto f = [&](const auto& r, td::uint64 spec_limit) {
|
||||
gas_limit = r.gas_limit;
|
||||
special_gas_limit = spec_limit;
|
||||
gas_credit = r.gas_credit;
|
||||
gas_price = r.gas_price;
|
||||
freeze_due_limit = td::RefInt256{true, r.freeze_due_limit};
|
||||
delete_due_limit = td::RefInt256{true, r.delete_due_limit};
|
||||
};
|
||||
block::gen::GasLimitsPrices::Record_gas_prices_ext rec;
|
||||
if (tlb::csr_unpack(cs, rec)) {
|
||||
f(rec, rec.special_gas_limit);
|
||||
} else {
|
||||
block::gen::GasLimitsPrices::Record_gas_prices rec0;
|
||||
if (tlb::csr_unpack(std::move(cs), rec0)) {
|
||||
f(rec0, rec0.gas_limit);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
compute_threshold();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ComputePhaseConfig::compute_threshold() {
|
||||
gas_price256 = td::RefInt256{true, gas_price};
|
||||
max_gas_threshold = td::rshift(gas_price256 * gas_limit, 16, 1);
|
||||
if (gas_limit > flat_gas_limit) {
|
||||
max_gas_threshold =
|
||||
td::rshift(gas_price256 * (gas_limit - flat_gas_limit), 16, 1) + td::make_refint(flat_gas_price);
|
||||
} else {
|
||||
max_gas_threshold = td::make_refint(flat_gas_price);
|
||||
}
|
||||
}
|
||||
|
||||
td::uint64 ComputePhaseConfig::gas_bought_for(td::RefInt256 nanograms) const {
|
||||
@ -684,8 +731,11 @@ td::uint64 ComputePhaseConfig::gas_bought_for(td::RefInt256 nanograms) const {
|
||||
if (nanograms >= max_gas_threshold) {
|
||||
return gas_limit;
|
||||
}
|
||||
auto res = td::div(std::move(nanograms) << 16, gas_price256);
|
||||
return res->to_long();
|
||||
if (nanograms < flat_gas_price) {
|
||||
return 0;
|
||||
}
|
||||
auto res = td::div((std::move(nanograms) - flat_gas_price) << 16, gas_price256);
|
||||
return res->to_long() + flat_gas_limit;
|
||||
}
|
||||
|
||||
td::RefInt256 ComputePhaseConfig::compute_gas_price(td::uint64 gas_used) const {
|
||||
@ -855,6 +905,16 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
|
||||
cp.skip_reason = ComputePhase::sk_no_gas;
|
||||
return true;
|
||||
}
|
||||
// Compute gas limits
|
||||
if (!compute_gas_limits(cp, cfg)) {
|
||||
compute_phase.reset();
|
||||
return false;
|
||||
}
|
||||
if (!cp.gas_limit && !cp.gas_credit) {
|
||||
// no gas
|
||||
cp.skip_reason = ComputePhase::sk_no_gas;
|
||||
return true;
|
||||
}
|
||||
if (in_msg_state.not_null()) {
|
||||
LOG(DEBUG) << "HASH(in_msg_state) = " << in_msg_state->get_hash().bits().to_hex(256)
|
||||
<< ", account_state_hash = " << account.state_hash.to_hex();
|
||||
@ -883,11 +943,6 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
|
||||
} else if (in_msg_state.not_null()) {
|
||||
unpack_msg_state(true); // use only libraries
|
||||
}
|
||||
// Compute gas limits
|
||||
if (!compute_gas_limits(cp, cfg)) {
|
||||
compute_phase.reset();
|
||||
return false;
|
||||
}
|
||||
// initialize VM
|
||||
Ref<vm::Stack> stack = prepare_vm_stack(cp);
|
||||
if (stack.is_null()) {
|
||||
|
@ -98,6 +98,8 @@ struct ComputePhaseConfig {
|
||||
td::uint64 gas_limit;
|
||||
td::uint64 special_gas_limit;
|
||||
td::uint64 gas_credit;
|
||||
td::uint64 flat_gas_limit = 0;
|
||||
td::uint64 flat_gas_price = 0;
|
||||
static constexpr td::uint64 gas_infty = (1ULL << 63) - 1;
|
||||
td::RefInt256 gas_price256;
|
||||
td::RefInt256 max_gas_threshold;
|
||||
@ -126,6 +128,8 @@ struct ComputePhaseConfig {
|
||||
Ref<vm::Cell> get_lib_root() const {
|
||||
return libraries ? libraries->get_root_cell() : Ref<vm::Cell>{};
|
||||
}
|
||||
bool parse_GasLimitsPrices(Ref<vm::CellSlice> cs, td::RefInt256& freeze_due_limit, td::RefInt256& delete_due_limit);
|
||||
bool parse_GasLimitsPrices(Ref<vm::Cell> cell, td::RefInt256& freeze_due_limit, td::RefInt256& delete_due_limit);
|
||||
};
|
||||
|
||||
// msg_fwd_fees = (lump_price + ceil((bit_price * msg.bits + cell_price * msg.cells)/2^16)) nanograms
|
||||
|
@ -79,7 +79,7 @@ class SourceLookup {
|
||||
if (os_time_) {
|
||||
return os_time_->now();
|
||||
}
|
||||
return static_cast<td::uint32>(td::Time::now());
|
||||
return static_cast<td::uint32>(td::Clocks::system());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -25,7 +25,7 @@
|
||||
{ bl word 1 { -rot 2 'nop does swap 0 (create) }
|
||||
} :: 2=:
|
||||
{ <b swap s, b> } : s>c
|
||||
{ s>c hash } : shash
|
||||
{ s>c hashB } : shash
|
||||
// to be more efficiently re-implemented in C++ in the future
|
||||
{ dup 0< ' negate if } : abs
|
||||
{ 2dup > ' swap if } : minmax
|
||||
|
@ -764,13 +764,17 @@ void interpret_string_to_bytes(vm::Stack& stack) {
|
||||
stack.push_bytes(stack.pop_string());
|
||||
}
|
||||
|
||||
void interpret_bytes_hash(vm::Stack& stack) {
|
||||
void interpret_bytes_hash(vm::Stack& stack, bool as_uint) {
|
||||
std::string str = stack.pop_bytes();
|
||||
unsigned char buffer[32];
|
||||
digest::hash_str<digest::SHA256>(buffer, str.c_str(), str.size());
|
||||
td::RefInt256 x{true};
|
||||
x.write().import_bytes(buffer, 32, false);
|
||||
stack.push_int(std::move(x));
|
||||
if (as_uint) {
|
||||
td::RefInt256 x{true};
|
||||
x.write().import_bytes(buffer, 32, false);
|
||||
stack.push_int(std::move(x));
|
||||
} else {
|
||||
stack.push_bytes(std::string{(char*)buffer, 32});
|
||||
}
|
||||
}
|
||||
|
||||
void interpret_empty(vm::Stack& stack) {
|
||||
@ -892,11 +896,15 @@ void interpret_builder_remaining_bitrefs(vm::Stack& stack, int mode) {
|
||||
}
|
||||
}
|
||||
|
||||
void interpret_cell_hash(vm::Stack& stack) {
|
||||
void interpret_cell_hash(vm::Stack& stack, bool as_uint) {
|
||||
auto cell = stack.pop_cell();
|
||||
td::RefInt256 hash{true};
|
||||
hash.write().import_bytes(cell->get_hash().as_slice().ubegin(), 32, false);
|
||||
stack.push_int(std::move(hash));
|
||||
if (as_uint) {
|
||||
td::RefInt256 hash{true};
|
||||
hash.write().import_bytes(cell->get_hash().as_slice().ubegin(), 32, false);
|
||||
stack.push_int(std::move(hash));
|
||||
} else {
|
||||
stack.push_bytes(cell->get_hash().as_slice().str());
|
||||
}
|
||||
}
|
||||
|
||||
void interpret_store_ref(vm::Stack& stack) {
|
||||
@ -934,7 +942,9 @@ void interpret_fetch(vm::Stack& stack, int mode) {
|
||||
auto n = stack.pop_smallint_range(256 + (mode & 1));
|
||||
auto cs = stack.pop_cellslice();
|
||||
if (!cs->have(n)) {
|
||||
stack.push(std::move(cs));
|
||||
if (mode & 2) {
|
||||
stack.push(std::move(cs));
|
||||
}
|
||||
stack.push_bool(false);
|
||||
if (!(mode & 4)) {
|
||||
throw IntError{"end of data while reading integer from cell"};
|
||||
@ -959,7 +969,9 @@ void interpret_fetch_bytes(vm::Stack& stack, int mode) {
|
||||
unsigned n = stack.pop_smallint_range(127);
|
||||
auto cs = stack.pop_cellslice();
|
||||
if (!cs->have(n * 8)) {
|
||||
stack.push(std::move(cs));
|
||||
if (mode & 2) {
|
||||
stack.push(std::move(cs));
|
||||
}
|
||||
stack.push_bool(false);
|
||||
if (!(mode & 4)) {
|
||||
throw IntError{"end of data while reading byte string from cell"};
|
||||
@ -970,7 +982,7 @@ void interpret_fetch_bytes(vm::Stack& stack, int mode) {
|
||||
if (mode & 2) {
|
||||
cs.write().fetch_bytes(tmp, n);
|
||||
} else {
|
||||
cs.write().prefetch_bytes(tmp, n);
|
||||
cs->prefetch_bytes(tmp, n);
|
||||
}
|
||||
std::string s{tmp, tmp + n};
|
||||
if (mode & 1) {
|
||||
@ -978,7 +990,9 @@ void interpret_fetch_bytes(vm::Stack& stack, int mode) {
|
||||
} else {
|
||||
stack.push_string(std::move(s));
|
||||
}
|
||||
stack.push(std::move(cs));
|
||||
if (mode & 2) {
|
||||
stack.push(std::move(cs));
|
||||
}
|
||||
if (mode & 4) {
|
||||
stack.push_bool(true);
|
||||
}
|
||||
@ -1009,13 +1023,15 @@ void interpret_cell_remaining(vm::Stack& stack) {
|
||||
void interpret_fetch_ref(vm::Stack& stack, int mode) {
|
||||
auto cs = stack.pop_cellslice();
|
||||
if (!cs->have_refs(1)) {
|
||||
stack.push(std::move(cs));
|
||||
if (mode & 2) {
|
||||
stack.push(std::move(cs));
|
||||
}
|
||||
stack.push_bool(false);
|
||||
if (!(mode & 4)) {
|
||||
throw IntError{"end of data while reading reference from cell"};
|
||||
}
|
||||
} else {
|
||||
auto cell = (mode & 2) ? cs.write().fetch_ref() : cs.write().prefetch_ref();
|
||||
auto cell = (mode & 2) ? cs.write().fetch_ref() : cs->prefetch_ref();
|
||||
if (mode & 2) {
|
||||
stack.push(std::move(cs));
|
||||
}
|
||||
@ -2474,7 +2490,9 @@ void init_words_common(Dictionary& d) {
|
||||
d.def_stack_word("B>Lu@+ ", std::bind(interpret_bytes_fetch_int, _1, 0x12));
|
||||
d.def_stack_word("B>Li@+ ", std::bind(interpret_bytes_fetch_int, _1, 0x13));
|
||||
d.def_stack_word("$>B ", interpret_string_to_bytes);
|
||||
d.def_stack_word("Bhash ", interpret_bytes_hash);
|
||||
d.def_stack_word("Bhash ", std::bind(interpret_bytes_hash, _1, true));
|
||||
d.def_stack_word("Bhashu ", std::bind(interpret_bytes_hash, _1, true));
|
||||
d.def_stack_word("BhashB ", std::bind(interpret_bytes_hash, _1, false));
|
||||
// cell manipulation (create, write and modify cells)
|
||||
d.def_stack_word("<b ", interpret_empty);
|
||||
d.def_stack_word("i, ", std::bind(interpret_store, _1, true));
|
||||
@ -2496,7 +2514,9 @@ void init_words_common(Dictionary& d) {
|
||||
d.def_stack_word("brembits ", std::bind(interpret_builder_remaining_bitrefs, _1, 1));
|
||||
d.def_stack_word("bremrefs ", std::bind(interpret_builder_remaining_bitrefs, _1, 2));
|
||||
d.def_stack_word("brembitrefs ", std::bind(interpret_builder_remaining_bitrefs, _1, 3));
|
||||
d.def_stack_word("hash ", interpret_cell_hash);
|
||||
d.def_stack_word("hash ", std::bind(interpret_cell_hash, _1, true));
|
||||
d.def_stack_word("hashu ", std::bind(interpret_cell_hash, _1, true));
|
||||
d.def_stack_word("hashB ", std::bind(interpret_cell_hash, _1, false));
|
||||
// cellslice manipulation (read from cells)
|
||||
d.def_stack_word("<s ", interpret_from_cell);
|
||||
d.def_stack_word("i@ ", std::bind(interpret_fetch, _1, 1));
|
||||
|
@ -628,7 +628,7 @@ bool Op::generate_code_step(Stack& stack) {
|
||||
stack.opt_show();
|
||||
StackLayout layout1 = stack.vars();
|
||||
bool next_empty = next->is_empty();
|
||||
stack.o << (next_empty ? "WHILEEND:<{" : "WHILE:<{");
|
||||
stack.o << "WHILE:<{";
|
||||
stack.o.indent();
|
||||
stack.forget_const();
|
||||
block0->generate_code_all(stack);
|
||||
@ -638,7 +638,7 @@ bool Op::generate_code_step(Stack& stack) {
|
||||
stack.modified();
|
||||
stack.o.undent();
|
||||
Stack stack_copy{stack};
|
||||
stack.o << (next_empty ? "}>" : "}>DO<{");
|
||||
stack.o << (next_empty ? "}>DO:" : "}>DO<{");
|
||||
if (!next_empty) {
|
||||
stack.o.indent();
|
||||
}
|
||||
|
@ -169,6 +169,11 @@ bool SourceReader::load_line() {
|
||||
error("line too long");
|
||||
return false;
|
||||
}
|
||||
if (len && cur_line.back() == '\r') {
|
||||
// CP/M line breaks support
|
||||
cur_line.pop_back();
|
||||
--len;
|
||||
}
|
||||
loc.text = cur_line;
|
||||
cur_line_len = (int)len;
|
||||
loc.line_pos = 0;
|
||||
|
@ -15,10 +15,10 @@ cr ."initial basechain state is:" cr dup <s csr. cr
|
||||
dup dup 31 boc+>B dup Bx. cr
|
||||
dup "basestate0" +suffix +".boc" tuck B>file
|
||||
."(Initial basechain state saved to file " type .")" cr
|
||||
Bhash dup =: basestate0_fhash
|
||||
Bhashu dup =: basestate0_fhash
|
||||
."file hash=" dup x. space 256 u>B dup B>base64url type cr
|
||||
"basestate0" +suffix +".fhash" B>file
|
||||
hash dup =: basestate0_rhash
|
||||
hashu dup =: basestate0_rhash
|
||||
."root hash=" dup x. space 256 u>B dup B>base64url type cr
|
||||
"basestate0" +suffix +".rhash" B>file
|
||||
|
||||
@ -227,10 +227,10 @@ cr cr ."new state is:" cr dup <s csr. cr
|
||||
dup 31 boc+>B dup Bx. cr
|
||||
dup "zerostate" +suffix +".boc" tuck B>file
|
||||
."(Initial masterchain state saved to file " type .")" cr
|
||||
Bhash dup =: zerostate_fhash
|
||||
Bhashu dup =: zerostate_fhash
|
||||
."file hash=" dup x. space 256 u>B dup B>base64url type cr
|
||||
"zerostate" +suffix +".fhash" B>file
|
||||
hash dup =: zerostate_rhash ."root hash=" dup x. space 256 u>B dup B>base64url type cr
|
||||
hashu dup =: zerostate_rhash ."root hash=" dup x. space 256 u>B dup B>base64url type cr
|
||||
"zerostate" +suffix +".rhash" B>file
|
||||
basestate0_rhash ."Basestate0 root hash=" dup x. space 256 u>B B>base64url type cr
|
||||
basestate0_fhash ."Basestate0 file hash=" dup x. space 256 u>B B>base64url type cr
|
||||
|
@ -15,10 +15,10 @@ cr ."initial basechain state is:" cr dup <s csr. cr
|
||||
dup dup 31 boc+>B dup Bx. cr
|
||||
dup "basestate0" +suffix +".boc" tuck B>file
|
||||
."(Initial basechain state saved to file " type .")" cr
|
||||
Bhash dup =: basestate0_fhash
|
||||
Bhashu dup =: basestate0_fhash
|
||||
."file hash=" dup x. space 256 u>B dup B>base64url type cr
|
||||
"basestate0" +suffix +".fhash" B>file
|
||||
hash dup =: basestate0_rhash
|
||||
hashu dup =: basestate0_rhash
|
||||
."root hash=" dup x. space 256 u>B dup B>base64url type cr
|
||||
"basestate0" +suffix +".rhash" B>file
|
||||
|
||||
@ -231,10 +231,10 @@ cr cr ."new state is:" cr dup <s csr. cr
|
||||
dup 31 boc+>B dup Bx. cr
|
||||
dup "zerostate" +suffix +".boc" tuck B>file
|
||||
."(Initial masterchain state saved to file " type .")" cr
|
||||
Bhash dup =: zerostate_fhash
|
||||
Bhashu dup =: zerostate_fhash
|
||||
."file hash= " dup X. space 256 u>B dup B>base64url type cr
|
||||
"zerostate" +suffix +".fhash" B>file
|
||||
hash dup =: zerostate_rhash ."root hash= " dup X. space 256 u>B dup B>base64url type cr
|
||||
hashu dup =: zerostate_rhash ."root hash= " dup X. space 256 u>B dup B>base64url type cr
|
||||
"zerostate" +suffix +".rhash" B>file
|
||||
basestate0_rhash ."Basestate0 root hash= " dup X. space 256 u>B B>base64url type cr
|
||||
basestate0_fhash ."Basestate0 file hash= " dup X. space 256 u>B B>base64url type cr
|
||||
|
@ -0,0 +1,41 @@
|
||||
;; Heavy-duty wallet for mass transfers (e.g., for cryptocurrency exchanges)
|
||||
;; accepts orders for up to 254 internal messages (transfers) in one external message
|
||||
|
||||
() recv_internal(slice in_msg) impure {
|
||||
;; do nothing for internal messages
|
||||
}
|
||||
|
||||
() recv_external(slice in_msg) impure {
|
||||
var signature = in_msg~load_bits(512);
|
||||
var cs = in_msg;
|
||||
var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32));
|
||||
throw_if(35, valid_until <= now());
|
||||
var ds = get_data().begin_parse();
|
||||
var (stored_seqno, stored_subwallet, public_key) = (ds~load_uint(32), ds~load_uint(32), ds~load_uint(256));
|
||||
ds.end_parse();
|
||||
throw_unless(33, msg_seqno == stored_seqno);
|
||||
throw_unless(34, subwallet_id == stored_subwallet);
|
||||
throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key));
|
||||
var dict = cs~load_dict();
|
||||
cs.end_parse();
|
||||
accept_message();
|
||||
int i = -1;
|
||||
do {
|
||||
(i, var cs, var f) = dict.idict_get_next?(16, i);
|
||||
if (f) {
|
||||
var mode = cs~load_uint(8);
|
||||
send_raw_message(cs~load_ref(), mode);
|
||||
}
|
||||
} until (~ f);
|
||||
set_data(begin_cell()
|
||||
.store_uint(stored_seqno + 1, 32)
|
||||
.store_uint(stored_subwallet, 32)
|
||||
.store_uint(public_key, 256)
|
||||
.end_cell());
|
||||
}
|
||||
|
||||
;; Get methods
|
||||
|
||||
int seqno() method_id {
|
||||
return get_data().begin_parse().preload_uint(32);
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
// automatically generated from `smartcont/stdlib.fc` `smartcont/highload-wallet-code.fc`
|
||||
PROGRAM{
|
||||
DECLPROC recv_internal
|
||||
DECLPROC recv_external
|
||||
85143 DECLMETHOD seqno
|
||||
recv_internal PROC:<{
|
||||
// in_msg
|
||||
DROP //
|
||||
}>
|
||||
recv_external PROC:<{
|
||||
// in_msg
|
||||
9 PUSHPOW2 // in_msg _3=512
|
||||
LDSLICEX // signature in_msg
|
||||
DUP // signature in_msg cs
|
||||
32 LDU // signature in_msg _9 cs
|
||||
32 LDU // signature in_msg _9 _12 cs
|
||||
32 LDU // signature in_msg subwallet_id valid_until msg_seqno cs
|
||||
NOW // signature in_msg subwallet_id valid_until msg_seqno cs _19
|
||||
s1 s3 XCHG // signature in_msg subwallet_id cs msg_seqno valid_until _19
|
||||
LEQ // signature in_msg subwallet_id cs msg_seqno _20
|
||||
35 THROWIF
|
||||
c4 PUSH // signature in_msg subwallet_id cs msg_seqno _23
|
||||
CTOS // signature in_msg subwallet_id cs msg_seqno ds
|
||||
32 LDU // signature in_msg subwallet_id cs msg_seqno _28 ds
|
||||
32 LDU // signature in_msg subwallet_id cs msg_seqno _28 _31 ds
|
||||
256 LDU // signature in_msg subwallet_id cs msg_seqno stored_seqno stored_subwallet public_key ds
|
||||
ENDS
|
||||
s3 s2 XCPU // signature in_msg subwallet_id cs public_key stored_seqno stored_subwallet msg_seqno stored_seqno
|
||||
EQUAL // signature in_msg subwallet_id cs public_key stored_seqno stored_subwallet _39
|
||||
33 THROWIFNOT
|
||||
s4 s4 XCPU // signature in_msg stored_subwallet cs public_key stored_seqno subwallet_id stored_subwallet
|
||||
EQUAL // signature in_msg stored_subwallet cs public_key stored_seqno _42
|
||||
34 THROWIFNOT
|
||||
s0 s4 XCHG // signature stored_seqno stored_subwallet cs public_key in_msg
|
||||
HASHSU // signature stored_seqno stored_subwallet cs public_key _45
|
||||
s0 s5 s5 XC2PU // public_key stored_seqno stored_subwallet cs _45 signature public_key
|
||||
CHKSIGNU // public_key stored_seqno stored_subwallet cs _46
|
||||
35 THROWIFNOT
|
||||
LDDICT // public_key stored_seqno stored_subwallet dict cs
|
||||
ENDS
|
||||
ACCEPT
|
||||
-1 PUSHINT // public_key stored_seqno stored_subwallet dict i=-1
|
||||
UNTIL:<{
|
||||
OVER
|
||||
16 PUSHINT // public_key stored_seqno stored_subwallet dict i dict _57=16
|
||||
DICTIGETNEXT
|
||||
NULLSWAPIFNOT
|
||||
NULLSWAPIFNOT // public_key stored_seqno stored_subwallet dict cs i f
|
||||
DUP // public_key stored_seqno stored_subwallet dict cs i f f
|
||||
IF:<{ // public_key stored_seqno stored_subwallet dict cs i f
|
||||
s0 s2 XCHG // public_key stored_seqno stored_subwallet dict f i cs
|
||||
8 LDU // public_key stored_seqno stored_subwallet dict f i mode cs
|
||||
LDREF // public_key stored_seqno stored_subwallet dict f i mode _100 _99
|
||||
DROP // public_key stored_seqno stored_subwallet dict f i mode _63
|
||||
SWAP // public_key stored_seqno stored_subwallet dict f i _63 mode
|
||||
SENDRAWMSG
|
||||
}>ELSE<{
|
||||
s2 POP // public_key stored_seqno stored_subwallet dict f i
|
||||
}>
|
||||
SWAP // public_key stored_seqno stored_subwallet dict i f
|
||||
NOT // public_key stored_seqno stored_subwallet dict i _66
|
||||
}> // public_key stored_seqno stored_subwallet dict i
|
||||
2DROP // public_key stored_seqno stored_subwallet
|
||||
SWAP // public_key stored_subwallet stored_seqno
|
||||
INC // public_key stored_subwallet _68
|
||||
NEWC // public_key stored_subwallet _68 _69
|
||||
32 STU // public_key stored_subwallet _71
|
||||
32 STU // public_key _73
|
||||
256 STU // _75
|
||||
ENDC // _76
|
||||
c4 POP
|
||||
}>
|
||||
seqno PROC:<{
|
||||
//
|
||||
c4 PUSH // _0
|
||||
CTOS // _1
|
||||
32 PLDU // _3
|
||||
}>
|
||||
}END>c
|
@ -0,0 +1,65 @@
|
||||
;; Heavy-duty wallet for mass transfers (e.g., for cryptocurrency exchanges)
|
||||
;; accepts orders for up to 254 internal messages (transfers) in one external message
|
||||
;; this version does not use seqno for replay protection; instead, it remembers all recent query_ids
|
||||
;; in this way several external messages with different query_id can be sent in parallel
|
||||
|
||||
() recv_internal(slice in_msg) impure {
|
||||
;; do nothing for internal messages
|
||||
}
|
||||
|
||||
() recv_external(slice in_msg) impure {
|
||||
var signature = in_msg~load_bits(512);
|
||||
var cs = in_msg;
|
||||
var (subwallet_id, query_id) = (cs~load_uint(32), cs~load_uint(64));
|
||||
var bound = (now() << 32);
|
||||
throw_if(35, query_id < bound);
|
||||
var ds = get_data().begin_parse();
|
||||
var (stored_subwallet, last_cleaned, public_key, old_queries) = (ds~load_uint(32), ds~load_uint(64), ds~load_uint(256), ds~load_dict());
|
||||
ds.end_parse();
|
||||
(_, var found?) = old_queries.udict_get?(64, query_id);
|
||||
throw_if(32, found?);
|
||||
throw_unless(34, subwallet_id == stored_subwallet);
|
||||
throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key));
|
||||
var dict = cs~load_dict();
|
||||
cs.end_parse();
|
||||
accept_message();
|
||||
int i = -1;
|
||||
do {
|
||||
(i, var cs, var f) = dict.idict_get_next?(16, i);
|
||||
if (f) {
|
||||
var mode = cs~load_uint(8);
|
||||
send_raw_message(cs~load_ref(), mode);
|
||||
}
|
||||
} until (~ f);
|
||||
bound -= (64 << 32); ;; clean up records expired more than 64 seconds ago
|
||||
old_queries~udict_set_builder(64, query_id, begin_cell());
|
||||
var queries = old_queries;
|
||||
do {
|
||||
var (old_queries', i, _, f) = old_queries.udict_delete_get_min(64);
|
||||
f~touch();
|
||||
if (f) {
|
||||
f = (i < bound);
|
||||
}
|
||||
if (f) {
|
||||
old_queries = old_queries';
|
||||
last_cleaned = i;
|
||||
}
|
||||
} until (~ f);
|
||||
set_data(begin_cell()
|
||||
.store_uint(stored_subwallet, 32)
|
||||
.store_uint(last_cleaned, 64)
|
||||
.store_uint(public_key, 256)
|
||||
.store_dict(old_queries)
|
||||
.end_cell());
|
||||
}
|
||||
|
||||
;; Get methods
|
||||
|
||||
;; returns -1 for processed queries, 0 for unprocessed, 1 for unknown (forgotten)
|
||||
int processed?(int query_id) method_id {
|
||||
var ds = get_data().begin_parse();
|
||||
var (_, last_cleaned, _, old_queries) = (ds~load_uint(32), ds~load_uint(64), ds~load_uint(256), ds~load_dict());
|
||||
ds.end_parse();
|
||||
(_, var found) = old_queries.udict_get?(64, query_id);
|
||||
return found ? true : - (query_id <= last_cleaned);
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
// automatically generated from `smartcont/stdlib.fc` `smartcont/highload-wallet-v2-code.fc`
|
||||
PROGRAM{
|
||||
DECLPROC recv_internal
|
||||
DECLPROC recv_external
|
||||
117746 DECLMETHOD processed?
|
||||
recv_internal PROC:<{
|
||||
// in_msg
|
||||
DROP //
|
||||
}>
|
||||
recv_external PROC:<{
|
||||
// in_msg
|
||||
9 PUSHPOW2 // in_msg _3=512
|
||||
LDSLICEX // signature in_msg
|
||||
DUP // signature in_msg cs
|
||||
32 LDU // signature in_msg _8 cs
|
||||
64 LDU // signature in_msg subwallet_id query_id cs
|
||||
NOW // signature in_msg subwallet_id query_id cs _15
|
||||
32 LSHIFT# // signature in_msg subwallet_id query_id cs bound
|
||||
s2 s0 PUSH2 // signature in_msg subwallet_id query_id cs bound query_id bound
|
||||
LESS // signature in_msg subwallet_id query_id cs bound _19
|
||||
35 THROWIF
|
||||
c4 PUSH // signature in_msg subwallet_id query_id cs bound _22
|
||||
CTOS // signature in_msg subwallet_id query_id cs bound ds
|
||||
32 LDU // signature in_msg subwallet_id query_id cs bound _28 ds
|
||||
64 LDU // signature in_msg subwallet_id query_id cs bound _28 _31 ds
|
||||
256 LDU // signature in_msg subwallet_id query_id cs bound _28 _31 _34 ds
|
||||
LDDICT // signature in_msg subwallet_id query_id cs bound stored_subwallet last_cleaned public_key old_queries ds
|
||||
ENDS
|
||||
s6 s0 PUSH2
|
||||
64 PUSHINT // signature in_msg subwallet_id query_id cs bound stored_subwallet last_cleaned public_key old_queries query_id old_queries _42=64
|
||||
DICTUGET
|
||||
NULLSWAPIFNOT // signature in_msg subwallet_id query_id cs bound stored_subwallet last_cleaned public_key old_queries _115 _116
|
||||
NIP // signature in_msg subwallet_id query_id cs bound stored_subwallet last_cleaned public_key old_queries found?
|
||||
32 THROWIF
|
||||
s7 s3 XCPU // signature in_msg old_queries query_id cs bound stored_subwallet last_cleaned public_key subwallet_id stored_subwallet
|
||||
EQUAL // signature in_msg old_queries query_id cs bound stored_subwallet last_cleaned public_key _47
|
||||
34 THROWIFNOT
|
||||
s0 s7 XCHG // signature public_key old_queries query_id cs bound stored_subwallet last_cleaned in_msg
|
||||
HASHSU // signature public_key old_queries query_id cs bound stored_subwallet last_cleaned _50
|
||||
s0 s8 s7 XC2PU // last_cleaned public_key old_queries query_id cs bound stored_subwallet _50 signature public_key
|
||||
CHKSIGNU // last_cleaned public_key old_queries query_id cs bound stored_subwallet _51
|
||||
35 THROWIFNOT
|
||||
s0 s2 XCHG // last_cleaned public_key old_queries query_id stored_subwallet bound cs
|
||||
LDDICT // last_cleaned public_key old_queries query_id stored_subwallet bound dict cs
|
||||
ENDS
|
||||
ACCEPT
|
||||
-1 PUSHINT // last_cleaned public_key old_queries query_id stored_subwallet bound dict i=-1
|
||||
UNTIL:<{
|
||||
OVER
|
||||
16 PUSHINT // last_cleaned public_key old_queries query_id stored_subwallet bound dict i dict _62=16
|
||||
DICTIGETNEXT
|
||||
NULLSWAPIFNOT
|
||||
NULLSWAPIFNOT // last_cleaned public_key old_queries query_id stored_subwallet bound dict cs i f
|
||||
DUP // last_cleaned public_key old_queries query_id stored_subwallet bound dict cs i f f
|
||||
IF:<{ // last_cleaned public_key old_queries query_id stored_subwallet bound dict cs i f
|
||||
s0 s2 XCHG // last_cleaned public_key old_queries query_id stored_subwallet bound dict f i cs
|
||||
8 LDU // last_cleaned public_key old_queries query_id stored_subwallet bound dict f i mode cs
|
||||
LDREF // last_cleaned public_key old_queries query_id stored_subwallet bound dict f i mode _125 _124
|
||||
DROP // last_cleaned public_key old_queries query_id stored_subwallet bound dict f i mode _68
|
||||
SWAP // last_cleaned public_key old_queries query_id stored_subwallet bound dict f i _68 mode
|
||||
SENDRAWMSG
|
||||
}>ELSE<{
|
||||
s2 POP // last_cleaned public_key old_queries query_id stored_subwallet bound dict f i
|
||||
}>
|
||||
SWAP // last_cleaned public_key old_queries query_id stored_subwallet bound dict i f
|
||||
NOT // last_cleaned public_key old_queries query_id stored_subwallet bound dict i _71
|
||||
}> // last_cleaned public_key old_queries query_id stored_subwallet bound dict i
|
||||
2DROP // last_cleaned public_key old_queries query_id stored_subwallet bound
|
||||
38 PUSHPOW2 // last_cleaned public_key old_queries query_id stored_subwallet bound _74
|
||||
SUB // last_cleaned public_key old_queries query_id stored_subwallet bound
|
||||
NEWC // last_cleaned public_key old_queries query_id stored_subwallet bound _77
|
||||
s0 s3 s4 XCHG3
|
||||
64 PUSHINT // last_cleaned public_key stored_subwallet bound _77 query_id old_queries _78=64
|
||||
DICTUSETB // last_cleaned public_key stored_subwallet bound old_queries
|
||||
UNTIL:<{
|
||||
DUP
|
||||
64 PUSHINT // last_cleaned public_key stored_subwallet bound old_queries old_queries _85=64
|
||||
DICTUREMMIN
|
||||
NULLSWAPIFNOT
|
||||
NULLSWAPIFNOT // last_cleaned public_key stored_subwallet bound old_queries _126 _128 _127 _129
|
||||
s2 POP // last_cleaned public_key stored_subwallet bound old_queries old_queries' f i
|
||||
s1 s0 XCPU // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f f
|
||||
IF:<{ // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f
|
||||
DROP // last_cleaned public_key stored_subwallet bound old_queries old_queries' i
|
||||
s0 s3 PUSH2 // last_cleaned public_key stored_subwallet bound old_queries old_queries' i i bound
|
||||
LESS // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f
|
||||
}> // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f
|
||||
DUP // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f f
|
||||
IF:<{ // last_cleaned public_key stored_subwallet bound old_queries old_queries' i f
|
||||
s3 POP
|
||||
s6 POP // last_cleaned public_key stored_subwallet bound f old_queries
|
||||
}>ELSE<{
|
||||
s3 s1 s3 XCHG3
|
||||
2DROP // last_cleaned public_key stored_subwallet bound f old_queries
|
||||
}>
|
||||
SWAP // last_cleaned public_key stored_subwallet bound old_queries f
|
||||
NOT // last_cleaned public_key stored_subwallet bound old_queries _90
|
||||
}> // last_cleaned public_key stored_subwallet bound old_queries
|
||||
NIP // last_cleaned public_key stored_subwallet old_queries
|
||||
NEWC // last_cleaned public_key stored_subwallet old_queries _91
|
||||
s1 s2 XCHG // last_cleaned public_key old_queries stored_subwallet _91
|
||||
32 STU // last_cleaned public_key old_queries _93
|
||||
s1 s3 XCHG // old_queries public_key last_cleaned _93
|
||||
64 STU // old_queries public_key _95
|
||||
256 STU // old_queries _97
|
||||
STDICT // _98
|
||||
ENDC // _99
|
||||
c4 POP
|
||||
}>
|
||||
processed? PROC:<{
|
||||
// query_id
|
||||
c4 PUSH // query_id _2
|
||||
CTOS // query_id ds
|
||||
32 LDU // query_id _29 _28
|
||||
NIP // query_id ds
|
||||
64 LDU // query_id _11 ds
|
||||
256 LDU // query_id _11 _33 _32
|
||||
NIP // query_id _11 ds
|
||||
LDDICT // query_id last_cleaned old_queries ds
|
||||
ENDS
|
||||
s2 s(-1) PUXC
|
||||
64 PUSHINT // query_id last_cleaned query_id old_queries _22=64
|
||||
DICTUGET
|
||||
NULLSWAPIFNOT // query_id last_cleaned _36 _37
|
||||
NIP // query_id last_cleaned found
|
||||
IF:<{ // query_id last_cleaned
|
||||
2DROP //
|
||||
TRUE // _24
|
||||
}>ELSE<{ // query_id last_cleaned
|
||||
LEQ // _26
|
||||
NEGATE // _24
|
||||
}>
|
||||
}>
|
||||
}END>c
|
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env fift -s
|
||||
"TonUtil.fif" include
|
||||
|
||||
{ ."usage: " @' $0 type ." <filename-base> <subwallet-id> <order-file> [<savefile>]" cr
|
||||
."Creates a request with up to 254 orders loaded from <order-file> to high-load v2 (sub)wallet created by new-highload-v2-wallet.fif, with private key loaded from file <filename-base>.pk "
|
||||
."and address from <filename-base><subwallet-id>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)" cr
|
||||
."<order-file> is a text file with lines `SEND <dest-addr> <amount>`" cr 1 halt
|
||||
} : usage
|
||||
$# dup 3 < swap 4 > or ' usage if
|
||||
|
||||
$1 =: file-base
|
||||
$2 parse-int dup 32 fits ' usage ifnot =: subwallet-id // parse subwallet-id
|
||||
{ subwallet-id (.) $+ } : +subwallet
|
||||
$3 =: order-file
|
||||
def? $4 { @' $4 } { "wallet-query" } cond constant savefile
|
||||
3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
60 constant timeout // external message expires in 60 seconds
|
||||
|
||||
file-base +subwallet +".addr" load-address
|
||||
2dup 2constant wallet_addr
|
||||
."Source wallet address = " 2dup .addr cr 6 .Addr cr
|
||||
file-base +".pk" load-keypair nip constant wallet_pk
|
||||
|
||||
variable orders dictnew orders !
|
||||
variable order# order# 0!
|
||||
// c --
|
||||
{ <s order# @ dup 254 >= abort"more than 254 orders"
|
||||
orders @ 16 udict!+ not abort"cannot add order to dictionary"
|
||||
orders ! order# 1+!
|
||||
} : add-order
|
||||
// b body -- b'
|
||||
{ tuck <s 2dup s-fits? not rot over 1 i, -rot
|
||||
{ drop swap ref, } { s, nip } cond
|
||||
} : append-msg-body
|
||||
// ng wc addr bounce body -- c
|
||||
{ <b b{01} s, rot 1 i, b{000100} s, 2swap addr, rot Gram,
|
||||
0 9 64 32 + + 1+ u, swap append-msg-body b>
|
||||
} : create-int-msg
|
||||
// ng wc addr bnc --
|
||||
{ ."Transferring " 3 roll .GR ."to account "
|
||||
-rot 2dup 4 pick 7 + .Addr ." = " .addr ." bounce=" . cr
|
||||
} : .transfer
|
||||
// addr$ ng -- c
|
||||
{ swap parse-smc-addr // ng wc addr bnc
|
||||
2over 2over .transfer
|
||||
<b 0 32 u, b> create-int-msg
|
||||
} : create-simple-transfer
|
||||
// c m -- c'
|
||||
{ <b swap 8 u, swap ref, b> } : create-order
|
||||
|
||||
// addr$ ng --
|
||||
{ create-simple-transfer send-mode create-order add-order } : send
|
||||
{ bl word bl word $>GR send } : SEND
|
||||
|
||||
// parse order file
|
||||
order-file include
|
||||
|
||||
// create external message
|
||||
now timeout + 32 << <b orders @ dict, b> hashu 32 1<<1- and + =: query_id
|
||||
<b subwallet-id 32 i, query_id 64 u, orders @ dict, b>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hashu wallet_pk ed25519_sign_uint
|
||||
<b b{1000100} s, wallet_addr addr, 0 Gram, b{00} s,
|
||||
swap B, swap <s s, b>
|
||||
dup ."resulting external message: " <s csr. cr
|
||||
2 boc+>B dup Bx. cr
|
||||
."Query_id is " query_id dup . ."= 0x" X. cr
|
||||
savefile +".boc" tuck B>file
|
||||
."(Saved to file " type .")" cr
|
@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env fift -s
|
||||
"TonUtil.fif" include
|
||||
|
||||
{ ."usage: " @' $0 type ." <filename-base> <subwallet-id> <seqno> <order-file> [<savefile>]" cr
|
||||
."Creates a request with up to 254 orders loaded from <order-file> to high-load (sub)wallet created by new-highload-wallet.fif, with private key loaded from file <filename-base>.pk "
|
||||
."and address from <filename-base><subwallet-id>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)" cr
|
||||
."<order-file> is a text file with lines `SEND <dest-addr> <amount>`" cr 1 halt
|
||||
} : usage
|
||||
$# dup 4 < swap 5 > or ' usage if
|
||||
|
||||
$1 =: file-base
|
||||
$2 parse-int dup 32 fits ' usage ifnot =: subwallet-id // parse subwallet-id
|
||||
{ subwallet-id (.) $+ } : +subwallet
|
||||
$3 parse-int =: seqno
|
||||
$4 =: order-file
|
||||
def? $5 { @' $5 } { "wallet-query" } cond constant savefile
|
||||
3 constant send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
60 constant timeout // external message expires in 60 seconds
|
||||
|
||||
file-base +subwallet +".addr" load-address
|
||||
2dup 2constant wallet_addr
|
||||
."Source wallet address = " 2dup .addr cr 6 .Addr cr
|
||||
file-base +".pk" load-keypair nip constant wallet_pk
|
||||
|
||||
variable orders dictnew orders !
|
||||
variable order# order# 0!
|
||||
// c --
|
||||
{ <s order# @ dup 254 >= abort"more than 254 orders"
|
||||
orders @ 16 udict!+ not abort"cannot add order to dictionary"
|
||||
orders ! order# 1+!
|
||||
} : add-order
|
||||
// b body -- b'
|
||||
{ tuck <s 2dup s-fits? not rot over 1 i, -rot
|
||||
{ drop swap ref, } { s, nip } cond
|
||||
} : append-msg-body
|
||||
// ng wc addr bounce body -- c
|
||||
{ <b b{01} s, rot 1 i, b{000100} s, 2swap addr, rot Gram,
|
||||
0 9 64 32 + + 1+ u, swap append-msg-body b>
|
||||
} : create-int-msg
|
||||
// ng wc addr bnc --
|
||||
{ ."Transferring " 3 roll .GR ."to account "
|
||||
-rot 2dup 4 pick 7 + .Addr ." = " .addr ." bounce=" . cr
|
||||
} : .transfer
|
||||
// addr$ ng -- c
|
||||
{ swap parse-smc-addr // ng wc addr bnc
|
||||
2over 2over .transfer
|
||||
<b 0 32 u, b> create-int-msg
|
||||
} : create-simple-transfer
|
||||
// c m -- c'
|
||||
{ <b swap 8 u, swap ref, b> } : create-order
|
||||
|
||||
// addr$ ng --
|
||||
{ create-simple-transfer send-mode create-order add-order } : send
|
||||
{ bl word bl word $>GR send } : SEND
|
||||
|
||||
// parse order file
|
||||
order-file include
|
||||
|
||||
// create external message
|
||||
<b subwallet-id 32 i, now timeout + 32 u, seqno 32 u, orders @ dict, b>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hashu wallet_pk ed25519_sign_uint
|
||||
<b b{1000100} s, wallet_addr addr, 0 Gram, b{00} s,
|
||||
swap B, swap <s s, b>
|
||||
dup ."resulting external message: " <s csr. cr
|
||||
2 boc+>B dup Bx. cr
|
||||
savefile +".boc" tuck B>file
|
||||
."(Saved to file " type .")" cr
|
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env fift -s
|
||||
"TonUtil.fif" include
|
||||
"Asm.fif" include
|
||||
|
||||
{ ."usage: " @' $0 type ." <workchain-id> <subwallet-id> [<filename-base>]" cr
|
||||
."Creates a new v2 high-load wallet in the specified workchain, with the controlling private key saved to or loaded from <filename-base>.pk "
|
||||
."('new-wallet.pk' by default)" cr
|
||||
."<subwallet-id> is the 32-bit identifier of this subwallet among all controlled by the same private key" cr 1 halt
|
||||
} : usage
|
||||
$# 2- -2 and ' usage if
|
||||
|
||||
$1 parse-workchain-id =: wc // set workchain id from command line argument
|
||||
$2 parse-int dup =: subwallet-id // parse subwallet-id
|
||||
32 fits ' usage ifnot
|
||||
{ subwallet-id (.) $+ } : +subwallet
|
||||
def? $3 { @' $3 } { "new-wallet" } cond constant file-base
|
||||
65536 constant timeout // init query times out in 65536 seconds
|
||||
|
||||
."Creating new v2 high-load wallet in workchain " wc .
|
||||
."with subwallet id " subwallet-id . cr
|
||||
|
||||
// Create new high-load wallet; source code included from `highload-wallet-v2-code.fif`
|
||||
"highload-wallet-v2-code.fif" include
|
||||
// code
|
||||
<b subwallet-id 32 i, 0 64 u,
|
||||
file-base +".pk" load-generate-keypair
|
||||
constant wallet_pk
|
||||
B, false 1 i,
|
||||
b> // data
|
||||
null // no libraries
|
||||
<b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit
|
||||
dup ."StateInit: " <s csr. cr
|
||||
dup hashu wc swap 2dup 2constant wallet_addr
|
||||
."new wallet address = " 2dup .addr cr
|
||||
2dup file-base +subwallet +".addr" save-address-verbose
|
||||
."Non-bounceable address (for init): " 2dup 7 .Addr cr
|
||||
."Bounceable address (for later access): " 6 .Addr cr
|
||||
now timeout + 32 << 1- dup =: query_id
|
||||
."Init query_id is " dup . ."(0x" X._ .")" cr
|
||||
<b subwallet-id 32 i, query_id 64 u, false 1 i, b>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hashu wallet_pk ed25519_sign_uint rot
|
||||
<b b{1000100} s, wallet_addr addr, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b>
|
||||
dup ."External message for initialization is " <s csr. cr
|
||||
2 boc+>B dup Bx. cr
|
||||
file-base +subwallet +"-query.boc" tuck B>file
|
||||
."(Saved wallet creating query to file " type .")" cr
|
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env fift -s
|
||||
"TonUtil.fif" include
|
||||
"Asm.fif" include
|
||||
|
||||
{ ."usage: " @' $0 type ." <workchain-id> <subwallet-id> [<filename-base>]" cr
|
||||
."Creates a new high-load wallet in the specified workchain, with the controlling private key saved to or loaded from <filename-base>.pk "
|
||||
."('new-wallet.pk' by default)" cr
|
||||
."<subwallet-id> is the 32-bit identifier of this subwallet among all controlled by the same private key" cr 1 halt
|
||||
} : usage
|
||||
$# 2- -2 and ' usage if
|
||||
|
||||
$1 parse-workchain-id =: wc // set workchain id from command line argument
|
||||
$2 parse-int dup =: subwallet-id // parse subwallet-id
|
||||
32 fits ' usage ifnot
|
||||
{ subwallet-id (.) $+ } : +subwallet
|
||||
def? $3 { @' $3 } { "new-wallet" } cond constant file-base
|
||||
|
||||
."Creating new high-load wallet in workchain " wc .
|
||||
."with subwallet id " subwallet-id . cr
|
||||
|
||||
// Create new high-load wallet; source code included from `highload-wallet-code.fif`
|
||||
"highload-wallet-code.fif" include
|
||||
// code
|
||||
<b 0 32 u, subwallet-id 32 i,
|
||||
file-base +".pk" load-generate-keypair
|
||||
constant wallet_pk
|
||||
B,
|
||||
b> // data
|
||||
null // no libraries
|
||||
<b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit
|
||||
dup ."StateInit: " <s csr. cr
|
||||
dup hashu wc swap 2dup 2constant wallet_addr
|
||||
."new wallet address = " 2dup .addr cr
|
||||
2dup file-base +subwallet +".addr" save-address-verbose
|
||||
."Non-bounceable address (for init): " 2dup 7 .Addr cr
|
||||
."Bounceable address (for later access): " 6 .Addr cr
|
||||
<b subwallet-id 32 i, -1 32 i, 0 32 u, false 1 i, b>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hashu wallet_pk ed25519_sign_uint rot
|
||||
<b b{1000100} s, wallet_addr addr, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b>
|
||||
dup ."External message for initialization is " <s csr. cr
|
||||
2 boc+>B dup Bx. cr
|
||||
file-base +subwallet +"-query.boc" tuck B>file
|
||||
."(Saved wallet creating query to file " type .")" cr
|
@ -41,7 +41,7 @@ def? $3 { @' $3 } { "new-pinger" } cond constant file-base
|
||||
// no libraries
|
||||
<b b{00110} s, rot ref, swap ref, b> // create StateInit
|
||||
dup ."StateInit: " <s csr. cr
|
||||
dup hash wc swap 2dup 2constant pinger_addr
|
||||
dup hashu wc swap 2dup 2constant pinger_addr
|
||||
."new pinger address = " 2dup .addr cr
|
||||
2dup file-base +".addr" save-address-verbose
|
||||
."Non-bounceable address (for init): " 2dup 7 .Addr cr
|
||||
|
@ -37,7 +37,7 @@ def? $2 { @' $2 } { "new-testgiver" } cond constant file-base
|
||||
null // no libraries
|
||||
<b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit
|
||||
dup ."StateInit: " <s csr. cr
|
||||
dup hash wc swap 2dup 2constant wallet_addr
|
||||
dup hashu wc swap 2dup 2constant wallet_addr
|
||||
."new money giver address = " 2dup .addr cr
|
||||
2dup file-base +".addr" save-address-verbose
|
||||
."Non-bounceable address (for init): " 2dup 7 .Addr cr
|
||||
|
@ -47,14 +47,14 @@ b> // data
|
||||
null // no libraries
|
||||
<b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit
|
||||
dup ."StateInit: " <s csr. cr
|
||||
dup hash wc swap 2dup 2constant wallet_addr
|
||||
dup hashu wc swap 2dup 2constant wallet_addr
|
||||
."new wallet address = " 2dup .addr cr
|
||||
2dup file-base +".addr" save-address-verbose
|
||||
."Non-bounceable address (for init): " 2dup 7 .Addr cr
|
||||
."Bounceable address (for later access): " 6 .Addr cr
|
||||
<b 0 32 u, -1 32 i, b>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hash wallet_pk ed25519_sign_uint rot
|
||||
dup hashu wallet_pk ed25519_sign_uint rot
|
||||
<b b{1000100} s, wallet_addr addr, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b>
|
||||
dup ."External message for initialization is " <s csr. cr
|
||||
2 boc+>B dup Bx. cr
|
||||
|
@ -47,14 +47,14 @@ null // no libraries
|
||||
// Libs{ x{ABACABADABACABA} drop x{AAAA} s>c public_lib x{1234} x{5678} |_ s>c public_lib }Libs
|
||||
<b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit
|
||||
dup ."StateInit: " <s csr. cr
|
||||
dup hash wc swap 2dup 2constant wallet_addr
|
||||
dup hashu wc swap 2dup 2constant wallet_addr
|
||||
."new wallet address = " 2dup .addr cr
|
||||
2dup file-base +".addr" save-address-verbose
|
||||
."Non-bounceable address (for init): " 2dup 7 .Addr cr
|
||||
."Bounceable address (for later access): " 6 .Addr cr
|
||||
<b 0 32 u, b>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hash wallet_pk ed25519_sign_uint rot
|
||||
dup hashu wallet_pk ed25519_sign_uint rot
|
||||
<b b{1000100} s, wallet_addr addr, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b>
|
||||
dup ."External message for initialization is " <s csr. cr
|
||||
2 boc+>B dup Bx. cr
|
||||
|
@ -86,6 +86,8 @@ cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(va
|
||||
(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT" "NULLSWAPIFNOT";
|
||||
(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT" "NULLSWAPIFNOT";
|
||||
(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT" "NULLSWAPIFNOT";
|
||||
(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT" "NULLSWAPIFNOT";
|
||||
(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT" "NULLSWAPIFNOT";
|
||||
cell new_dict() asm "NEWDICT";
|
||||
int dict_empty?(cell c) asm "DICTEMPTY";
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
."with private key loaded from file <filename-base>.pk, "
|
||||
."and saves it into <savefile>.boc ('config-query.boc' by default)" cr 1 halt
|
||||
} : usage
|
||||
def? $# { @' $# dup 2 < swap 3 > or ' usage if } if
|
||||
$# dup 2 < swap 3 > or ' usage if
|
||||
|
||||
"config-master" constant file-base
|
||||
0 constant seqno
|
||||
@ -15,18 +15,16 @@ true constant bounce
|
||||
"config-code.fif" constant config-source
|
||||
100 constant interval // valid for 100 seconds
|
||||
|
||||
def? $2 {
|
||||
@' $1 =: file-base
|
||||
@' $2 parse-int =: seqno
|
||||
} if
|
||||
def? $5 { @' $5 } { "config-query" } cond constant savefile
|
||||
$1 =: file-base
|
||||
$2 parse-int =: seqno
|
||||
def? $3 { @' $3 } { "config-query" } cond constant savefile
|
||||
|
||||
file-base +".addr" load-address
|
||||
2dup 2constant config_addr
|
||||
."Configuration smart contract address = " 2dup .addr cr 6 .Addr cr
|
||||
file-base +".pk" load-keypair nip constant config_pk
|
||||
|
||||
."Loading new configuration smart contract code from file file " config-source type cr
|
||||
."Loading new configuration smart contract code from file " config-source type cr
|
||||
"Asm.fif" include
|
||||
config-source include
|
||||
dup <s csr. cr
|
||||
@ -34,7 +32,7 @@ dup <s csr. cr
|
||||
// create a message
|
||||
<b x{4e436f64} s, seqno 32 u, now interval + 32 u, swap ref, b>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hash config_pk ed25519_sign_uint
|
||||
dup hashu config_pk ed25519_sign_uint
|
||||
<b b{1000100} s, config_addr addr, 0 Gram, b{00} s,
|
||||
swap B, swap <s s, b>
|
||||
dup ."resulting external message: " <s csr. cr
|
||||
|
@ -6,7 +6,7 @@
|
||||
."with private key loaded from file <filename-base>.pk, "
|
||||
."and saves it into <savefile>.boc ('config-query.boc' by default)" cr 1 halt
|
||||
} : usage
|
||||
def? $# { @' $# dup 4 < swap 5 > or ' usage if } if
|
||||
$# dup 4 < swap 5 > or ' usage if
|
||||
|
||||
"config-master" constant file-base
|
||||
0 constant seqno
|
||||
@ -15,12 +15,10 @@ true constant bounce
|
||||
"new-value.boc" constant boc-filename
|
||||
100 constant interval // valid for 100 seconds
|
||||
|
||||
def? $4 {
|
||||
@' $1 =: file-base
|
||||
@' $2 parse-int =: seqno
|
||||
@' $3 parse-int =: idx
|
||||
@' $4 =: boc-filename
|
||||
} if
|
||||
$1 =: file-base
|
||||
$2 parse-int =: seqno
|
||||
$3 parse-int =: idx
|
||||
$4 =: boc-filename
|
||||
def? $5 { @' $5 } { "config-query" } cond constant savefile
|
||||
|
||||
file-base +".addr" load-address
|
||||
@ -39,7 +37,7 @@ dup idx is-valid-config? not abort"not a valid value for chosen configuration pa
|
||||
// create a message
|
||||
<b x{43665021} s, seqno 32 u, now interval + 32 u, idx 32 i, swap ref, b>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hash config_pk ed25519_sign_uint
|
||||
dup hashu config_pk ed25519_sign_uint
|
||||
<b b{1000100} s, config_addr addr, 0 Gram, b{00} s,
|
||||
swap B, swap <s s, b>
|
||||
dup ."resulting external message: " <s csr. cr
|
||||
|
@ -6,7 +6,7 @@
|
||||
."with private key loaded from file <filename-base>.pk, "
|
||||
."and saves it into <savefile>.boc ('config-query.boc' by default)" cr 1 halt
|
||||
} : usage
|
||||
def? $# { @' $# dup 2 < swap 3 > or ' usage if } if
|
||||
$# dup 2 < swap 3 > or ' usage if
|
||||
|
||||
"config-master" constant file-base
|
||||
0 constant seqno
|
||||
@ -15,18 +15,16 @@ true constant bounce
|
||||
"elector-code.fif" constant elector-source
|
||||
100 constant interval // valid for 100 seconds
|
||||
|
||||
def? $2 {
|
||||
@' $1 =: file-base
|
||||
@' $2 parse-int =: seqno
|
||||
} if
|
||||
def? $5 { @' $5 } { "config-query" } cond constant savefile
|
||||
$1 =: file-base
|
||||
$2 parse-int =: seqno
|
||||
def? $3 { @' $3 } { "config-query" } cond constant savefile
|
||||
|
||||
file-base +".addr" load-address
|
||||
2dup 2constant config_addr
|
||||
."Configuration smart contract address = " 2dup .addr cr 6 .Addr cr
|
||||
file-base +".pk" load-keypair nip constant config_pk
|
||||
|
||||
."Loading new elector smart contract code from file file " elector-source type cr
|
||||
."Loading new elector smart contract code from file " elector-source type cr
|
||||
"Asm.fif" include
|
||||
elector-source include
|
||||
dup <s csr. cr
|
||||
@ -34,7 +32,7 @@ dup <s csr. cr
|
||||
// create a message
|
||||
<b x{4e43ef05} s, seqno 32 u, now interval + 32 u, swap ref, b>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hash config_pk ed25519_sign_uint
|
||||
dup hashu config_pk ed25519_sign_uint
|
||||
<b b{1000100} s, config_addr addr, 0 Gram, b{00} s,
|
||||
swap B, swap <s s, b>
|
||||
dup ."resulting external message: " <s csr. cr
|
||||
|
@ -38,7 +38,7 @@ dest_addr 2dup bounce 7 + .Addr ." = " .addr
|
||||
b>
|
||||
<b seqno 32 u, now timeout + 32 u, send-mode 8 u, swap ref, b>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hash wallet_pk ed25519_sign_uint
|
||||
dup hashu wallet_pk ed25519_sign_uint
|
||||
<b b{1000100} s, wallet_addr addr, 0 Gram, b{00} s,
|
||||
swap B, swap <s s, b>
|
||||
dup ."resulting external message: " <s csr. cr
|
||||
|
@ -37,7 +37,7 @@ dest_addr 2dup bounce 7 + .Addr ." = " .addr
|
||||
b>
|
||||
<b seqno 32 u, send-mode 8 u, swap ref, b>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hash wallet_pk ed25519_sign_uint
|
||||
dup hashu wallet_pk ed25519_sign_uint
|
||||
<b b{1000100} s, wallet_addr addr, 0 Gram, b{00} s,
|
||||
swap B, swap <s s, b>
|
||||
dup ."resulting external message: " <s csr. cr
|
||||
|
@ -745,6 +745,26 @@ Ref<Cell> CellSlice::fetch_ref() {
|
||||
}
|
||||
}
|
||||
|
||||
bool CellSlice::prefetch_maybe_ref(Ref<vm::Cell>& res) const {
|
||||
auto z = prefetch_ulong(1);
|
||||
if (!z) {
|
||||
res.clear();
|
||||
return true;
|
||||
} else {
|
||||
return z == 1 && prefetch_ref_to(res);
|
||||
}
|
||||
}
|
||||
|
||||
bool CellSlice::fetch_maybe_ref(Ref<vm::Cell>& res) {
|
||||
auto z = prefetch_ulong(1);
|
||||
if (!z) {
|
||||
res.clear();
|
||||
return advance(1);
|
||||
} else {
|
||||
return z == 1 && prefetch_ref_to(res) && advance_ext(1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool CellSlice::begins_with(unsigned bits, unsigned long long value) const {
|
||||
return have(bits) && !((prefetch_ulong(bits) ^ value) & ((1ULL << bits) - 1));
|
||||
}
|
||||
|
@ -185,6 +185,8 @@ class CellSlice : public td::CntObject {
|
||||
bool prefetch_ref_to(Ref<Cell>& ref, unsigned offset = 0) const {
|
||||
return (ref = prefetch_ref(offset)).not_null();
|
||||
}
|
||||
bool fetch_maybe_ref(Ref<Cell>& ref);
|
||||
bool prefetch_maybe_ref(Ref<Cell>& ref) const;
|
||||
td::BitSlice fetch_bits(unsigned bits);
|
||||
td::BitSlice prefetch_bits(unsigned bits) const;
|
||||
td::Ref<CellSlice> fetch_subslice(unsigned bits, unsigned refs = 0);
|
||||
|
@ -267,16 +267,18 @@ MerkleProofBuilder::MerkleProofBuilder(Ref<Cell> root)
|
||||
usage_root = UsageCell::create(orig_root, usage_tree->root_ptr());
|
||||
}
|
||||
|
||||
void MerkleProofBuilder::reset(Ref<Cell> root) {
|
||||
Ref<Cell> MerkleProofBuilder::init(Ref<Cell> root) {
|
||||
usage_tree = std::make_shared<CellUsageTree>();
|
||||
orig_root = std::move(root);
|
||||
usage_root = UsageCell::create(orig_root, usage_tree->root_ptr());
|
||||
return usage_root;
|
||||
}
|
||||
|
||||
void MerkleProofBuilder::clear() {
|
||||
bool MerkleProofBuilder::clear() {
|
||||
usage_tree.reset();
|
||||
orig_root.clear();
|
||||
usage_root.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
Ref<Cell> MerkleProofBuilder::extract_proof() const {
|
||||
|
@ -51,9 +51,10 @@ class MerkleProofBuilder {
|
||||
Ref<vm::Cell> orig_root, usage_root;
|
||||
|
||||
public:
|
||||
MerkleProofBuilder() = default;
|
||||
MerkleProofBuilder(Ref<Cell> root);
|
||||
void reset(Ref<Cell> root);
|
||||
void clear();
|
||||
Ref<Cell> init(Ref<Cell> root);
|
||||
bool clear();
|
||||
Ref<Cell> root() const {
|
||||
return usage_root;
|
||||
}
|
||||
|
@ -914,8 +914,10 @@ bool TestNode::do_parse_line() {
|
||||
return parse_block_id_ext(blkid) && parse_account_addr(workchain, addr) && parse_lt(lt) && seekeoln() &&
|
||||
get_one_transaction(blkid, workchain, addr, lt, true);
|
||||
} else if (word == "lasttrans" || word == "lasttransdump") {
|
||||
return parse_account_addr(workchain, addr) && parse_lt(lt) && parse_hash(hash) && seekeoln() &&
|
||||
get_last_transactions(workchain, addr, lt, hash, 10, word == "lasttransdump");
|
||||
count = 10;
|
||||
return parse_account_addr(workchain, addr) && parse_lt(lt) && parse_hash(hash) &&
|
||||
(seekeoln() || parse_uint32(count)) && seekeoln() &&
|
||||
get_last_transactions(workchain, addr, lt, hash, count, word == "lasttransdump");
|
||||
} else if (word == "listblocktrans" || word == "listblocktransrev") {
|
||||
lt = 0;
|
||||
int mode = (word == "listblocktrans" ? 7 : 0x47);
|
||||
|
@ -364,7 +364,7 @@ inline void register_actor_info_ptr(core::ActorInfoPtr actor_info_ptr) {
|
||||
}
|
||||
|
||||
template <class T, class... ArgsT>
|
||||
core::ActorInfoPtr create_actor(core::ActorOptions &options, ArgsT &&... args) {
|
||||
core::ActorInfoPtr create_actor(core::ActorOptions &options, ArgsT &&... args) noexcept {
|
||||
auto *scheduler_context = core::SchedulerContext::get();
|
||||
if (!options.has_scheduler()) {
|
||||
options.on_scheduler(scheduler_context->get_scheduler_id());
|
||||
|
@ -75,7 +75,7 @@ void ActorExecutor::send(ActorSignals signals) {
|
||||
pending_signals_.add_signals(signals);
|
||||
}
|
||||
|
||||
void ActorExecutor::start() {
|
||||
void ActorExecutor::start() noexcept {
|
||||
//LOG(ERROR) << "START " << actor_info_.get_name() << " " << tag("from_queue", options.from_queue);
|
||||
if (is_closed()) {
|
||||
return;
|
||||
@ -126,7 +126,7 @@ void ActorExecutor::start() {
|
||||
}
|
||||
}
|
||||
|
||||
void ActorExecutor::finish() {
|
||||
void ActorExecutor::finish() noexcept {
|
||||
//LOG(ERROR) << "FINISH " << actor_info_.get_name() << " " << tag("own_lock", actor_locker_.own_lock());
|
||||
if (!actor_locker_.own_lock()) {
|
||||
if (!pending_signals_.empty() && actor_locker_.add_signals(pending_signals_)) {
|
||||
|
@ -106,8 +106,8 @@ class ActorExecutor {
|
||||
return flags_;
|
||||
}
|
||||
|
||||
void start();
|
||||
void finish();
|
||||
void start() noexcept;
|
||||
void finish() noexcept;
|
||||
|
||||
bool flush_one(ActorSignals &signals);
|
||||
bool flush_one_signal(ActorSignals &signals);
|
||||
|
@ -50,6 +50,9 @@
|
||||
|
||||
#define TRY_RESULT(name, result) TRY_RESULT_IMPL(TD_CONCAT(TD_CONCAT(r_, name), __LINE__), auto name, result)
|
||||
|
||||
#define TRY_RESULT_PROMISE(promise_name, name, result) \
|
||||
TRY_RESULT_PROMISE_IMPL(promise_name, TD_CONCAT(TD_CONCAT(r_, name), __LINE__), auto name, result)
|
||||
|
||||
#define TRY_RESULT_ASSIGN(name, result) TRY_RESULT_IMPL(TD_CONCAT(TD_CONCAT(r_, name), __LINE__), name, result)
|
||||
|
||||
#define TRY_RESULT_PREFIX(name, result, prefix) \
|
||||
@ -78,10 +81,18 @@
|
||||
} \
|
||||
name = r_name.move_as_ok();
|
||||
|
||||
#define TRY_RESULT_PROMISE_IMPL(promise_name, r_name, name, result) \
|
||||
auto r_name = (result); \
|
||||
if (r_name.is_error()) { \
|
||||
promise_name.set_error(r_name.move_as_error()); \
|
||||
return; \
|
||||
} \
|
||||
name = r_name.move_as_ok();
|
||||
|
||||
#define TRY_RESULT_PROMISE_PREFIX_IMPL(promise_name, r_name, name, result, prefix) \
|
||||
auto r_name = (result); \
|
||||
if (r_name.is_error()) { \
|
||||
promise.set_error(r_name.move_as_error()); \
|
||||
promise_name.set_error(r_name.move_as_error_prefix(prefix)); \
|
||||
return; \
|
||||
} \
|
||||
name = r_name.move_as_ok();
|
||||
@ -298,14 +309,31 @@ class Status {
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
Status move_as_error_prefix(Slice prefix) TD_WARN_UNUSED_RESULT {
|
||||
Status move_as_error_prefix(const Status &status) const TD_WARN_UNUSED_RESULT {
|
||||
return status.move_as_error_suffix(message());
|
||||
}
|
||||
|
||||
Status move_as_error_prefix(Slice prefix) const TD_WARN_UNUSED_RESULT {
|
||||
CHECK(is_error());
|
||||
Info info = get_info();
|
||||
switch (info.error_type) {
|
||||
case ErrorType::general:
|
||||
return Error(code(), PSLICE() << prefix << message());
|
||||
return Error(code(), PSLICE() << prefix << " " << message());
|
||||
case ErrorType::os:
|
||||
return Status(false, ErrorType::os, code(), PSLICE() << prefix << message());
|
||||
return Status(false, ErrorType::os, code(), PSLICE() << prefix << " " << message());
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
Status move_as_error_suffix(Slice suffix) const TD_WARN_UNUSED_RESULT {
|
||||
CHECK(is_error());
|
||||
Info info = get_info();
|
||||
switch (info.error_type) {
|
||||
case ErrorType::general:
|
||||
return Error(code(), PSLICE() << message() << " " << suffix);
|
||||
case ErrorType::os:
|
||||
return Status(false, ErrorType::os, code(), PSLICE() << message() << " " << suffix);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
@ -488,6 +516,18 @@ class Result {
|
||||
};
|
||||
return status_.move_as_error_prefix(prefix);
|
||||
}
|
||||
Status move_as_error_prefix(const Status &prefix) TD_WARN_UNUSED_RESULT {
|
||||
SCOPE_EXIT {
|
||||
status_ = Status::Error<-5>();
|
||||
};
|
||||
return status_.move_as_error_prefix(prefix);
|
||||
}
|
||||
Status move_as_error_suffix(Slice suffix) TD_WARN_UNUSED_RESULT {
|
||||
SCOPE_EXIT {
|
||||
status_ = Status::Error<-5>();
|
||||
};
|
||||
return status_.move_as_error_suffix(suffix);
|
||||
}
|
||||
const T &ok() const {
|
||||
LOG_CHECK(status_.is_ok()) << status_;
|
||||
return value_;
|
||||
|
@ -32,10 +32,10 @@
|
||||
#include <type_traits>
|
||||
#include <unordered_set>
|
||||
|
||||
#define BEGIN_STORE_FLAGS() \
|
||||
do { \
|
||||
uint32 flags_store = 0; \
|
||||
uint32 bit_offset_store = 0
|
||||
#define BEGIN_STORE_FLAGS() \
|
||||
do { \
|
||||
td::uint32 flags_store = 0; \
|
||||
td::uint32 bit_offset_store = 0
|
||||
|
||||
#define STORE_FLAG(flag) \
|
||||
flags_store |= (flag) << bit_offset_store; \
|
||||
@ -47,10 +47,10 @@
|
||||
} \
|
||||
while (false)
|
||||
|
||||
#define BEGIN_PARSE_FLAGS() \
|
||||
do { \
|
||||
uint32 flags_parse; \
|
||||
uint32 bit_offset_parse = 0; \
|
||||
#define BEGIN_PARSE_FLAGS() \
|
||||
do { \
|
||||
td::uint32 flags_parse; \
|
||||
td::uint32 bit_offset_parse = 0; \
|
||||
td::parse(flags_parse, parser)
|
||||
|
||||
#define PARSE_FLAG(flag) \
|
||||
|
@ -99,6 +99,16 @@ class TlParser {
|
||||
}
|
||||
}
|
||||
|
||||
bool can_prefetch_int() const {
|
||||
return get_left_len() >= sizeof(int32);
|
||||
}
|
||||
|
||||
int32 prefetch_int_unsafe() const {
|
||||
int32 result;
|
||||
std::memcpy(&result, data, sizeof(int32));
|
||||
return result;
|
||||
}
|
||||
|
||||
int32 fetch_int_unsafe() {
|
||||
int32 result;
|
||||
std::memcpy(&result, data, sizeof(int32));
|
||||
|
@ -244,6 +244,8 @@ object_ptr<Object> Object::fetch(td::TlParser &p) {
|
||||
return db_state_destroyedSessions::fetch(p);
|
||||
case db_state_gcBlockId::ID:
|
||||
return db_state_gcBlockId::fetch(p);
|
||||
case db_state_hardforks::ID:
|
||||
return db_state_hardforks::fetch(p);
|
||||
case db_state_initBlockId::ID:
|
||||
return db_state_initBlockId::fetch(p);
|
||||
case db_state_key_destroyedSessions::ID:
|
||||
@ -256,6 +258,8 @@ object_ptr<Object> Object::fetch(td::TlParser &p) {
|
||||
return db_state_key_shardClient::fetch(p);
|
||||
case db_state_key_asyncSerializer::ID:
|
||||
return db_state_key_asyncSerializer::fetch(p);
|
||||
case db_state_key_hardforks::ID:
|
||||
return db_state_key_hardforks::fetch(p);
|
||||
case db_state_shardClient::ID:
|
||||
return db_state_shardClient::fetch(p);
|
||||
case dht_key::ID:
|
||||
@ -498,6 +502,8 @@ object_ptr<Object> Object::fetch(td::TlParser &p) {
|
||||
return tonNode_zeroStateIdExt::fetch(p);
|
||||
case validator_group::ID:
|
||||
return validator_group::fetch(p);
|
||||
case validator_groupEx::ID:
|
||||
return validator_groupEx::fetch(p);
|
||||
case validator_config_global::ID:
|
||||
return validator_config_global::fetch(p);
|
||||
case validator_config_local::ID:
|
||||
@ -5905,6 +5911,44 @@ void db_state_gcBlockId::store(td::TlStorerToString &s, const char *field_name)
|
||||
}
|
||||
}
|
||||
|
||||
db_state_hardforks::db_state_hardforks()
|
||||
: blocks_()
|
||||
{}
|
||||
|
||||
db_state_hardforks::db_state_hardforks(std::vector<object_ptr<tonNode_blockIdExt>> &&blocks_)
|
||||
: blocks_(std::move(blocks_))
|
||||
{}
|
||||
|
||||
const std::int32_t db_state_hardforks::ID;
|
||||
|
||||
object_ptr<db_state_hardforks> db_state_hardforks::fetch(td::TlParser &p) {
|
||||
return make_object<db_state_hardforks>(p);
|
||||
}
|
||||
|
||||
db_state_hardforks::db_state_hardforks(td::TlParser &p)
|
||||
#define FAIL(error) p.set_error(error)
|
||||
: blocks_(TlFetchVector<TlFetchObject<tonNode_blockIdExt>>::parse(p))
|
||||
#undef FAIL
|
||||
{}
|
||||
|
||||
void db_state_hardforks::store(td::TlStorerCalcLength &s) const {
|
||||
(void)sizeof(s);
|
||||
TlStoreVector<TlStoreObject>::store(blocks_, s);
|
||||
}
|
||||
|
||||
void db_state_hardforks::store(td::TlStorerUnsafe &s) const {
|
||||
(void)sizeof(s);
|
||||
TlStoreVector<TlStoreObject>::store(blocks_, s);
|
||||
}
|
||||
|
||||
void db_state_hardforks::store(td::TlStorerToString &s, const char *field_name) const {
|
||||
if (!LOG_IS_STRIPPED(ERROR)) {
|
||||
s.store_class_begin(field_name, "db_state_hardforks");
|
||||
{ const std::vector<object_ptr<tonNode_blockIdExt>> &v = blocks_; 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("blocks", 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_class_end();
|
||||
}
|
||||
}
|
||||
|
||||
db_state_initBlockId::db_state_initBlockId()
|
||||
: block_()
|
||||
{}
|
||||
@ -5957,6 +6001,8 @@ object_ptr<db_state_Key> db_state_Key::fetch(td::TlParser &p) {
|
||||
return db_state_key_shardClient::fetch(p);
|
||||
case db_state_key_asyncSerializer::ID:
|
||||
return db_state_key_asyncSerializer::fetch(p);
|
||||
case db_state_key_hardforks::ID:
|
||||
return db_state_key_hardforks::fetch(p);
|
||||
default:
|
||||
FAIL(PSTRING() << "Unknown constructor found " << td::format::as_hex(constructor));
|
||||
}
|
||||
@ -6118,6 +6164,37 @@ void db_state_key_asyncSerializer::store(td::TlStorerToString &s, const char *fi
|
||||
}
|
||||
}
|
||||
|
||||
db_state_key_hardforks::db_state_key_hardforks() {
|
||||
}
|
||||
|
||||
const std::int32_t db_state_key_hardforks::ID;
|
||||
|
||||
object_ptr<db_state_Key> db_state_key_hardforks::fetch(td::TlParser &p) {
|
||||
return make_object<db_state_key_hardforks>(p);
|
||||
}
|
||||
|
||||
db_state_key_hardforks::db_state_key_hardforks(td::TlParser &p)
|
||||
#define FAIL(error) p.set_error(error)
|
||||
#undef FAIL
|
||||
{
|
||||
(void)p;
|
||||
}
|
||||
|
||||
void db_state_key_hardforks::store(td::TlStorerCalcLength &s) const {
|
||||
(void)sizeof(s);
|
||||
}
|
||||
|
||||
void db_state_key_hardforks::store(td::TlStorerUnsafe &s) const {
|
||||
(void)sizeof(s);
|
||||
}
|
||||
|
||||
void db_state_key_hardforks::store(td::TlStorerToString &s, const char *field_name) const {
|
||||
if (!LOG_IS_STRIPPED(ERROR)) {
|
||||
s.store_class_begin(field_name, "db_state_key_hardforks");
|
||||
s.store_class_end();
|
||||
}
|
||||
}
|
||||
|
||||
db_state_shardClient::db_state_shardClient()
|
||||
: block_()
|
||||
{}
|
||||
@ -11755,6 +11832,20 @@ void tonNode_zeroStateIdExt::store(td::TlStorerToString &s, const char *field_na
|
||||
}
|
||||
}
|
||||
|
||||
object_ptr<validator_Group> validator_Group::fetch(td::TlParser &p) {
|
||||
#define FAIL(error) p.set_error(error); return nullptr;
|
||||
int constructor = p.fetch_int();
|
||||
switch (constructor) {
|
||||
case validator_group::ID:
|
||||
return validator_group::fetch(p);
|
||||
case validator_groupEx::ID:
|
||||
return validator_groupEx::fetch(p);
|
||||
default:
|
||||
FAIL(PSTRING() << "Unknown constructor found " << td::format::as_hex(constructor));
|
||||
}
|
||||
#undef FAIL
|
||||
}
|
||||
|
||||
validator_group::validator_group()
|
||||
: workchain_()
|
||||
, shard_()
|
||||
@ -11773,7 +11864,7 @@ validator_group::validator_group(std::int32_t workchain_, std::int64_t shard_, s
|
||||
|
||||
const std::int32_t validator_group::ID;
|
||||
|
||||
object_ptr<validator_group> validator_group::fetch(td::TlParser &p) {
|
||||
object_ptr<validator_Group> validator_group::fetch(td::TlParser &p) {
|
||||
return make_object<validator_group>(p);
|
||||
}
|
||||
|
||||
@ -11817,6 +11908,74 @@ void validator_group::store(td::TlStorerToString &s, const char *field_name) con
|
||||
}
|
||||
}
|
||||
|
||||
validator_groupEx::validator_groupEx()
|
||||
: workchain_()
|
||||
, shard_()
|
||||
, vertical_seqno_()
|
||||
, catchain_seqno_()
|
||||
, config_hash_()
|
||||
, members_()
|
||||
{}
|
||||
|
||||
validator_groupEx::validator_groupEx(std::int32_t workchain_, std::int64_t shard_, std::int32_t vertical_seqno_, std::int32_t catchain_seqno_, td::Bits256 const &config_hash_, std::vector<object_ptr<validator_groupMember>> &&members_)
|
||||
: workchain_(workchain_)
|
||||
, shard_(shard_)
|
||||
, vertical_seqno_(vertical_seqno_)
|
||||
, catchain_seqno_(catchain_seqno_)
|
||||
, config_hash_(config_hash_)
|
||||
, members_(std::move(members_))
|
||||
{}
|
||||
|
||||
const std::int32_t validator_groupEx::ID;
|
||||
|
||||
object_ptr<validator_Group> validator_groupEx::fetch(td::TlParser &p) {
|
||||
return make_object<validator_groupEx>(p);
|
||||
}
|
||||
|
||||
validator_groupEx::validator_groupEx(td::TlParser &p)
|
||||
#define FAIL(error) p.set_error(error)
|
||||
: workchain_(TlFetchInt::parse(p))
|
||||
, shard_(TlFetchLong::parse(p))
|
||||
, vertical_seqno_(TlFetchInt::parse(p))
|
||||
, catchain_seqno_(TlFetchInt::parse(p))
|
||||
, config_hash_(TlFetchInt256::parse(p))
|
||||
, members_(TlFetchVector<TlFetchObject<validator_groupMember>>::parse(p))
|
||||
#undef FAIL
|
||||
{}
|
||||
|
||||
void validator_groupEx::store(td::TlStorerCalcLength &s) const {
|
||||
(void)sizeof(s);
|
||||
TlStoreBinary::store(workchain_, s);
|
||||
TlStoreBinary::store(shard_, s);
|
||||
TlStoreBinary::store(vertical_seqno_, s);
|
||||
TlStoreBinary::store(catchain_seqno_, s);
|
||||
TlStoreBinary::store(config_hash_, s);
|
||||
TlStoreVector<TlStoreObject>::store(members_, s);
|
||||
}
|
||||
|
||||
void validator_groupEx::store(td::TlStorerUnsafe &s) const {
|
||||
(void)sizeof(s);
|
||||
TlStoreBinary::store(workchain_, s);
|
||||
TlStoreBinary::store(shard_, s);
|
||||
TlStoreBinary::store(vertical_seqno_, s);
|
||||
TlStoreBinary::store(catchain_seqno_, s);
|
||||
TlStoreBinary::store(config_hash_, s);
|
||||
TlStoreVector<TlStoreObject>::store(members_, s);
|
||||
}
|
||||
|
||||
void validator_groupEx::store(td::TlStorerToString &s, const char *field_name) const {
|
||||
if (!LOG_IS_STRIPPED(ERROR)) {
|
||||
s.store_class_begin(field_name, "validator_groupEx");
|
||||
s.store_field("workchain", workchain_);
|
||||
s.store_field("shard", shard_);
|
||||
s.store_field("vertical_seqno", vertical_seqno_);
|
||||
s.store_field("catchain_seqno", catchain_seqno_);
|
||||
s.store_field("config_hash", config_hash_);
|
||||
{ const std::vector<object_ptr<validator_groupMember>> &v = members_; 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("members", 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_class_end();
|
||||
}
|
||||
}
|
||||
|
||||
validator_config_global::validator_config_global()
|
||||
: zero_state_()
|
||||
, init_block_()
|
||||
|
@ -162,6 +162,8 @@ class db_state_destroyedSessions;
|
||||
|
||||
class db_state_gcBlockId;
|
||||
|
||||
class db_state_hardforks;
|
||||
|
||||
class db_state_initBlockId;
|
||||
|
||||
class db_state_Key;
|
||||
@ -344,7 +346,7 @@ class tonNode_success;
|
||||
|
||||
class tonNode_zeroStateIdExt;
|
||||
|
||||
class validator_group;
|
||||
class validator_Group;
|
||||
|
||||
class validator_config_global;
|
||||
|
||||
@ -3215,6 +3217,30 @@ class db_state_gcBlockId final : public Object {
|
||||
void store(td::TlStorerToString &s, const char *field_name) const final;
|
||||
};
|
||||
|
||||
class db_state_hardforks final : public Object {
|
||||
public:
|
||||
std::vector<object_ptr<tonNode_blockIdExt>> blocks_;
|
||||
|
||||
db_state_hardforks();
|
||||
|
||||
explicit db_state_hardforks(std::vector<object_ptr<tonNode_blockIdExt>> &&blocks_);
|
||||
|
||||
static const std::int32_t ID = -2047668988;
|
||||
std::int32_t get_id() const final {
|
||||
return ID;
|
||||
}
|
||||
|
||||
static object_ptr<db_state_hardforks> fetch(td::TlParser &p);
|
||||
|
||||
explicit db_state_hardforks(td::TlParser &p);
|
||||
|
||||
void store(td::TlStorerCalcLength &s) const final;
|
||||
|
||||
void store(td::TlStorerUnsafe &s) const final;
|
||||
|
||||
void store(td::TlStorerToString &s, const char *field_name) const final;
|
||||
};
|
||||
|
||||
class db_state_initBlockId final : public Object {
|
||||
public:
|
||||
object_ptr<tonNode_blockIdExt> block_;
|
||||
@ -3350,6 +3376,27 @@ class db_state_key_asyncSerializer final : public db_state_Key {
|
||||
void store(td::TlStorerToString &s, const char *field_name) const final;
|
||||
};
|
||||
|
||||
class db_state_key_hardforks final : public db_state_Key {
|
||||
public:
|
||||
|
||||
db_state_key_hardforks();
|
||||
|
||||
static const std::int32_t ID = -420206662;
|
||||
std::int32_t get_id() const final {
|
||||
return ID;
|
||||
}
|
||||
|
||||
static object_ptr<db_state_Key> fetch(td::TlParser &p);
|
||||
|
||||
explicit db_state_key_hardforks(td::TlParser &p);
|
||||
|
||||
void store(td::TlStorerCalcLength &s) const final;
|
||||
|
||||
void store(td::TlStorerUnsafe &s) const final;
|
||||
|
||||
void store(td::TlStorerToString &s, const char *field_name) const final;
|
||||
};
|
||||
|
||||
class db_state_shardClient final : public Object {
|
||||
public:
|
||||
object_ptr<tonNode_blockIdExt> block_;
|
||||
@ -6440,7 +6487,13 @@ class tonNode_zeroStateIdExt final : public Object {
|
||||
void store(td::TlStorerToString &s, const char *field_name) const final;
|
||||
};
|
||||
|
||||
class validator_group final : public Object {
|
||||
class validator_Group: public Object {
|
||||
public:
|
||||
|
||||
static object_ptr<validator_Group> fetch(td::TlParser &p);
|
||||
};
|
||||
|
||||
class validator_group final : public validator_Group {
|
||||
public:
|
||||
std::int32_t workchain_;
|
||||
std::int64_t shard_;
|
||||
@ -6457,7 +6510,7 @@ class validator_group final : public Object {
|
||||
return ID;
|
||||
}
|
||||
|
||||
static object_ptr<validator_group> fetch(td::TlParser &p);
|
||||
static object_ptr<validator_Group> fetch(td::TlParser &p);
|
||||
|
||||
explicit validator_group(td::TlParser &p);
|
||||
|
||||
@ -6468,6 +6521,35 @@ class validator_group final : public Object {
|
||||
void store(td::TlStorerToString &s, const char *field_name) const final;
|
||||
};
|
||||
|
||||
class validator_groupEx final : public validator_Group {
|
||||
public:
|
||||
std::int32_t workchain_;
|
||||
std::int64_t shard_;
|
||||
std::int32_t vertical_seqno_;
|
||||
std::int32_t catchain_seqno_;
|
||||
td::Bits256 config_hash_;
|
||||
std::vector<object_ptr<validator_groupMember>> members_;
|
||||
|
||||
validator_groupEx();
|
||||
|
||||
validator_groupEx(std::int32_t workchain_, std::int64_t shard_, std::int32_t vertical_seqno_, std::int32_t catchain_seqno_, td::Bits256 const &config_hash_, std::vector<object_ptr<validator_groupMember>> &&members_);
|
||||
|
||||
static const std::int32_t ID = 479350270;
|
||||
std::int32_t get_id() const final {
|
||||
return ID;
|
||||
}
|
||||
|
||||
static object_ptr<validator_Group> fetch(td::TlParser &p);
|
||||
|
||||
explicit validator_groupEx(td::TlParser &p);
|
||||
|
||||
void store(td::TlStorerCalcLength &s) const final;
|
||||
|
||||
void store(td::TlStorerUnsafe &s) const final;
|
||||
|
||||
void store(td::TlStorerToString &s, const char *field_name) const final;
|
||||
};
|
||||
|
||||
class validator_config_global final : public Object {
|
||||
public:
|
||||
object_ptr<tonNode_blockIdExt> zero_state_;
|
||||
|
@ -344,6 +344,9 @@ bool downcast_call(Object &obj, const T &func) {
|
||||
case db_state_gcBlockId::ID:
|
||||
func(static_cast<db_state_gcBlockId &>(obj));
|
||||
return true;
|
||||
case db_state_hardforks::ID:
|
||||
func(static_cast<db_state_hardforks &>(obj));
|
||||
return true;
|
||||
case db_state_initBlockId::ID:
|
||||
func(static_cast<db_state_initBlockId &>(obj));
|
||||
return true;
|
||||
@ -362,6 +365,9 @@ bool downcast_call(Object &obj, const T &func) {
|
||||
case db_state_key_asyncSerializer::ID:
|
||||
func(static_cast<db_state_key_asyncSerializer &>(obj));
|
||||
return true;
|
||||
case db_state_key_hardforks::ID:
|
||||
func(static_cast<db_state_key_hardforks &>(obj));
|
||||
return true;
|
||||
case db_state_shardClient::ID:
|
||||
func(static_cast<db_state_shardClient &>(obj));
|
||||
return true;
|
||||
@ -725,6 +731,9 @@ bool downcast_call(Object &obj, const T &func) {
|
||||
case validator_group::ID:
|
||||
func(static_cast<validator_group &>(obj));
|
||||
return true;
|
||||
case validator_groupEx::ID:
|
||||
func(static_cast<validator_groupEx &>(obj));
|
||||
return true;
|
||||
case validator_config_global::ID:
|
||||
func(static_cast<validator_config_global &>(obj));
|
||||
return true;
|
||||
@ -1470,6 +1479,9 @@ bool downcast_call(db_state_Key &obj, const T &func) {
|
||||
case db_state_key_asyncSerializer::ID:
|
||||
func(static_cast<db_state_key_asyncSerializer &>(obj));
|
||||
return true;
|
||||
case db_state_key_hardforks::ID:
|
||||
func(static_cast<db_state_key_hardforks &>(obj));
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -1874,6 +1886,26 @@ bool downcast_call(tonNode_PreparedState &obj, const T &func) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls specified function object with the specified object downcasted to the most-derived type.
|
||||
* \param[in] obj Object to pass as an argument to the function object.
|
||||
* \param[in] func Function object to which the object will be passed.
|
||||
* \returns whether function object call has happened. Should always return true for correct parameters.
|
||||
*/
|
||||
template <class T>
|
||||
bool downcast_call(validator_Group &obj, const T &func) {
|
||||
switch (obj.get_id()) {
|
||||
case validator_group::ID:
|
||||
func(static_cast<validator_group &>(obj));
|
||||
return true;
|
||||
case validator_groupEx::ID:
|
||||
func(static_cast<validator_groupEx &>(obj));
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls specified function object with the specified object downcasted to the most-derived type.
|
||||
* \param[in] obj Object to pass as an argument to the function object.
|
||||
|
@ -226,7 +226,8 @@ Result<int32> tl_constructor_from_string(ton_api::db_state_Key *object, const st
|
||||
{"db.state.key.initBlockId", 1971484899},
|
||||
{"db.state.key.gcBlockId", -1015417890},
|
||||
{"db.state.key.shardClient", -912576121},
|
||||
{"db.state.key.asyncSerializer", 699304479}
|
||||
{"db.state.key.asyncSerializer", 699304479},
|
||||
{"db.state.key.hardforks", -420206662}
|
||||
};
|
||||
auto it = m.find(str);
|
||||
if (it == m.end()) {
|
||||
@ -445,6 +446,17 @@ Result<int32> tl_constructor_from_string(ton_api::tonNode_PreparedState *object,
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
Result<int32> tl_constructor_from_string(ton_api::validator_Group *object, const std::string &str) {
|
||||
static const std::unordered_map<Slice, int32, SliceHash> m = {
|
||||
{"validator.group", -120029535},
|
||||
{"validator.groupEx", 479350270}
|
||||
};
|
||||
auto it = m.find(str);
|
||||
if (it == m.end()) {
|
||||
return Status::Error(str + "Unknown class");
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
Result<int32> tl_constructor_from_string(ton_api::validator_config_Local *object, const std::string &str) {
|
||||
static const std::unordered_map<Slice, int32, SliceHash> m = {
|
||||
{"validator.config.local", 1716256616},
|
||||
@ -596,12 +608,14 @@ Result<int32> tl_constructor_from_string(ton_api::Object *object, const std::str
|
||||
{"db.state.asyncSerializer", -751883871},
|
||||
{"db.state.destroyedSessions", -1381443196},
|
||||
{"db.state.gcBlockId", -550453937},
|
||||
{"db.state.hardforks", -2047668988},
|
||||
{"db.state.initBlockId", 1932303605},
|
||||
{"db.state.key.destroyedSessions", -386404007},
|
||||
{"db.state.key.initBlockId", 1971484899},
|
||||
{"db.state.key.gcBlockId", -1015417890},
|
||||
{"db.state.key.shardClient", -912576121},
|
||||
{"db.state.key.asyncSerializer", 699304479},
|
||||
{"db.state.key.hardforks", -420206662},
|
||||
{"db.state.shardClient", 186033821},
|
||||
{"dht.key", -160964977},
|
||||
{"dht.keyDescription", 673009157},
|
||||
@ -723,6 +737,7 @@ Result<int32> tl_constructor_from_string(ton_api::Object *object, const std::str
|
||||
{"tonNode.success", -1063902129},
|
||||
{"tonNode.zeroStateIdExt", 494024110},
|
||||
{"validator.group", -120029535},
|
||||
{"validator.groupEx", 479350270},
|
||||
{"validator.config.global", -2038562966},
|
||||
{"validator.config.local", 1716256616},
|
||||
{"validator.config.random.local", 1501795426},
|
||||
@ -2554,6 +2569,15 @@ Status from_json(ton_api::db_state_gcBlockId &to, JsonObject &from) {
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
Status from_json(ton_api::db_state_hardforks &to, JsonObject &from) {
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "blocks", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json(to.blocks_, value));
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
Status from_json(ton_api::db_state_initBlockId &to, JsonObject &from) {
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "block", JsonValue::Type::Null, true));
|
||||
@ -2578,6 +2602,9 @@ Status from_json(ton_api::db_state_key_shardClient &to, JsonObject &from) {
|
||||
Status from_json(ton_api::db_state_key_asyncSerializer &to, JsonObject &from) {
|
||||
return Status::OK();
|
||||
}
|
||||
Status from_json(ton_api::db_state_key_hardforks &to, JsonObject &from) {
|
||||
return Status::OK();
|
||||
}
|
||||
Status from_json(ton_api::db_state_shardClient &to, JsonObject &from) {
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "block", JsonValue::Type::Null, true));
|
||||
@ -4507,6 +4534,45 @@ Status from_json(ton_api::validator_group &to, JsonObject &from) {
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
Status from_json(ton_api::validator_groupEx &to, JsonObject &from) {
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "workchain", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json(to.workchain_, value));
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "shard", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json(to.shard_, value));
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "vertical_seqno", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json(to.vertical_seqno_, value));
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "catchain_seqno", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json(to.catchain_seqno_, value));
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "config_hash", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json(to.config_hash_, value));
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "members", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json(to.members_, value));
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
Status from_json(ton_api::validator_config_global &to, JsonObject &from) {
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "zero_state", JsonValue::Type::Null, true));
|
||||
@ -6631,6 +6697,11 @@ void to_json(JsonValueScope &jv, const ton_api::db_state_gcBlockId &object) {
|
||||
jo << ctie("block", ToJson(object.block_));
|
||||
}
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_hardforks &object) {
|
||||
auto jo = jv.enter_object();
|
||||
jo << ctie("@type", "db.state.hardforks");
|
||||
jo << ctie("blocks", ToJson(object.blocks_));
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_initBlockId &object) {
|
||||
auto jo = jv.enter_object();
|
||||
jo << ctie("@type", "db.state.initBlockId");
|
||||
@ -6661,6 +6732,10 @@ void to_json(JsonValueScope &jv, const ton_api::db_state_key_asyncSerializer &ob
|
||||
auto jo = jv.enter_object();
|
||||
jo << ctie("@type", "db.state.key.asyncSerializer");
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_key_hardforks &object) {
|
||||
auto jo = jv.enter_object();
|
||||
jo << ctie("@type", "db.state.key.hardforks");
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_shardClient &object) {
|
||||
auto jo = jv.enter_object();
|
||||
jo << ctie("@type", "db.state.shardClient");
|
||||
@ -7535,6 +7610,9 @@ void to_json(JsonValueScope &jv, const ton_api::tonNode_zeroStateIdExt &object)
|
||||
jo << ctie("root_hash", ToJson(object.root_hash_));
|
||||
jo << ctie("file_hash", ToJson(object.file_hash_));
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const ton_api::validator_Group &object) {
|
||||
ton_api::downcast_call(const_cast<ton_api::validator_Group &>(object), [&jv](const auto &object) { to_json(jv, object); });
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const ton_api::validator_group &object) {
|
||||
auto jo = jv.enter_object();
|
||||
jo << ctie("@type", "validator.group");
|
||||
@ -7544,6 +7622,16 @@ void to_json(JsonValueScope &jv, const ton_api::validator_group &object) {
|
||||
jo << ctie("config_hash", ToJson(object.config_hash_));
|
||||
jo << ctie("members", ToJson(object.members_));
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const ton_api::validator_groupEx &object) {
|
||||
auto jo = jv.enter_object();
|
||||
jo << ctie("@type", "validator.groupEx");
|
||||
jo << ctie("workchain", ToJson(object.workchain_));
|
||||
jo << ctie("shard", ToJson(JsonInt64{object.shard_}));
|
||||
jo << ctie("vertical_seqno", ToJson(object.vertical_seqno_));
|
||||
jo << ctie("catchain_seqno", ToJson(object.catchain_seqno_));
|
||||
jo << ctie("config_hash", ToJson(object.config_hash_));
|
||||
jo << ctie("members", ToJson(object.members_));
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const ton_api::validator_config_global &object) {
|
||||
auto jo = jv.enter_object();
|
||||
jo << ctie("@type", "validator.config.global");
|
||||
|
@ -45,6 +45,7 @@ Result<int32> tl_constructor_from_string(ton_api::tonNode_DataFull *object, cons
|
||||
Result<int32> tl_constructor_from_string(ton_api::tonNode_Prepared *object, const std::string &str);
|
||||
Result<int32> tl_constructor_from_string(ton_api::tonNode_PreparedProof *object, const std::string &str);
|
||||
Result<int32> tl_constructor_from_string(ton_api::tonNode_PreparedState *object, const std::string &str);
|
||||
Result<int32> tl_constructor_from_string(ton_api::validator_Group *object, const std::string &str);
|
||||
Result<int32> tl_constructor_from_string(ton_api::validator_config_Local *object, const std::string &str);
|
||||
Result<int32> tl_constructor_from_string(ton_api::validatorSession_Message *object, const std::string &str);
|
||||
Result<int32> tl_constructor_from_string(ton_api::validatorSession_round_Message *object, const std::string &str);
|
||||
@ -160,12 +161,14 @@ Status from_json(ton_api::db_root_key_config &to, JsonObject &from);
|
||||
Status from_json(ton_api::db_state_asyncSerializer &to, JsonObject &from);
|
||||
Status from_json(ton_api::db_state_destroyedSessions &to, JsonObject &from);
|
||||
Status from_json(ton_api::db_state_gcBlockId &to, JsonObject &from);
|
||||
Status from_json(ton_api::db_state_hardforks &to, JsonObject &from);
|
||||
Status from_json(ton_api::db_state_initBlockId &to, JsonObject &from);
|
||||
Status from_json(ton_api::db_state_key_destroyedSessions &to, JsonObject &from);
|
||||
Status from_json(ton_api::db_state_key_initBlockId &to, JsonObject &from);
|
||||
Status from_json(ton_api::db_state_key_gcBlockId &to, JsonObject &from);
|
||||
Status from_json(ton_api::db_state_key_shardClient &to, JsonObject &from);
|
||||
Status from_json(ton_api::db_state_key_asyncSerializer &to, JsonObject &from);
|
||||
Status from_json(ton_api::db_state_key_hardforks &to, JsonObject &from);
|
||||
Status from_json(ton_api::db_state_shardClient &to, JsonObject &from);
|
||||
Status from_json(ton_api::dht_key &to, JsonObject &from);
|
||||
Status from_json(ton_api::dht_keyDescription &to, JsonObject &from);
|
||||
@ -287,6 +290,7 @@ Status from_json(ton_api::tonNode_shardPublicOverlayId &to, JsonObject &from);
|
||||
Status from_json(ton_api::tonNode_success &to, JsonObject &from);
|
||||
Status from_json(ton_api::tonNode_zeroStateIdExt &to, JsonObject &from);
|
||||
Status from_json(ton_api::validator_group &to, JsonObject &from);
|
||||
Status from_json(ton_api::validator_groupEx &to, JsonObject &from);
|
||||
Status from_json(ton_api::validator_config_global &to, JsonObject &from);
|
||||
Status from_json(ton_api::validator_config_local &to, JsonObject &from);
|
||||
Status from_json(ton_api::validator_config_random_local &to, JsonObject &from);
|
||||
@ -505,6 +509,7 @@ void to_json(JsonValueScope &jv, const ton_api::db_root_key_config &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_asyncSerializer &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_destroyedSessions &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_gcBlockId &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_hardforks &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_initBlockId &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_Key &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_key_destroyedSessions &object);
|
||||
@ -512,6 +517,7 @@ void to_json(JsonValueScope &jv, const ton_api::db_state_key_initBlockId &object
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_key_gcBlockId &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_key_shardClient &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_key_asyncSerializer &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_key_hardforks &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::db_state_shardClient &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::dht_key &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::dht_keyDescription &object);
|
||||
@ -650,7 +656,9 @@ void to_json(JsonValueScope &jv, const ton_api::tonNode_sessionId &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::tonNode_shardPublicOverlayId &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::tonNode_success &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::tonNode_zeroStateIdExt &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::validator_Group &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::validator_group &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::validator_groupEx &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::validator_config_global &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::validator_config_Local &object);
|
||||
void to_json(JsonValueScope &jv, const ton_api::validator_config_local &object);
|
||||
|
@ -199,6 +199,36 @@ void key::store(td::TlStorerToString &s, const char *field_name) const {
|
||||
}
|
||||
}
|
||||
|
||||
keyStoreTypeDirectory::keyStoreTypeDirectory()
|
||||
: directory_()
|
||||
{}
|
||||
|
||||
keyStoreTypeDirectory::keyStoreTypeDirectory(std::string const &directory_)
|
||||
: directory_(std::move(directory_))
|
||||
{}
|
||||
|
||||
const std::int32_t keyStoreTypeDirectory::ID;
|
||||
|
||||
void keyStoreTypeDirectory::store(td::TlStorerToString &s, const char *field_name) const {
|
||||
if (!LOG_IS_STRIPPED(ERROR)) {
|
||||
s.store_class_begin(field_name, "keyStoreTypeDirectory");
|
||||
s.store_field("directory", directory_);
|
||||
s.store_class_end();
|
||||
}
|
||||
}
|
||||
|
||||
keyStoreTypeInMemory::keyStoreTypeInMemory() {
|
||||
}
|
||||
|
||||
const std::int32_t keyStoreTypeInMemory::ID;
|
||||
|
||||
void keyStoreTypeInMemory::store(td::TlStorerToString &s, const char *field_name) const {
|
||||
if (!LOG_IS_STRIPPED(ERROR)) {
|
||||
s.store_class_begin(field_name, "keyStoreTypeInMemory");
|
||||
s.store_class_end();
|
||||
}
|
||||
}
|
||||
|
||||
logStreamDefault::logStreamDefault() {
|
||||
}
|
||||
|
||||
@ -294,12 +324,12 @@ void ok::store(td::TlStorerToString &s, const char *field_name) const {
|
||||
|
||||
options::options()
|
||||
: config_()
|
||||
, keystore_directory_()
|
||||
, keystore_type_()
|
||||
{}
|
||||
|
||||
options::options(object_ptr<config> &&config_, std::string const &keystore_directory_)
|
||||
options::options(object_ptr<config> &&config_, object_ptr<KeyStoreType> &&keystore_type_)
|
||||
: config_(std::move(config_))
|
||||
, keystore_directory_(std::move(keystore_directory_))
|
||||
, keystore_type_(std::move(keystore_type_))
|
||||
{}
|
||||
|
||||
const std::int32_t options::ID;
|
||||
@ -308,17 +338,19 @@ void options::store(td::TlStorerToString &s, const char *field_name) const {
|
||||
if (!LOG_IS_STRIPPED(ERROR)) {
|
||||
s.store_class_begin(field_name, "options");
|
||||
if (config_ == nullptr) { s.store_field("config", "null"); } else { config_->store(s, "config"); }
|
||||
s.store_field("keystore_directory", keystore_directory_);
|
||||
if (keystore_type_ == nullptr) { s.store_field("keystore_type", "null"); } else { keystore_type_->store(s, "keystore_type"); }
|
||||
s.store_class_end();
|
||||
}
|
||||
}
|
||||
|
||||
sendGramsResult::sendGramsResult()
|
||||
: sent_until_()
|
||||
, body_hash_()
|
||||
{}
|
||||
|
||||
sendGramsResult::sendGramsResult(std::int64_t sent_until_)
|
||||
sendGramsResult::sendGramsResult(std::int64_t sent_until_, std::string const &body_hash_)
|
||||
: sent_until_(sent_until_)
|
||||
, body_hash_(std::move(body_hash_))
|
||||
{}
|
||||
|
||||
const std::int32_t sendGramsResult::ID;
|
||||
@ -327,6 +359,7 @@ void sendGramsResult::store(td::TlStorerToString &s, const char *field_name) con
|
||||
if (!LOG_IS_STRIPPED(ERROR)) {
|
||||
s.store_class_begin(field_name, "sendGramsResult");
|
||||
s.store_field("sent_until", sent_until_);
|
||||
s.store_bytes_field("body_hash", body_hash_);
|
||||
s.store_class_end();
|
||||
}
|
||||
}
|
||||
@ -545,13 +578,21 @@ raw_message::raw_message()
|
||||
: source_()
|
||||
, destination_()
|
||||
, value_()
|
||||
, fwd_fee_()
|
||||
, ihr_fee_()
|
||||
, created_lt_()
|
||||
, body_hash_()
|
||||
, message_()
|
||||
{}
|
||||
|
||||
raw_message::raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::string const &message_)
|
||||
raw_message::raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::int64_t fwd_fee_, std::int64_t ihr_fee_, std::int64_t created_lt_, std::string const &body_hash_, std::string const &message_)
|
||||
: source_(std::move(source_))
|
||||
, destination_(std::move(destination_))
|
||||
, value_(value_)
|
||||
, fwd_fee_(fwd_fee_)
|
||||
, ihr_fee_(ihr_fee_)
|
||||
, created_lt_(created_lt_)
|
||||
, body_hash_(std::move(body_hash_))
|
||||
, message_(std::move(message_))
|
||||
{}
|
||||
|
||||
@ -563,6 +604,10 @@ void raw_message::store(td::TlStorerToString &s, const char *field_name) const {
|
||||
s.store_field("source", source_);
|
||||
s.store_field("destination", destination_);
|
||||
s.store_field("value", value_);
|
||||
s.store_field("fwd_fee", fwd_fee_);
|
||||
s.store_field("ihr_fee", ihr_fee_);
|
||||
s.store_field("created_lt", created_lt_);
|
||||
s.store_bytes_field("body_hash", body_hash_);
|
||||
s.store_bytes_field("message", message_);
|
||||
s.store_class_end();
|
||||
}
|
||||
@ -573,15 +618,19 @@ raw_transaction::raw_transaction()
|
||||
, data_()
|
||||
, transaction_id_()
|
||||
, fee_()
|
||||
, storage_fee_()
|
||||
, other_fee_()
|
||||
, in_msg_()
|
||||
, out_msgs_()
|
||||
{}
|
||||
|
||||
raw_transaction::raw_transaction(std::int64_t utime_, std::string const &data_, object_ptr<internal_transactionId> &&transaction_id_, std::int64_t fee_, object_ptr<raw_message> &&in_msg_, std::vector<object_ptr<raw_message>> &&out_msgs_)
|
||||
raw_transaction::raw_transaction(std::int64_t utime_, std::string const &data_, object_ptr<internal_transactionId> &&transaction_id_, std::int64_t fee_, std::int64_t storage_fee_, std::int64_t other_fee_, object_ptr<raw_message> &&in_msg_, std::vector<object_ptr<raw_message>> &&out_msgs_)
|
||||
: utime_(utime_)
|
||||
, data_(std::move(data_))
|
||||
, transaction_id_(std::move(transaction_id_))
|
||||
, fee_(fee_)
|
||||
, storage_fee_(storage_fee_)
|
||||
, other_fee_(other_fee_)
|
||||
, in_msg_(std::move(in_msg_))
|
||||
, out_msgs_(std::move(out_msgs_))
|
||||
{}
|
||||
@ -595,6 +644,8 @@ void raw_transaction::store(td::TlStorerToString &s, const char *field_name) con
|
||||
s.store_bytes_field("data", data_);
|
||||
if (transaction_id_ == nullptr) { s.store_field("transaction_id", "null"); } else { transaction_id_->store(s, "transaction_id"); }
|
||||
s.store_field("fee", fee_);
|
||||
s.store_field("storage_fee", storage_fee_);
|
||||
s.store_field("other_fee", other_fee_);
|
||||
if (in_msg_ == nullptr) { s.store_field("in_msg", "null"); } else { in_msg_->store(s, "in_msg"); }
|
||||
{ const std::vector<object_ptr<raw_message>> &v = out_msgs_; 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("out_msgs", 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_class_end();
|
||||
@ -841,6 +892,18 @@ void createNewKey::store(td::TlStorerToString &s, const char *field_name) const
|
||||
}
|
||||
}
|
||||
|
||||
deleteAllKeys::deleteAllKeys() {
|
||||
}
|
||||
|
||||
const std::int32_t deleteAllKeys::ID;
|
||||
|
||||
void deleteAllKeys::store(td::TlStorerToString &s, const char *field_name) const {
|
||||
if (!LOG_IS_STRIPPED(ERROR)) {
|
||||
s.store_class_begin(field_name, "deleteAllKeys");
|
||||
s.store_class_end();
|
||||
}
|
||||
}
|
||||
|
||||
deleteKey::deleteKey()
|
||||
: key_()
|
||||
{}
|
||||
|
@ -62,6 +62,8 @@ class inputKey;
|
||||
|
||||
class key;
|
||||
|
||||
class KeyStoreType;
|
||||
|
||||
class LogStream;
|
||||
|
||||
class logTags;
|
||||
@ -264,6 +266,39 @@ class key final : public Object {
|
||||
void store(td::TlStorerToString &s, const char *field_name) const final;
|
||||
};
|
||||
|
||||
class KeyStoreType: public Object {
|
||||
public:
|
||||
};
|
||||
|
||||
class keyStoreTypeDirectory final : public KeyStoreType {
|
||||
public:
|
||||
std::string directory_;
|
||||
|
||||
keyStoreTypeDirectory();
|
||||
|
||||
explicit keyStoreTypeDirectory(std::string const &directory_);
|
||||
|
||||
static const std::int32_t ID = -378990038;
|
||||
std::int32_t get_id() const final {
|
||||
return ID;
|
||||
}
|
||||
|
||||
void store(td::TlStorerToString &s, const char *field_name) const final;
|
||||
};
|
||||
|
||||
class keyStoreTypeInMemory final : public KeyStoreType {
|
||||
public:
|
||||
|
||||
keyStoreTypeInMemory();
|
||||
|
||||
static const std::int32_t ID = -2106848825;
|
||||
std::int32_t get_id() const final {
|
||||
return ID;
|
||||
}
|
||||
|
||||
void store(td::TlStorerToString &s, const char *field_name) const final;
|
||||
};
|
||||
|
||||
class LogStream: public Object {
|
||||
public:
|
||||
};
|
||||
@ -359,13 +394,13 @@ class ok final : public Object {
|
||||
class options final : public Object {
|
||||
public:
|
||||
object_ptr<config> config_;
|
||||
std::string keystore_directory_;
|
||||
object_ptr<KeyStoreType> keystore_type_;
|
||||
|
||||
options();
|
||||
|
||||
options(object_ptr<config> &&config_, std::string const &keystore_directory_);
|
||||
options(object_ptr<config> &&config_, object_ptr<KeyStoreType> &&keystore_type_);
|
||||
|
||||
static const std::int32_t ID = 789823302;
|
||||
static const std::int32_t ID = -1924388359;
|
||||
std::int32_t get_id() const final {
|
||||
return ID;
|
||||
}
|
||||
@ -376,12 +411,13 @@ class options final : public Object {
|
||||
class sendGramsResult final : public Object {
|
||||
public:
|
||||
std::int64_t sent_until_;
|
||||
std::string body_hash_;
|
||||
|
||||
sendGramsResult();
|
||||
|
||||
explicit sendGramsResult(std::int64_t sent_until_);
|
||||
sendGramsResult(std::int64_t sent_until_, std::string const &body_hash_);
|
||||
|
||||
static const std::int32_t ID = -858318471;
|
||||
static const std::int32_t ID = 426872238;
|
||||
std::int32_t get_id() const final {
|
||||
return ID;
|
||||
}
|
||||
@ -568,13 +604,17 @@ class raw_message final : public Object {
|
||||
std::string source_;
|
||||
std::string destination_;
|
||||
std::int64_t value_;
|
||||
std::int64_t fwd_fee_;
|
||||
std::int64_t ihr_fee_;
|
||||
std::int64_t created_lt_;
|
||||
std::string body_hash_;
|
||||
std::string message_;
|
||||
|
||||
raw_message();
|
||||
|
||||
raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::string const &message_);
|
||||
raw_message(std::string const &source_, std::string const &destination_, std::int64_t value_, std::int64_t fwd_fee_, std::int64_t ihr_fee_, std::int64_t created_lt_, std::string const &body_hash_, std::string const &message_);
|
||||
|
||||
static const std::int32_t ID = -259956097;
|
||||
static const std::int32_t ID = -906281442;
|
||||
std::int32_t get_id() const final {
|
||||
return ID;
|
||||
}
|
||||
@ -588,14 +628,16 @@ class raw_transaction final : public Object {
|
||||
std::string data_;
|
||||
object_ptr<internal_transactionId> transaction_id_;
|
||||
std::int64_t fee_;
|
||||
std::int64_t storage_fee_;
|
||||
std::int64_t other_fee_;
|
||||
object_ptr<raw_message> in_msg_;
|
||||
std::vector<object_ptr<raw_message>> out_msgs_;
|
||||
|
||||
raw_transaction();
|
||||
|
||||
raw_transaction(std::int64_t utime_, std::string const &data_, object_ptr<internal_transactionId> &&transaction_id_, std::int64_t fee_, object_ptr<raw_message> &&in_msg_, std::vector<object_ptr<raw_message>> &&out_msgs_);
|
||||
raw_transaction(std::int64_t utime_, std::string const &data_, object_ptr<internal_transactionId> &&transaction_id_, std::int64_t fee_, std::int64_t storage_fee_, std::int64_t other_fee_, object_ptr<raw_message> &&in_msg_, std::vector<object_ptr<raw_message>> &&out_msgs_);
|
||||
|
||||
static const std::int32_t ID = -1159530820;
|
||||
static const std::int32_t ID = 1887601793;
|
||||
std::int32_t get_id() const final {
|
||||
return ID;
|
||||
}
|
||||
@ -612,7 +654,7 @@ class raw_transactions final : public Object {
|
||||
|
||||
raw_transactions(std::vector<object_ptr<raw_transaction>> &&transactions_, object_ptr<internal_transactionId> &&previous_transaction_id_);
|
||||
|
||||
static const std::int32_t ID = 240548986;
|
||||
static const std::int32_t ID = -2063931155;
|
||||
std::int32_t get_id() const final {
|
||||
return ID;
|
||||
}
|
||||
@ -800,6 +842,21 @@ class createNewKey final : public Function {
|
||||
void store(td::TlStorerToString &s, const char *field_name) const final;
|
||||
};
|
||||
|
||||
class deleteAllKeys final : public Function {
|
||||
public:
|
||||
|
||||
deleteAllKeys();
|
||||
|
||||
static const std::int32_t ID = 1608776483;
|
||||
std::int32_t get_id() const final {
|
||||
return ID;
|
||||
}
|
||||
|
||||
using ReturnType = object_ptr<ok>;
|
||||
|
||||
void store(td::TlStorerToString &s, const char *field_name) const final;
|
||||
};
|
||||
|
||||
class deleteKey final : public Function {
|
||||
public:
|
||||
object_ptr<key> key_;
|
||||
|
@ -41,6 +41,12 @@ bool downcast_call(Object &obj, const T &func) {
|
||||
case key::ID:
|
||||
func(static_cast<key &>(obj));
|
||||
return true;
|
||||
case keyStoreTypeDirectory::ID:
|
||||
func(static_cast<keyStoreTypeDirectory &>(obj));
|
||||
return true;
|
||||
case keyStoreTypeInMemory::ID:
|
||||
func(static_cast<keyStoreTypeInMemory &>(obj));
|
||||
return true;
|
||||
case logStreamDefault::ID:
|
||||
func(static_cast<logStreamDefault &>(obj));
|
||||
return true;
|
||||
@ -148,6 +154,9 @@ bool downcast_call(Function &obj, const T &func) {
|
||||
case createNewKey::ID:
|
||||
func(static_cast<createNewKey &>(obj));
|
||||
return true;
|
||||
case deleteAllKeys::ID:
|
||||
func(static_cast<deleteAllKeys &>(obj));
|
||||
return true;
|
||||
case deleteKey::ID:
|
||||
func(static_cast<deleteKey &>(obj));
|
||||
return true;
|
||||
@ -270,6 +279,26 @@ bool downcast_call(Function &obj, const T &func) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls specified function object with the specified object downcasted to the most-derived type.
|
||||
* \param[in] obj Object to pass as an argument to the function object.
|
||||
* \param[in] func Function object to which the object will be passed.
|
||||
* \returns whether function object call has happened. Should always return true for correct parameters.
|
||||
*/
|
||||
template <class T>
|
||||
bool downcast_call(KeyStoreType &obj, const T &func) {
|
||||
switch (obj.get_id()) {
|
||||
case keyStoreTypeDirectory::ID:
|
||||
func(static_cast<keyStoreTypeDirectory &>(obj));
|
||||
return true;
|
||||
case keyStoreTypeInMemory::ID:
|
||||
func(static_cast<keyStoreTypeInMemory &>(obj));
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls specified function object with the specified object downcasted to the most-derived type.
|
||||
* \param[in] obj Object to pass as an argument to the function object.
|
||||
|
@ -14,6 +14,17 @@
|
||||
namespace ton {
|
||||
namespace tonlib_api{
|
||||
using namespace td;
|
||||
Result<int32> tl_constructor_from_string(tonlib_api::KeyStoreType *object, const std::string &str) {
|
||||
static const std::unordered_map<Slice, int32, SliceHash> m = {
|
||||
{"keyStoreTypeDirectory", -378990038},
|
||||
{"keyStoreTypeInMemory", -2106848825}
|
||||
};
|
||||
auto it = m.find(str);
|
||||
if (it == m.end()) {
|
||||
return Status::Error(str + "Unknown class");
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
Result<int32> tl_constructor_from_string(tonlib_api::LogStream *object, const std::string &str) {
|
||||
static const std::unordered_map<Slice, int32, SliceHash> m = {
|
||||
{"logStreamDefault", 1390581436},
|
||||
@ -51,14 +62,16 @@ Result<int32> tl_constructor_from_string(tonlib_api::Object *object, const std::
|
||||
{"exportedPemKey", 1425473725},
|
||||
{"inputKey", 869287093},
|
||||
{"key", -1978362923},
|
||||
{"keyStoreTypeDirectory", -378990038},
|
||||
{"keyStoreTypeInMemory", -2106848825},
|
||||
{"logStreamDefault", 1390581436},
|
||||
{"logStreamFile", -1880085930},
|
||||
{"logStreamEmpty", -499912244},
|
||||
{"logTags", -1604930601},
|
||||
{"logVerbosityLevel", 1734624234},
|
||||
{"ok", -722616727},
|
||||
{"options", 789823302},
|
||||
{"sendGramsResult", -858318471},
|
||||
{"options", -1924388359},
|
||||
{"sendGramsResult", 426872238},
|
||||
{"unpackedAccountAddress", 1892946998},
|
||||
{"updateSendLiteServerQuery", -1555130916},
|
||||
{"generic.accountStateRaw", -1387096685},
|
||||
@ -69,9 +82,9 @@ Result<int32> tl_constructor_from_string(tonlib_api::Object *object, const std::
|
||||
{"internal.transactionId", -989527262},
|
||||
{"raw.accountState", 461615898},
|
||||
{"raw.initialAccountState", 777456197},
|
||||
{"raw.message", -259956097},
|
||||
{"raw.transaction", -1159530820},
|
||||
{"raw.transactions", 240548986},
|
||||
{"raw.message", -906281442},
|
||||
{"raw.transaction", 1887601793},
|
||||
{"raw.transactions", -2063931155},
|
||||
{"testGiver.accountState", 860930426},
|
||||
{"testWallet.accountState", 305698744},
|
||||
{"testWallet.initialAccountState", -1231516227},
|
||||
@ -91,6 +104,7 @@ Result<int32> tl_constructor_from_string(tonlib_api::Function *object, const std
|
||||
{"changeLocalPassword", -1685491421},
|
||||
{"close", -1187782273},
|
||||
{"createNewKey", -1861385712},
|
||||
{"deleteAllKeys", 1608776483},
|
||||
{"deleteKey", -1579595571},
|
||||
{"exportEncryptedKey", 155352861},
|
||||
{"exportKey", 399723440},
|
||||
@ -254,6 +268,18 @@ Status from_json(tonlib_api::key &to, JsonObject &from) {
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
Status from_json(tonlib_api::keyStoreTypeDirectory &to, JsonObject &from) {
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "directory", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json(to.directory_, value));
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
Status from_json(tonlib_api::keyStoreTypeInMemory &to, JsonObject &from) {
|
||||
return Status::OK();
|
||||
}
|
||||
Status from_json(tonlib_api::logStreamDefault &to, JsonObject &from) {
|
||||
return Status::OK();
|
||||
}
|
||||
@ -304,9 +330,9 @@ Status from_json(tonlib_api::options &to, JsonObject &from) {
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "keystore_directory", JsonValue::Type::Null, true));
|
||||
TRY_RESULT(value, get_json_object_field(from, "keystore_type", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json(to.keystore_directory_, value));
|
||||
TRY_STATUS(from_json(to.keystore_type_, value));
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
@ -318,6 +344,12 @@ Status from_json(tonlib_api::sendGramsResult &to, JsonObject &from) {
|
||||
TRY_STATUS(from_json(to.sent_until_, value));
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "body_hash", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json_bytes(to.body_hash_, value));
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
Status from_json(tonlib_api::unpackedAccountAddress &to, JsonObject &from) {
|
||||
@ -489,6 +521,30 @@ Status from_json(tonlib_api::raw_message &to, JsonObject &from) {
|
||||
TRY_STATUS(from_json(to.value_, value));
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "fwd_fee", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json(to.fwd_fee_, value));
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "ihr_fee", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json(to.ihr_fee_, value));
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "created_lt", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json(to.created_lt_, value));
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "body_hash", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json_bytes(to.body_hash_, value));
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "message", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
@ -522,6 +578,18 @@ Status from_json(tonlib_api::raw_transaction &to, JsonObject &from) {
|
||||
TRY_STATUS(from_json(to.fee_, value));
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "storage_fee", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json(to.storage_fee_, value));
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "other_fee", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
TRY_STATUS(from_json(to.other_fee_, value));
|
||||
}
|
||||
}
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "in_msg", JsonValue::Type::Null, true));
|
||||
if (value.type() != JsonValue::Type::Null) {
|
||||
@ -725,6 +793,9 @@ Status from_json(tonlib_api::createNewKey &to, JsonObject &from) {
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
Status from_json(tonlib_api::deleteAllKeys &to, JsonObject &from) {
|
||||
return Status::OK();
|
||||
}
|
||||
Status from_json(tonlib_api::deleteKey &to, JsonObject &from) {
|
||||
{
|
||||
TRY_RESULT(value, get_json_object_field(from, "key", JsonValue::Type::Null, true));
|
||||
@ -1291,6 +1362,18 @@ void to_json(JsonValueScope &jv, const tonlib_api::key &object) {
|
||||
jo << ctie("public_key", ToJson(object.public_key_));
|
||||
jo << ctie("secret", ToJson(JsonBytes{object.secret_}));
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::KeyStoreType &object) {
|
||||
tonlib_api::downcast_call(const_cast<tonlib_api::KeyStoreType &>(object), [&jv](const auto &object) { to_json(jv, object); });
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::keyStoreTypeDirectory &object) {
|
||||
auto jo = jv.enter_object();
|
||||
jo << ctie("@type", "keyStoreTypeDirectory");
|
||||
jo << ctie("directory", ToJson(object.directory_));
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::keyStoreTypeInMemory &object) {
|
||||
auto jo = jv.enter_object();
|
||||
jo << ctie("@type", "keyStoreTypeInMemory");
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::LogStream &object) {
|
||||
tonlib_api::downcast_call(const_cast<tonlib_api::LogStream &>(object), [&jv](const auto &object) { to_json(jv, object); });
|
||||
}
|
||||
@ -1328,12 +1411,15 @@ void to_json(JsonValueScope &jv, const tonlib_api::options &object) {
|
||||
if (object.config_) {
|
||||
jo << ctie("config", ToJson(object.config_));
|
||||
}
|
||||
jo << ctie("keystore_directory", ToJson(object.keystore_directory_));
|
||||
if (object.keystore_type_) {
|
||||
jo << ctie("keystore_type", ToJson(object.keystore_type_));
|
||||
}
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::sendGramsResult &object) {
|
||||
auto jo = jv.enter_object();
|
||||
jo << ctie("@type", "sendGramsResult");
|
||||
jo << ctie("sent_until", ToJson(object.sent_until_));
|
||||
jo << ctie("body_hash", ToJson(JsonBytes{object.body_hash_}));
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::unpackedAccountAddress &object) {
|
||||
auto jo = jv.enter_object();
|
||||
@ -1416,6 +1502,10 @@ void to_json(JsonValueScope &jv, const tonlib_api::raw_message &object) {
|
||||
jo << ctie("source", ToJson(object.source_));
|
||||
jo << ctie("destination", ToJson(object.destination_));
|
||||
jo << ctie("value", ToJson(JsonInt64{object.value_}));
|
||||
jo << ctie("fwd_fee", ToJson(JsonInt64{object.fwd_fee_}));
|
||||
jo << ctie("ihr_fee", ToJson(JsonInt64{object.ihr_fee_}));
|
||||
jo << ctie("created_lt", ToJson(JsonInt64{object.created_lt_}));
|
||||
jo << ctie("body_hash", ToJson(JsonBytes{object.body_hash_}));
|
||||
jo << ctie("message", ToJson(JsonBytes{object.message_}));
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::raw_transaction &object) {
|
||||
@ -1427,6 +1517,8 @@ void to_json(JsonValueScope &jv, const tonlib_api::raw_transaction &object) {
|
||||
jo << ctie("transaction_id", ToJson(object.transaction_id_));
|
||||
}
|
||||
jo << ctie("fee", ToJson(JsonInt64{object.fee_}));
|
||||
jo << ctie("storage_fee", ToJson(JsonInt64{object.storage_fee_}));
|
||||
jo << ctie("other_fee", ToJson(JsonInt64{object.other_fee_}));
|
||||
if (object.in_msg_) {
|
||||
jo << ctie("in_msg", ToJson(object.in_msg_));
|
||||
}
|
||||
@ -1514,6 +1606,10 @@ void to_json(JsonValueScope &jv, const tonlib_api::createNewKey &object) {
|
||||
jo << ctie("mnemonic_password", ToJson(JsonBytes{object.mnemonic_password_}));
|
||||
jo << ctie("random_extra_seed", ToJson(JsonBytes{object.random_extra_seed_}));
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::deleteAllKeys &object) {
|
||||
auto jo = jv.enter_object();
|
||||
jo << ctie("@type", "deleteAllKeys");
|
||||
}
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::deleteKey &object) {
|
||||
auto jo = jv.enter_object();
|
||||
jo << ctie("@type", "deleteKey");
|
||||
|
@ -11,6 +11,7 @@
|
||||
namespace ton {
|
||||
namespace tonlib_api{
|
||||
using namespace td;
|
||||
Result<int32> tl_constructor_from_string(tonlib_api::KeyStoreType *object, const std::string &str);
|
||||
Result<int32> tl_constructor_from_string(tonlib_api::LogStream *object, const std::string &str);
|
||||
Result<int32> tl_constructor_from_string(tonlib_api::generic_AccountState *object, const std::string &str);
|
||||
Result<int32> tl_constructor_from_string(tonlib_api::Object *object, const std::string &str);
|
||||
@ -24,6 +25,8 @@ Status from_json(tonlib_api::exportedKey &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::exportedPemKey &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::inputKey &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::key &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::keyStoreTypeDirectory &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::keyStoreTypeInMemory &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::logStreamDefault &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::logStreamFile &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::logStreamEmpty &to, JsonObject &from);
|
||||
@ -55,6 +58,7 @@ Status from_json(tonlib_api::addLogMessage &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::changeLocalPassword &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::close &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::createNewKey &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::deleteAllKeys &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::deleteKey &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::exportEncryptedKey &to, JsonObject &from);
|
||||
Status from_json(tonlib_api::exportKey &to, JsonObject &from);
|
||||
@ -103,6 +107,9 @@ void to_json(JsonValueScope &jv, const tonlib_api::exportedKey &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::exportedPemKey &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::inputKey &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::key &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::KeyStoreType &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::keyStoreTypeDirectory &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::keyStoreTypeInMemory &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::LogStream &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::logStreamDefault &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::logStreamFile &object);
|
||||
@ -136,6 +143,7 @@ void to_json(JsonValueScope &jv, const tonlib_api::addLogMessage &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::changeLocalPassword &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::close &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::createNewKey &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::deleteAllKeys &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::deleteKey &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::exportEncryptedKey &object);
|
||||
void to_json(JsonValueScope &jv, const tonlib_api::exportKey &object);
|
||||
|
@ -444,12 +444,14 @@ db.state.initBlockId block:tonNode.blockIdExt = db.state.InitBlockId;
|
||||
db.state.gcBlockId block:tonNode.blockIdExt = db.state.GcBlockId;
|
||||
db.state.shardClient block:tonNode.blockIdExt = db.state.ShardClient;
|
||||
db.state.asyncSerializer block:tonNode.blockIdExt last:tonNode.blockIdExt last_ts:int = db.state.AsyncSerializer;
|
||||
db.state.hardforks blocks:(vector tonNode.blockIdExt) = db.state.Hardforks;
|
||||
|
||||
db.state.key.destroyedSessions = db.state.Key;
|
||||
db.state.key.initBlockId = db.state.Key;
|
||||
db.state.key.gcBlockId = db.state.Key;
|
||||
db.state.key.shardClient = db.state.Key;
|
||||
db.state.key.asyncSerializer = db.state.Key;
|
||||
db.state.key.hardforks = db.state.Key;
|
||||
|
||||
db.lt.el.key workchain:int shard:long idx:int = db.lt.Key;
|
||||
db.lt.desc.key workchain:int shard:long = db.lt.Key;
|
||||
@ -466,6 +468,7 @@ db.lt.status.value total_shards:int = db.lt.status.Value;
|
||||
|
||||
validator.groupMember public_key_hash:int256 adnl:int256 weight:long = engine.validator.GroupMember;
|
||||
validator.group workchain:int shard:long catchain_seqno:int config_hash:int256 members:(vector validator.groupMember) = validator.Group;
|
||||
validator.groupEx workchain:int shard:long vertical_seqno:int catchain_seqno:int config_hash:int256 members:(vector validator.groupMember) = validator.Group;
|
||||
|
||||
---functions---
|
||||
|
||||
|
Binary file not shown.
@ -16,8 +16,12 @@ vector {t:Type} # [ t ] = Vector t;
|
||||
error code:int32 message:string = Error;
|
||||
ok = Ok;
|
||||
|
||||
keyStoreTypeDirectory directory:string = KeyStoreType;
|
||||
keyStoreTypeInMemory = KeyStoreType;
|
||||
|
||||
config config:string blockchain_name:string use_callbacks_for_network:Bool ignore_cache:Bool = Config;
|
||||
options config:config keystore_directory:string = Options;
|
||||
|
||||
options config:config keystore_type:KeyStoreType = Options;
|
||||
|
||||
key public_key:string secret:secureBytes = Key;
|
||||
inputKey key:key local_password:secureBytes = InputKey;
|
||||
@ -35,9 +39,9 @@ internal.transactionId lt:int64 hash:bytes = internal.TransactionId;
|
||||
|
||||
raw.initialAccountState code:bytes data:bytes = raw.InitialAccountState;
|
||||
raw.accountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId sync_utime:int53 = raw.AccountState;
|
||||
raw.message source:string destination:string value:int64 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.transactions transactions:vector<raw.Transaction> previous_transaction_id:internal.transactionId = raw.Transactions;
|
||||
raw.message source:string destination:string value:int64 fwd_fee:int64 ihr_fee:int64 created_lt:int64 body_hash:bytes message:bytes = raw.Message;
|
||||
raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 storage_fee:int64 other_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;
|
||||
|
||||
testWallet.initialAccountState public_key:string = testWallet.InitialAccountState;
|
||||
testWallet.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId sync_utime:int53 = testWallet.AccountState;
|
||||
@ -59,7 +63,7 @@ generic.accountStateWallet account_state:wallet.accountState = generic.AccountSt
|
||||
generic.accountStateTestGiver account_state:testGiver.accountState = generic.AccountState;
|
||||
generic.accountStateUninited account_state:uninited.accountState = generic.AccountState;
|
||||
|
||||
sendGramsResult sent_until:int53 = SendGramsResult;
|
||||
sendGramsResult sent_until:int53 body_hash:bytes = SendGramsResult;
|
||||
|
||||
updateSendLiteServerQuery id:int64 data:bytes = Update;
|
||||
|
||||
@ -90,6 +94,7 @@ options.setConfig config:config = Ok;
|
||||
|
||||
createNewKey local_password:secureBytes mnemonic_password:secureBytes random_extra_seed:secureBytes = Key;
|
||||
deleteKey key:key = Ok;
|
||||
deleteAllKeys = Ok;
|
||||
exportKey input_key:inputKey = ExportedKey;
|
||||
exportPemKey input_key:inputKey key_password:secureBytes = ExportedPemKey;
|
||||
exportEncryptedKey input_key:inputKey key_password:secureBytes = ExportedEncryptedKey;
|
||||
|
Binary file not shown.
@ -5,6 +5,7 @@ if (NOT OPENSSL_FOUND)
|
||||
endif()
|
||||
|
||||
set(TONLIB_SOURCE
|
||||
tonlib/CellString.cpp
|
||||
tonlib/Client.cpp
|
||||
tonlib/Config.cpp
|
||||
tonlib/ExtClient.cpp
|
||||
@ -12,6 +13,7 @@ set(TONLIB_SOURCE
|
||||
tonlib/ExtClientOutbound.cpp
|
||||
tonlib/GenericAccount.cpp
|
||||
tonlib/KeyStorage.cpp
|
||||
tonlib/KeyValue.cpp
|
||||
tonlib/LastBlock.cpp
|
||||
tonlib/LastBlockStorage.cpp
|
||||
tonlib/Logging.cpp
|
||||
@ -21,6 +23,7 @@ set(TONLIB_SOURCE
|
||||
tonlib/utils.cpp
|
||||
tonlib/Wallet.cpp
|
||||
|
||||
tonlib/CellString.h
|
||||
tonlib/Client.h
|
||||
tonlib/Config.h
|
||||
tonlib/ExtClient.h
|
||||
@ -28,6 +31,7 @@ set(TONLIB_SOURCE
|
||||
tonlib/ExtClientOutbound.h
|
||||
tonlib/GenericAccount.h
|
||||
tonlib/KeyStorage.h
|
||||
tonlib/KeyValue.h
|
||||
tonlib/LastBlock.h
|
||||
tonlib/LastBlockStorage.h
|
||||
tonlib/Logging.h
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "vm/boc.h"
|
||||
#include "vm/cells/MerkleProof.h"
|
||||
|
||||
#include "tonlib/CellString.h"
|
||||
#include "tonlib/utils.h"
|
||||
#include "tonlib/TestGiver.h"
|
||||
#include "tonlib/TestWallet.h"
|
||||
@ -53,6 +54,20 @@
|
||||
#include "tonlib/keys/Mnemonic.h"
|
||||
#include "tonlib/keys/SimpleEncryption.h"
|
||||
|
||||
TEST(Tonlib, CellString) {
|
||||
for (unsigned size :
|
||||
{0, 1, 7, 8, 35, 127, 128, 255, 256, (int)vm::CellString::max_bytes - 1, (int)vm::CellString::max_bytes}) {
|
||||
auto str = td::rand_string('a', 'z', size);
|
||||
for (unsigned head : {0, 1, 7, 8, 127, 35 * 8, 127 * 8, 1023, 1024}) {
|
||||
vm::CellBuilder cb;
|
||||
vm::CellString::store(cb, str, head).ensure();
|
||||
auto cs = vm::load_cell_slice(cb.finalize());
|
||||
auto got_str = vm::CellString::load(cs, head).move_as_ok();
|
||||
ASSERT_EQ(str, got_str);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using namespace tonlib;
|
||||
|
||||
std::string current_dir() {
|
||||
@ -268,20 +283,23 @@ static auto sync_send = [](auto &client, auto query) {
|
||||
TEST(Tonlib, InitClose) {
|
||||
using tonlib_api::make_object;
|
||||
auto cfg = [](auto str) { return make_object<tonlib_api::config>(str, "", false, false); };
|
||||
auto dir = [](auto str) { return make_object<tonlib_api::keyStoreTypeDirectory>(str); };
|
||||
{
|
||||
Client client;
|
||||
sync_send(client, make_object<tonlib_api::close>()).ensure();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(nullptr, "."))).ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(nullptr, dir("."))))
|
||||
.ensure_error();
|
||||
}
|
||||
{
|
||||
Client client;
|
||||
sync_send(client, make_object<tonlib_api::init>(nullptr)).ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(cfg("fdajkfldsjkafld"), ".")))
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(cfg("fdajkfldsjkafld"), dir("."))))
|
||||
.ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(nullptr, "fdhskfds")))
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(nullptr, dir("fdhskfds"))))
|
||||
.ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(nullptr, dir(".")))).ensure();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(nullptr, dir("."))))
|
||||
.ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(nullptr, "."))).ensure();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(nullptr, "."))).ensure_error();
|
||||
|
||||
td::Slice bad_config = R"abc(
|
||||
{
|
||||
@ -294,7 +312,8 @@ TEST(Tonlib, InitClose) {
|
||||
sync_send(client, make_object<tonlib_api::testGiver_getAccountState>()).ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::close>()).ensure();
|
||||
sync_send(client, make_object<tonlib_api::close>()).ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(nullptr, "."))).ensure_error();
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(nullptr, dir("."))))
|
||||
.ensure_error();
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,7 +408,9 @@ TEST(Tonlib, ParseAddres) {
|
||||
Client client;
|
||||
|
||||
// init
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(nullptr, "."))).ensure();
|
||||
sync_send(client, make_object<tonlib_api::init>(
|
||||
make_object<tonlib_api::options>(nullptr, make_object<tonlib_api::keyStoreTypeDirectory>("."))))
|
||||
.ensure();
|
||||
|
||||
sync_send(client, make_object<tonlib_api::unpackAccountAddress>("hello")).ensure_error();
|
||||
auto addr =
|
||||
@ -409,7 +430,9 @@ TEST(Tonlib, KeysApi) {
|
||||
Client client;
|
||||
|
||||
// init
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(nullptr, "."))).ensure();
|
||||
sync_send(client, make_object<tonlib_api::init>(
|
||||
make_object<tonlib_api::options>(nullptr, make_object<tonlib_api::keyStoreTypeDirectory>("."))))
|
||||
.ensure();
|
||||
auto local_password = td::SecureString("local password");
|
||||
auto mnemonic_password = td::SecureString("mnemonic password");
|
||||
{
|
||||
|
@ -197,7 +197,8 @@ int main(int argc, char* argv[]) {
|
||||
Client client;
|
||||
{
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(
|
||||
make_object<tonlib_api::config>(global_config_str, "", false, false), ".")))
|
||||
make_object<tonlib_api::config>(global_config_str, "", false, false),
|
||||
make_object<tonlib_api::keyStoreTypeDirectory>("."))))
|
||||
.ensure();
|
||||
}
|
||||
//dump_transaction_history(client, get_test_giver_address(client));
|
||||
@ -211,7 +212,8 @@ int main(int argc, char* argv[]) {
|
||||
{
|
||||
// init
|
||||
sync_send(client, make_object<tonlib_api::init>(make_object<tonlib_api::options>(
|
||||
make_object<tonlib_api::config>(global_config_str, "", false, false), ".")))
|
||||
make_object<tonlib_api::config>(global_config_str, "", false, false),
|
||||
make_object<tonlib_api::keyStoreTypeDirectory>("."))))
|
||||
.ensure();
|
||||
|
||||
auto key = sync_send(client, make_object<tonlib_api::createNewKey>(
|
||||
|
Binary file not shown.
BIN
submodules/ton/tonlib-src/tonlib/tonlib/.TonlibError.h.swp
Normal file
BIN
submodules/ton/tonlib-src/tonlib/tonlib/.TonlibError.h.swp
Normal file
Binary file not shown.
Binary file not shown.
64
submodules/ton/tonlib-src/tonlib/tonlib/CellString.cpp
Normal file
64
submodules/ton/tonlib-src/tonlib/tonlib/CellString.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include "CellString.h"
|
||||
#include "td/utils/misc.h"
|
||||
|
||||
#include "vm/cells/CellSlice.h"
|
||||
|
||||
namespace vm {
|
||||
td::Status CellString::store(CellBuilder &cb, td::Slice slice, unsigned int top_bits) {
|
||||
td::uint32 size = td::narrow_cast<td::uint32>(slice.size() * 8);
|
||||
return store(cb, td::BitSlice(slice.ubegin(), size), top_bits);
|
||||
}
|
||||
|
||||
td::Status CellString::store(CellBuilder &cb, td::BitSlice slice, unsigned int top_bits) {
|
||||
if (slice.size() > max_bytes * 8) {
|
||||
return td::Status::Error("String is too long (1)");
|
||||
}
|
||||
unsigned int head = td::min(slice.size(), td::min(cb.remaining_bits(), top_bits)) / 8 * 8;
|
||||
auto max_bits = vm::Cell::max_bits / 8 * 8;
|
||||
auto depth = 1 + (slice.size() - head + max_bits - 1) / max_bits;
|
||||
if (depth > max_chain_length) {
|
||||
return td::Status::Error("String is too long (2)");
|
||||
}
|
||||
cb.append_bitslice(slice.subslice(0, head));
|
||||
slice.advance(head);
|
||||
if (slice.size() == 0) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
CellBuilder child_cb;
|
||||
store(child_cb, std::move(slice));
|
||||
cb.store_ref(child_cb.finalize());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void CellString::for_each(F &&f, CellSlice &cs, unsigned int top_bits) {
|
||||
unsigned int head = td::min(cs.size(), top_bits);
|
||||
f(cs.prefetch_bits(head));
|
||||
if (!cs.have_refs()) {
|
||||
return;
|
||||
}
|
||||
auto ref = cs.prefetch_ref();
|
||||
while (true) {
|
||||
auto cs = vm::load_cell_slice(ref);
|
||||
f(cs.prefetch_bits(cs.size()));
|
||||
if (!cs.have_refs()) {
|
||||
return;
|
||||
}
|
||||
ref = cs.prefetch_ref();
|
||||
}
|
||||
}
|
||||
|
||||
td::Result<td::string> CellString::load(CellSlice &cs, unsigned int top_bits) {
|
||||
unsigned int size = 0;
|
||||
for_each([&](auto slice) { size += slice.size(); }, cs, top_bits);
|
||||
if (size % 8 != 0) {
|
||||
return td::Status::Error("Size is not divisible by 8");
|
||||
}
|
||||
std::string res(size / 8, 0);
|
||||
|
||||
td::BitPtr to(td::MutableSlice(res).ubegin());
|
||||
for_each([&](auto slice) { to.concat(slice); }, cs, top_bits);
|
||||
CHECK(to.offs == (int)size);
|
||||
return res;
|
||||
}
|
||||
} // namespace vm
|
22
submodules/ton/tonlib-src/tonlib/tonlib/CellString.h
Normal file
22
submodules/ton/tonlib-src/tonlib/tonlib/CellString.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include "vm/cells/CellBuilder.h"
|
||||
|
||||
namespace vm {
|
||||
class CellString {
|
||||
public:
|
||||
static constexpr unsigned int max_bytes = 1024;
|
||||
static constexpr unsigned int max_chain_length = 16;
|
||||
|
||||
static td::Status store(CellBuilder &cb, td::Slice slice, unsigned int top_bits = Cell::max_bits);
|
||||
static td::Status store(CellBuilder &cb, td::BitSlice slice, unsigned int top_bits = Cell::max_bits);
|
||||
static td::Result<td::string> load(CellSlice &cs, unsigned int top_bits = Cell::max_bits);
|
||||
|
||||
private:
|
||||
template <class F>
|
||||
static void for_each(F &&f, CellSlice &cs, unsigned int top_bits = Cell::max_bits);
|
||||
};
|
||||
|
||||
} // namespace vm
|
@ -30,7 +30,7 @@ void ExtClient::with_last_block(td::Promise<LastBlockState> promise) {
|
||||
});
|
||||
};
|
||||
if (client_.last_block_actor_.empty()) {
|
||||
return P.set_error(td::Status::Error(500, "No lite clients"));
|
||||
return P.set_error(TonlibError::NoLiteServers());
|
||||
}
|
||||
td::actor::send_closure(client_.last_block_actor_, &LastBlock::get_last_block, std::move(P));
|
||||
}
|
||||
@ -44,7 +44,7 @@ void ExtClient::send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlic
|
||||
});
|
||||
};
|
||||
if (client_.andl_ext_client_.empty()) {
|
||||
return P.set_error(td::Status::Error(500, "No lite clients"));
|
||||
return P.set_error(TonlibError::NoLiteServers());
|
||||
}
|
||||
td::actor::send_closure(client_.andl_ext_client_, &ton::adnl::AdnlExtClient::send_query, "query", std::move(query),
|
||||
td::Timestamp::in(10.0), std::move(P));
|
||||
|
@ -26,6 +26,10 @@
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/utils/Container.h"
|
||||
#include "td/utils/Random.h"
|
||||
|
||||
#include "TonlibError.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace tonlib {
|
||||
class LastBlock;
|
||||
@ -55,21 +59,28 @@ class ExtClient {
|
||||
template <class QueryT>
|
||||
void send_query(QueryT query, td::Promise<typename QueryT::ReturnType> promise) {
|
||||
auto raw_query = ton::serialize_tl_object(&query, true);
|
||||
LOG(ERROR) << "send query to liteserver: " << to_string(query);
|
||||
td::uint32 tag = td::Random::fast_uint32();
|
||||
VLOG(lite_server) << "send query to liteserver: " << tag << " " << to_string(query);
|
||||
td::BufferSlice liteserver_query =
|
||||
ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(raw_query)), true);
|
||||
|
||||
send_raw_query(std::move(liteserver_query), [promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
||||
promise.set_result([&]() -> td::Result<typename QueryT::ReturnType> {
|
||||
TRY_RESULT(data, std::move(R));
|
||||
auto r_error = ton::fetch_tl_object<ton::lite_api::liteServer_error>(data.clone(), true);
|
||||
if (r_error.is_ok()) {
|
||||
auto f = r_error.move_as_ok();
|
||||
return td::Status::Error(f->code_, f->message_);
|
||||
}
|
||||
return ton::fetch_result<QueryT>(std::move(data));
|
||||
}());
|
||||
});
|
||||
send_raw_query(
|
||||
std::move(liteserver_query), [promise = std::move(promise), tag](td::Result<td::BufferSlice> R) mutable {
|
||||
auto res = [&]() -> td::Result<typename QueryT::ReturnType> {
|
||||
TRY_RESULT_PREFIX(data, std::move(R), TonlibError::LiteServerNetwork());
|
||||
auto r_error = ton::fetch_tl_object<ton::lite_api::liteServer_error>(data.clone(), true);
|
||||
if (r_error.is_ok()) {
|
||||
auto f = r_error.move_as_ok();
|
||||
return TonlibError::LiteServer(f->code_, f->message_);
|
||||
}
|
||||
return ton::fetch_result<QueryT>(std::move(data));
|
||||
}
|
||||
();
|
||||
VLOG_IF(lite_server, res.is_ok())
|
||||
<< "got result from liteserver: " << tag << " " << td::Slice(to_string(res.ok())).truncate(1 << 12);
|
||||
VLOG_IF(lite_server, res.is_error()) << "got error from liteserver: " << tag << " " << res.error();
|
||||
promise.set_result(std::move(res));
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -18,6 +18,7 @@
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "ExtClientOutbound.h"
|
||||
#include "TonlibError.h"
|
||||
#include <map>
|
||||
namespace tonlib {
|
||||
|
||||
@ -40,7 +41,7 @@ class ExtClientOutboundImp : public ExtClientOutbound {
|
||||
void on_query_result(td::int64 id, td::Result<td::BufferSlice> r_data, td::Promise<td::Unit> promise) override {
|
||||
auto it = queries_.find(id);
|
||||
if (it == queries_.end()) {
|
||||
promise.set_error(td::Status::Error(400, "Unknown query id"));
|
||||
promise.set_error(TonlibError::Internal("Unknown query id"));
|
||||
}
|
||||
it->second.set_result(std::move(r_data));
|
||||
queries_.erase(it);
|
||||
@ -54,7 +55,7 @@ class ExtClientOutboundImp : public ExtClientOutbound {
|
||||
|
||||
void tear_down() override {
|
||||
for (auto &it : queries_) {
|
||||
it.second.set_error(td::Status::Error(400, "Query cancelled"));
|
||||
it.second.set_error(TonlibError::Cancelled());
|
||||
}
|
||||
queries_.clear();
|
||||
}
|
||||
|
@ -20,18 +20,19 @@
|
||||
#include "tonlib/utils.h"
|
||||
#include "block/block-auto.h"
|
||||
namespace tonlib {
|
||||
td::Ref<vm::Cell> GenericAccount::get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data) {
|
||||
td::Ref<vm::Cell> GenericAccount::get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data) noexcept {
|
||||
return vm::CellBuilder()
|
||||
.append_cellslice(binary_bitstring_to_cellslice("b{00110}").move_as_ok())
|
||||
.store_ref(std::move(code))
|
||||
.store_ref(std::move(data))
|
||||
.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) noexcept {
|
||||
return block::StdAddress(workchain_id, init_state->get_hash().bits(), true /*bounce*/);
|
||||
}
|
||||
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) noexcept {
|
||||
block::gen::Message::Record message;
|
||||
/*info*/ {
|
||||
block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
|
||||
|
@ -22,9 +22,9 @@
|
||||
namespace tonlib {
|
||||
class GenericAccount {
|
||||
public:
|
||||
static td::Ref<vm::Cell> get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data);
|
||||
static block::StdAddress get_address(ton::WorkchainId workchain_id, const td::Ref<vm::Cell>& init_state);
|
||||
static td::Ref<vm::Cell> get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data) noexcept;
|
||||
static block::StdAddress get_address(ton::WorkchainId workchain_id, const td::Ref<vm::Cell>& init_state) noexcept;
|
||||
static td::Ref<vm::Cell> create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
||||
td::Ref<vm::Cell> body);
|
||||
td::Ref<vm::Cell> body) noexcept;
|
||||
};
|
||||
} // namespace tonlib
|
||||
|
@ -22,34 +22,26 @@
|
||||
#include "tonlib/keys/DecryptedKey.h"
|
||||
#include "tonlib/keys/EncryptedKey.h"
|
||||
|
||||
#include "tonlib/TonlibError.h"
|
||||
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/PathView.h"
|
||||
|
||||
namespace tonlib {
|
||||
namespace {
|
||||
std::string to_file_name_old(const KeyStorage::Key &key) {
|
||||
return td::buffer_to_hex(key.public_key);
|
||||
}
|
||||
|
||||
std::string KeyStorage::to_file_path_old(const Key &key) {
|
||||
return directory_ + TD_DIR_SLASH + to_file_name_old(key);
|
||||
}
|
||||
|
||||
std::string to_file_name(const KeyStorage::Key &key) {
|
||||
return td::buffer_to_hex(td::sha512(key.secret.as_slice()).substr(0, 32));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string KeyStorage::to_file_path(const Key &key) {
|
||||
return directory_ + TD_DIR_SLASH + to_file_name(key);
|
||||
}
|
||||
td::Status KeyStorage::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();
|
||||
void KeyStorage::set_key_value(std::shared_ptr<KeyValue> kv) {
|
||||
kv_ = std::move(kv);
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::Key> KeyStorage::save_key(const DecryptedKey &decrypted_key, td::Slice local_password) {
|
||||
@ -58,17 +50,7 @@ td::Result<KeyStorage::Key> KeyStorage::save_key(const DecryptedKey &decrypted_k
|
||||
Key res;
|
||||
res.public_key = encrypted_key.public_key.as_octet_string();
|
||||
res.secret = std::move(encrypted_key.secret);
|
||||
|
||||
auto size = encrypted_key.encrypted_data.size();
|
||||
|
||||
LOG(ERROR) << "SAVE " << to_file_name(res);
|
||||
TRY_RESULT(to_file, td::FileFd::open(to_file_path(res), td::FileFd::CreateNew | td::FileFd::Write));
|
||||
TRY_RESULT(written, to_file.write(encrypted_key.encrypted_data));
|
||||
if (written != static_cast<size_t>(size)) {
|
||||
return td::Status::Error(PSLICE() << "Failed to write file: written " << written << " bytes instead of " << size);
|
||||
}
|
||||
to_file.close();
|
||||
|
||||
TRY_STATUS_PREFIX(kv_->set(to_file_name(res), encrypted_key.encrypted_data), TonlibError::Internal());
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
@ -83,19 +65,22 @@ td::Result<KeyStorage::Key> KeyStorage::create_new_key(td::Slice local_password,
|
||||
}
|
||||
|
||||
td::Result<DecryptedKey> KeyStorage::export_decrypted_key(InputKey input_key) {
|
||||
auto r_encrypted_data = td::read_file_secure(to_file_path(input_key.key));
|
||||
auto r_encrypted_data = kv_->get(to_file_name(input_key.key));
|
||||
if (r_encrypted_data.is_error()) {
|
||||
r_encrypted_data = td::read_file_secure(to_file_path_old(input_key.key));
|
||||
r_encrypted_data = kv_->get(to_file_name_old(input_key.key));
|
||||
if (r_encrypted_data.is_ok()) {
|
||||
LOG(WARNING) << "Restore private from deprecated location " << to_file_path_old(input_key.key) << " --> "
|
||||
<< to_file_path(input_key.key);
|
||||
td::rename(to_file_path_old(input_key.key), to_file_path(input_key.key)).ignore();
|
||||
LOG(WARNING) << "Restore private from deprecated location " << to_file_name_old(input_key.key) << " --> "
|
||||
<< to_file_name(input_key.key);
|
||||
TRY_STATUS_PREFIX(kv_->set(to_file_name(input_key.key), r_encrypted_data.ok()), TonlibError::Internal());
|
||||
kv_->erase(to_file_name_old(input_key.key)).ignore();
|
||||
}
|
||||
}
|
||||
TRY_RESULT(encrypted_data, std::move(r_encrypted_data));
|
||||
TRY_RESULT_PREFIX(encrypted_data, std::move(r_encrypted_data), TonlibError::KeyUnknown());
|
||||
EncryptedKey encrypted_key{std::move(encrypted_data), td::Ed25519::PublicKey(std::move(input_key.key.public_key)),
|
||||
std::move(input_key.key.secret)};
|
||||
return encrypted_key.decrypt(std::move(input_key.local_password));
|
||||
TRY_RESULT_PREFIX(decrypted_key, encrypted_key.decrypt(std::move(input_key.local_password)),
|
||||
TonlibError::KeyDecrypt());
|
||||
return decrypted_key;
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::ExportedKey> KeyStorage::export_key(InputKey input_key) {
|
||||
@ -113,7 +98,26 @@ td::Result<KeyStorage::PrivateKey> KeyStorage::load_private_key(InputKey input_k
|
||||
}
|
||||
|
||||
td::Status KeyStorage::delete_key(const Key &key) {
|
||||
return td::unlink(to_file_path(key));
|
||||
LOG(WARNING) << "Delete private key stored at " << to_file_name(key);
|
||||
return kv_->erase(to_file_name(key));
|
||||
}
|
||||
|
||||
td::Status KeyStorage::delete_all_keys() {
|
||||
std::vector<std::string> keys;
|
||||
kv_->foreach_key([&](td::Slice key) {
|
||||
if (td::PathView(key).extension().empty()) {
|
||||
keys.push_back(key.str());
|
||||
}
|
||||
});
|
||||
td::Status status;
|
||||
for (auto key : keys) {
|
||||
LOG(WARNING) << "Delete private key stored at " << key;
|
||||
auto err = kv_->erase(key);
|
||||
if (err.is_error() && status.is_ok()) {
|
||||
status = std::move(err);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::Key> KeyStorage::import_key(td::Slice local_password, td::Slice mnemonic_password,
|
||||
@ -121,16 +125,16 @@ td::Result<KeyStorage::Key> KeyStorage::import_key(td::Slice local_password, td:
|
||||
TRY_RESULT(mnemonic, Mnemonic::create(std::move(exported_key.mnemonic_words), td::SecureString(mnemonic_password)));
|
||||
if (!mnemonic.is_basic_seed()) {
|
||||
if (mnemonic_password.empty() && mnemonic.is_password_seed()) {
|
||||
return td::Status::Error("Mnemonic password is expected");
|
||||
return TonlibError::NeedMnemonicPassword();
|
||||
}
|
||||
return td::Status::Error("Invalid mnemonic words or password (invalid checksum)");
|
||||
return TonlibError::InvalidMnemonic();
|
||||
}
|
||||
return save_key(DecryptedKey(std::move(mnemonic)), local_password);
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::ExportedPemKey> KeyStorage::export_pem_key(InputKey input_key, td::Slice key_password) {
|
||||
TRY_RESULT(decrypted_key, export_decrypted_key(std::move(input_key)));
|
||||
TRY_RESULT(pem, decrypted_key.private_key.as_pem(key_password));
|
||||
TRY_RESULT_PREFIX(pem, decrypted_key.private_key.as_pem(key_password), TonlibError::Internal());
|
||||
return ExportedPemKey{std::move(pem)};
|
||||
}
|
||||
|
||||
@ -140,13 +144,15 @@ td::Result<KeyStorage::Key> KeyStorage::change_local_password(InputKey input_key
|
||||
Key res;
|
||||
res.public_key = std::move(input_key.key.public_key);
|
||||
res.secret = std::move(new_secret);
|
||||
TRY_STATUS(td::copy_file(to_file_path(input_key.key), to_file_path(res)));
|
||||
TRY_RESULT_PREFIX(value, kv_->get(to_file_name(input_key.key)), TonlibError::KeyUnknown());
|
||||
TRY_STATUS_PREFIX(kv_->add(to_file_name(res), value), TonlibError::Internal());
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
td::Result<KeyStorage::Key> KeyStorage::import_pem_key(td::Slice local_password, td::Slice key_password,
|
||||
ExportedPemKey exported_key) {
|
||||
TRY_RESULT(key, td::Ed25519::PrivateKey::from_pem(exported_key.pem, key_password));
|
||||
TRY_RESULT_PREFIX(key, td::Ed25519::PrivateKey::from_pem(exported_key.pem, key_password),
|
||||
TonlibError::InvalidPemKey());
|
||||
return save_key(DecryptedKey({}, std::move(key)), local_password);
|
||||
}
|
||||
|
||||
@ -162,7 +168,7 @@ td::Result<KeyStorage::Key> KeyStorage::import_encrypted_key(td::Slice local_pas
|
||||
ExportedEncryptedKey exported_key) {
|
||||
EncryptedKey encrypted_key{std::move(exported_key.data), td::Ed25519::PublicKey(td::SecureString()),
|
||||
td::SecureString(dummy_secret)};
|
||||
TRY_RESULT(decrypted_key, encrypted_key.decrypt(key_password, false));
|
||||
TRY_RESULT_PREFIX(decrypted_key, encrypted_key.decrypt(key_password, false), TonlibError::KeyDecrypt());
|
||||
return save_key(std::move(decrypted_key), local_password);
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/SharedSlice.h"
|
||||
|
||||
#include "KeyValue.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace tonlib {
|
||||
@ -48,7 +50,7 @@ class KeyStorage {
|
||||
td::SecureString private_key;
|
||||
};
|
||||
|
||||
td::Status set_directory(std::string directory);
|
||||
void set_key_value(std::shared_ptr<KeyValue> kv);
|
||||
|
||||
td::Result<Key> create_new_key(td::Slice local_password, td::Slice key_password, td::Slice entropy);
|
||||
|
||||
@ -58,6 +60,7 @@ class KeyStorage {
|
||||
td::Result<Key> change_local_password(InputKey input_key, td::Slice new_local_password);
|
||||
|
||||
td::Status delete_key(const Key& key);
|
||||
td::Status delete_all_keys();
|
||||
|
||||
td::Result<Key> import_key(td::Slice local_password, td::Slice mnemonic_password, ExportedKey exported_key);
|
||||
td::Result<Key> import_pem_key(td::Slice local_password, td::Slice key_password, ExportedPemKey exported_key);
|
||||
@ -67,12 +70,9 @@ class KeyStorage {
|
||||
td::Result<PrivateKey> load_private_key(InputKey input_key);
|
||||
|
||||
private:
|
||||
std::string directory_;
|
||||
std::shared_ptr<KeyValue> kv_;
|
||||
|
||||
td::Result<Key> save_key(const DecryptedKey& mnemonic, td::Slice local_password);
|
||||
td::Result<DecryptedKey> export_decrypted_key(InputKey input_key);
|
||||
|
||||
std::string to_file_path(const Key& key);
|
||||
std::string to_file_path_old(const Key& key);
|
||||
};
|
||||
} // namespace tonlib
|
||||
|
124
submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.cpp
Normal file
124
submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
#include "KeyValue.h"
|
||||
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/port/path.h"
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
namespace tonlib {
|
||||
namespace detail {
|
||||
class KeyValueDir : public KeyValue {
|
||||
public:
|
||||
static td::Result<td::unique_ptr<KeyValueDir>> create(td::CSlice directory) {
|
||||
TRY_RESULT(path, td::realpath(directory));
|
||||
TRY_RESULT(stat, td::stat(path));
|
||||
if (!stat.is_dir_) {
|
||||
return td::Status::Error("not a directory");
|
||||
}
|
||||
return td::make_unique<KeyValueDir>(path);
|
||||
}
|
||||
|
||||
KeyValueDir(std::string directory) : directory_(std::move(directory)) {
|
||||
}
|
||||
|
||||
td::Status add(td::Slice key, td::Slice value) override {
|
||||
auto path = to_file_path(key.str());
|
||||
if (td::stat(path).is_ok()) {
|
||||
return td::Status::Error(PSLICE() << "File " << path << "already exists");
|
||||
}
|
||||
return td::atomic_write_file(path, value);
|
||||
}
|
||||
|
||||
td::Status set(td::Slice key, td::Slice value) override {
|
||||
return td::atomic_write_file(to_file_path(key.str()), value);
|
||||
}
|
||||
|
||||
td::Result<td::SecureString> get(td::Slice key) override {
|
||||
return td::read_file_secure(to_file_path(key.str()));
|
||||
}
|
||||
|
||||
td::Status erase(td::Slice key) override {
|
||||
return td::unlink(key.str());
|
||||
}
|
||||
|
||||
void foreach_key(std::function<void(td::Slice)> f) override {
|
||||
int cnt = 0;
|
||||
td::WalkPath::run(directory_, [&](td::Slice path, td::WalkPath::Type type) {
|
||||
cnt++;
|
||||
if (type == td::WalkPath::Type::EnterDir) {
|
||||
if (cnt != 1) {
|
||||
return td::WalkPath::Action::SkipDir;
|
||||
}
|
||||
} else if (type == td::WalkPath::Type::NotDir) {
|
||||
f(path);
|
||||
}
|
||||
|
||||
return td::WalkPath::Action::Continue;
|
||||
}).ignore();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string directory_;
|
||||
|
||||
std::string to_file_path(std::string key) {
|
||||
return directory_ + TD_DIR_SLASH + key;
|
||||
}
|
||||
};
|
||||
|
||||
class KeyValueInmemory : public KeyValue {
|
||||
public:
|
||||
td::Status add(td::Slice key, td::Slice value) override {
|
||||
auto res = map_.insert(std::make_pair(key.str(), td::SecureString(value)));
|
||||
if (!res.second) {
|
||||
return td::Status::Error(PSLICE() << "Add failed: value with key=`" << key << "` already exists");
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status set(td::Slice key, td::Slice value) override {
|
||||
map_[key.str()] = td::SecureString(value);
|
||||
return td::Status::OK();
|
||||
}
|
||||
td::Result<td::SecureString> get(td::Slice key) override {
|
||||
auto it = map_.find(key);
|
||||
if (it == map_.end()) {
|
||||
return td::Status::Error("Unknown key");
|
||||
}
|
||||
return it->second.copy();
|
||||
}
|
||||
static td::Result<td::unique_ptr<KeyValueInmemory>> create() {
|
||||
return td::make_unique<KeyValueInmemory>();
|
||||
}
|
||||
td::Status erase(td::Slice key) override {
|
||||
auto it = map_.find(key);
|
||||
if (it == map_.end()) {
|
||||
return td::Status::Error("Unknown key");
|
||||
}
|
||||
map_.erase(it);
|
||||
return td::Status::OK();
|
||||
}
|
||||
void foreach_key(std::function<void(td::Slice)> f) override {
|
||||
for (auto &it : map_) {
|
||||
f(it.first);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
class Cmp : public std::less<> {
|
||||
public:
|
||||
using is_transparent = void;
|
||||
};
|
||||
std::map<std::string, td::SecureString, Cmp> map_;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
td::Result<td::unique_ptr<KeyValue>> KeyValue::create_dir(td::CSlice dir) {
|
||||
TRY_RESULT(res, detail::KeyValueDir::create(dir.str()));
|
||||
return std::move(res);
|
||||
}
|
||||
td::Result<td::unique_ptr<KeyValue>> KeyValue::create_inmemory() {
|
||||
TRY_RESULT(res, detail::KeyValueInmemory::create());
|
||||
return std::move(res);
|
||||
}
|
||||
} // namespace tonlib
|
19
submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.h
Normal file
19
submodules/ton/tonlib-src/tonlib/tonlib/KeyValue.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "td/utils/SharedSlice.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
namespace tonlib {
|
||||
class KeyValue {
|
||||
public:
|
||||
virtual ~KeyValue() = default;
|
||||
virtual td::Status add(td::Slice key, td::Slice value) = 0;
|
||||
virtual td::Status set(td::Slice key, td::Slice value) = 0;
|
||||
virtual td::Status erase(td::Slice key) = 0;
|
||||
virtual td::Result<td::SecureString> get(td::Slice key) = 0;
|
||||
virtual void foreach_key(std::function<void(td::Slice)> f) = 0;
|
||||
|
||||
static td::Result<td::unique_ptr<KeyValue>> create_dir(td::CSlice dir);
|
||||
static td::Result<td::unique_ptr<KeyValue>> create_inmemory();
|
||||
};
|
||||
} // namespace tonlib
|
@ -18,12 +18,18 @@
|
||||
*/
|
||||
#include "tonlib/LastBlock.h"
|
||||
|
||||
#include "tonlib/utils.h"
|
||||
|
||||
#include "ton/lite-tl.hpp"
|
||||
|
||||
#include "lite-client/lite-client-common.h"
|
||||
|
||||
namespace tonlib {
|
||||
|
||||
// init_state <-> last_key_block
|
||||
// state.valitated_init_state
|
||||
// last_key_block ->
|
||||
//
|
||||
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);
|
||||
@ -32,9 +38,10 @@ td::StringBuilder& operator<<(td::StringBuilder& sb, const LastBlockState& state
|
||||
LastBlock::LastBlock(ExtClientRef client, LastBlockState state, Config config, td::unique_ptr<Callback> callback)
|
||||
: state_(std::move(state)), config_(std::move(config)), callback_(std::move(callback)) {
|
||||
client_.set_client(client);
|
||||
if (!config_.init_block_id.is_valid()) {
|
||||
check_init_block_state_ = QueryState::Done;
|
||||
}
|
||||
state_.last_block_id = state_.last_key_block_id;
|
||||
|
||||
VLOG(last_block) << "check_init_block: skip - FIXME before release";
|
||||
check_init_block_state_ = QueryState::Done;
|
||||
}
|
||||
|
||||
void LastBlock::get_last_block(td::Promise<LastBlockState> promise) {
|
||||
@ -42,9 +49,13 @@ void LastBlock::get_last_block(td::Promise<LastBlockState> promise) {
|
||||
promise.set_error(fatal_error_.clone());
|
||||
return;
|
||||
}
|
||||
|
||||
if (promises_.empty() && get_last_block_state_ == QueryState::Done) {
|
||||
VLOG(last_block) << "sync: start";
|
||||
VLOG(last_block) << "get_last_block: reset";
|
||||
get_last_block_state_ = QueryState::Empty;
|
||||
}
|
||||
|
||||
promises_.push_back(std::move(promise));
|
||||
sync_loop();
|
||||
}
|
||||
@ -54,36 +65,43 @@ void LastBlock::sync_loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
update_zero_state(state_.zero_state_id);
|
||||
update_zero_state(state_.zero_state_id, "cache");
|
||||
update_zero_state(ton::ZeroStateIdExt(config_.zero_state_id.id.workchain, config_.zero_state_id.root_hash,
|
||||
config_.zero_state_id.file_hash));
|
||||
config_.zero_state_id.file_hash),
|
||||
"config");
|
||||
|
||||
if (get_mc_info_state_ == QueryState::Empty) {
|
||||
VLOG(last_block) << "get_masterchain_info: start";
|
||||
get_mc_info_state_ = QueryState::Active;
|
||||
client_.send_query(ton::lite_api::liteServer_getMasterchainInfo(),
|
||||
[this](auto r_info) { this->on_masterchain_info(std::move(r_info)); });
|
||||
}
|
||||
|
||||
if (get_last_block_state_ == QueryState::Empty) {
|
||||
get_last_block_state_ = QueryState::Active;
|
||||
total_sync_ = td::Timer();
|
||||
validate_ = td::Timer(true);
|
||||
queries_ = 0;
|
||||
LOG(INFO) << "Begin last block synchronization " << state_;
|
||||
do_get_last_block();
|
||||
if (check_init_block_state_ == QueryState::Empty) {
|
||||
if (!config_.init_block_id.is_valid()) {
|
||||
check_init_block_state_ = QueryState::Done;
|
||||
VLOG(last_block) << "check_init_block: skip - no init_block in config";
|
||||
} else if (config_.init_block_id == state_.init_block_id) {
|
||||
check_init_block_state_ = QueryState::Done;
|
||||
VLOG(last_block) << "check_init_block: skip - was checked before";
|
||||
} else {
|
||||
check_init_block_state_ = QueryState::Active;
|
||||
check_init_block_stats_.start();
|
||||
if (state_.last_block_id.id.seqno >= config_.init_block_id.id.seqno) {
|
||||
VLOG(last_block) << "check_init_block: start - init_block -> last_block";
|
||||
do_check_init_block(config_.init_block_id, state_.last_key_block_id);
|
||||
} else {
|
||||
VLOG(last_block) << "check_init_block: start - last_block -> init_block";
|
||||
do_check_init_block(state_.last_key_block_id, config_.init_block_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (check_init_block_state_ == QueryState::Empty) {
|
||||
if (state_.last_block_id.id.seqno >= config_.init_block_id.id.seqno) {
|
||||
check_init_block_state_ = QueryState::Active;
|
||||
// validate
|
||||
//total_sync_ = td::Timer();
|
||||
//validate_ = td::Timer(true);
|
||||
//queries_ = 0;
|
||||
LOG(INFO) << "Begin last block synchronization (check init_block)" << state_;
|
||||
do_check_init_block(state_.last_key_block_id);
|
||||
} else {
|
||||
}
|
||||
if (get_last_block_state_ == QueryState::Empty && check_init_block_state_ == QueryState::Done) {
|
||||
VLOG(last_block) << "get_last_block: start";
|
||||
get_last_block_stats_.start();
|
||||
get_last_block_state_ = QueryState::Active;
|
||||
do_get_last_block();
|
||||
}
|
||||
|
||||
if (get_mc_info_state_ == QueryState::Done && get_last_block_state_ == QueryState::Done &&
|
||||
@ -94,7 +112,8 @@ void LastBlock::sync_loop() {
|
||||
|
||||
void LastBlock::do_get_last_block() {
|
||||
//liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof;
|
||||
queries_++;
|
||||
VLOG(last_block) << "get_last_block: continue " << state_.last_key_block_id.to_str() << " -> ?";
|
||||
get_last_block_stats_.queries_++;
|
||||
client_.send_query(
|
||||
ton::lite_api::liteServer_getBlockProof(0, create_tl_lite_block_id(state_.last_key_block_id), nullptr),
|
||||
[this, from = state_.last_key_block_id](auto r_block_proof) {
|
||||
@ -102,64 +121,69 @@ void LastBlock::do_get_last_block() {
|
||||
});
|
||||
}
|
||||
|
||||
void LastBlock::do_check_init_block(ton::BlockIdExt from) {
|
||||
void LastBlock::do_check_init_block(ton::BlockIdExt from, ton::BlockIdExt to) {
|
||||
VLOG(last_block) << "check_init_block: continue " << from.to_str() << " -> " << to.to_str();
|
||||
//liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof;
|
||||
//queries_++;
|
||||
client_.send_query(ton::lite_api::liteServer_getBlockProof(1, create_tl_lite_block_id(from),
|
||||
create_tl_lite_block_id(config_.init_block_id)),
|
||||
[this, from = state_.last_key_block_id](auto r_block_proof) {
|
||||
this->on_init_block_proof(from, std::move(r_block_proof));
|
||||
});
|
||||
check_init_block_stats_.queries_++;
|
||||
client_.send_query(
|
||||
ton::lite_api::liteServer_getBlockProof(1, create_tl_lite_block_id(from), create_tl_lite_block_id(to)),
|
||||
[this, from, to](auto r_block_proof) { this->on_init_block_proof(from, to, std::move(r_block_proof)); });
|
||||
}
|
||||
|
||||
td::Result<std::unique_ptr<block::BlockProofChain>> LastBlock::process_block_proof(
|
||||
ton::BlockIdExt from,
|
||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
||||
TRY_RESULT(block_proof, std::move(r_block_proof));
|
||||
LOG(DEBUG) << "Got proof FROM\n" << to_string(block_proof->from_) << "TO\n" << to_string(block_proof->to_);
|
||||
TRY_RESULT(block_proof, std::move(r_block_proof)); //TODO: it is fatal?
|
||||
TRY_RESULT_PREFIX(chain, TRY_VM(process_block_proof(from, std::move(block_proof))),
|
||||
TonlibError::ValidateBlockProof());
|
||||
return chain;
|
||||
}
|
||||
|
||||
td::Result<std::unique_ptr<block::BlockProofChain>> LastBlock::process_block_proof(
|
||||
ton::BlockIdExt from, ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof> block_proof) {
|
||||
VLOG(last_block) << "Got proof FROM\n" << to_string(block_proof->from_) << "TO\n" << to_string(block_proof->to_);
|
||||
TRY_RESULT(chain, liteclient::deserialize_proof_chain(std::move(block_proof)));
|
||||
if (chain->from != from) {
|
||||
return td::Status::Error(PSLICE() << "block proof chain starts from block " << chain->from.to_str()
|
||||
<< ", not from requested block " << from.to_str());
|
||||
}
|
||||
TRY_STATUS(chain->validate());
|
||||
return chain;
|
||||
}
|
||||
|
||||
void LastBlock::update_state(block::BlockProofChain& chain) {
|
||||
// Update state_
|
||||
bool is_changed = false;
|
||||
is_changed |= update_mc_last_block(chain->to);
|
||||
if (chain->has_key_block) {
|
||||
is_changed |= update_mc_last_key_block(chain->key_blkid);
|
||||
is_changed |= update_mc_last_block(chain.to);
|
||||
if (chain.has_key_block) {
|
||||
is_changed |= update_mc_last_key_block(chain.key_blkid);
|
||||
}
|
||||
if (chain->has_utime) {
|
||||
update_utime(chain->last_utime);
|
||||
if (chain.has_utime) {
|
||||
update_utime(chain.last_utime);
|
||||
}
|
||||
if (is_changed) {
|
||||
callback_->on_state_changed(state_);
|
||||
}
|
||||
return std::move(chain);
|
||||
}
|
||||
|
||||
void LastBlock::on_block_proof(
|
||||
ton::BlockIdExt from,
|
||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
||||
validate_.resume();
|
||||
get_last_block_stats_.validate_.resume();
|
||||
auto r_chain = process_block_proof(from, std::move(r_block_proof));
|
||||
validate_.pause();
|
||||
bool is_ready;
|
||||
get_last_block_stats_.validate_.pause();
|
||||
if (r_chain.is_error()) {
|
||||
LOG(WARNING) << "Error during last block synchronization " << r_chain.error();
|
||||
if (config_.init_block_id.is_valid()) {
|
||||
if (state_.last_key_block_id.id.seqno < config_.init_block_id.id.seqno) {
|
||||
on_sync_error(td::Status::Error(PSLICE() << "Sync failed and we can't validate config.init_block: "
|
||||
<< r_chain.move_as_error()));
|
||||
}
|
||||
}
|
||||
is_ready = true;
|
||||
} else {
|
||||
is_ready = r_chain.ok()->complete;
|
||||
get_last_block_state_ = QueryState::Empty;
|
||||
VLOG(last_block) << "get_last_block: error " << r_chain.error();
|
||||
on_sync_error(r_chain.move_as_error_suffix("(during last block synchronization)"));
|
||||
return;
|
||||
}
|
||||
if (is_ready) {
|
||||
LOG(INFO) << "End last block synchronization " << state_ << "\n"
|
||||
<< " net queries: " << queries_ << "\n"
|
||||
<< " total: " << total_sync_ << " validation: " << validate_;
|
||||
|
||||
auto chain = r_chain.move_as_ok();
|
||||
CHECK(chain);
|
||||
update_state(*chain);
|
||||
if (chain->complete) {
|
||||
VLOG(last_block) << "get_last_block: done\n" << get_last_block_stats_;
|
||||
get_last_block_state_ = QueryState::Done;
|
||||
sync_loop();
|
||||
} else {
|
||||
@ -168,26 +192,26 @@ void LastBlock::on_block_proof(
|
||||
}
|
||||
|
||||
void LastBlock::on_init_block_proof(
|
||||
ton::BlockIdExt from,
|
||||
ton::BlockIdExt from, ton::BlockIdExt to,
|
||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
||||
validate_.resume();
|
||||
check_init_block_stats_.validate_.resume();
|
||||
auto r_chain = process_block_proof(from, std::move(r_block_proof));
|
||||
validate_.pause();
|
||||
check_init_block_stats_.validate_.pause();
|
||||
if (r_chain.is_error()) {
|
||||
check_init_block_state_ = QueryState::Empty;
|
||||
on_sync_error(
|
||||
td::Status::Error(PSLICE() << "Error during last block synchronization (check init_block)" << r_chain.error()));
|
||||
VLOG(last_block) << "check_init_block: error " << r_chain.error();
|
||||
on_sync_error(r_chain.move_as_error_suffix("(during check init block)"));
|
||||
return;
|
||||
}
|
||||
auto chain = r_chain.move_as_ok();
|
||||
CHECK(chain);
|
||||
update_state(*chain);
|
||||
if (chain->complete) {
|
||||
LOG(INFO) << "End last block synchronization " << state_ << "\n"
|
||||
<< " net queries: " << queries_ << "\n"
|
||||
<< " total: " << total_sync_ << " validation: " << validate_;
|
||||
get_last_block_state_ = QueryState::Done;
|
||||
VLOG(last_block) << "check_init_block: done\n" << check_init_block_stats_;
|
||||
check_init_block_state_ = QueryState::Done;
|
||||
sync_loop();
|
||||
} else {
|
||||
do_check_init_block(chain->to);
|
||||
do_check_init_block(chain->to, to);
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,28 +219,30 @@ void LastBlock::on_masterchain_info(
|
||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_masterchainInfo>> r_info) {
|
||||
if (r_info.is_ok()) {
|
||||
auto info = r_info.move_as_ok();
|
||||
update_zero_state(create_zero_state_id(info->init_));
|
||||
update_mc_last_block(create_block_id(info->last_));
|
||||
update_zero_state(create_zero_state_id(info->init_), "masterchain info");
|
||||
// last block is not validated! Do not update it
|
||||
get_mc_info_state_ = QueryState::Done;
|
||||
VLOG(last_block) << "get_masterchain_info: done";
|
||||
} else {
|
||||
get_mc_info_state_ = QueryState::Empty;
|
||||
VLOG(last_block) << "get_masterchain_info: error " << r_info.error();
|
||||
LOG(WARNING) << "Failed liteServer_getMasterchainInfo " << r_info.error();
|
||||
on_sync_error(r_info.move_as_error());
|
||||
}
|
||||
sync_loop();
|
||||
}
|
||||
|
||||
void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id) {
|
||||
void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id, td::Slice source) {
|
||||
if (has_fatal_error()) {
|
||||
return;
|
||||
}
|
||||
if (!zero_state_id.is_valid()) {
|
||||
LOG(ERROR) << "Ignore invalid zero state update";
|
||||
LOG(ERROR) << "Ignore invalid zero state update from " << source;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state_.zero_state_id.is_valid()) {
|
||||
LOG(INFO) << "Init zerostate: " << zero_state_id.to_str();
|
||||
LOG(INFO) << "Init zerostate from " << source << ": " << zero_state_id.to_str();
|
||||
state_.zero_state_id = std::move(zero_state_id);
|
||||
return;
|
||||
}
|
||||
@ -225,8 +251,9 @@ void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
on_fatal_error(td::Status::Error(PSLICE() << "Masterchain zerostate mismatch: expected: "
|
||||
<< state_.zero_state_id.to_str() << ", found " << zero_state_id.to_str()));
|
||||
on_fatal_error(TonlibError::ValidateZeroState(PSLICE() << "Masterchain zerostate mismatch: expected: "
|
||||
<< state_.zero_state_id.to_str() << ", found "
|
||||
<< zero_state_id.to_str() << " from " << source));
|
||||
}
|
||||
|
||||
bool LastBlock::update_mc_last_block(ton::BlockIdExt mc_block_id) {
|
||||
@ -256,6 +283,9 @@ bool LastBlock::update_mc_last_key_block(ton::BlockIdExt mc_key_block_id) {
|
||||
if (!state_.last_key_block_id.is_valid() || state_.last_key_block_id.id.seqno < mc_key_block_id.id.seqno) {
|
||||
state_.last_key_block_id = mc_key_block_id;
|
||||
LOG(INFO) << "Update masterchain key block id: " << state_.last_key_block_id.to_str();
|
||||
//LOG(ERROR) << td::int64(state_.last_key_block_id.id.shard) << " "
|
||||
//<< td::base64_encode(state_.last_key_block_id.file_hash.as_slice()) << " "
|
||||
//<< td::base64_encode(state_.last_key_block_id.root_hash.as_slice());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -268,6 +298,7 @@ void LastBlock::update_utime(td::int64 utime) {
|
||||
}
|
||||
|
||||
void LastBlock::on_sync_ok() {
|
||||
VLOG(last_block) << "sync: ok " << state_;
|
||||
for (auto& promise : promises_) {
|
||||
auto state = state_;
|
||||
promise.set_value(std::move(state));
|
||||
@ -275,12 +306,14 @@ void LastBlock::on_sync_ok() {
|
||||
promises_.clear();
|
||||
}
|
||||
void LastBlock::on_sync_error(td::Status status) {
|
||||
VLOG(last_block) << "sync: error " << status;
|
||||
for (auto& promise : promises_) {
|
||||
promise.set_error(status.clone());
|
||||
}
|
||||
promises_.clear();
|
||||
}
|
||||
void LastBlock::on_fatal_error(td::Status status) {
|
||||
VLOG(last_block) << "sync: fatal error " << status;
|
||||
fatal_error_ = std::move(status);
|
||||
on_sync_error(fatal_error_.clone());
|
||||
}
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include "tonlib/Config.h"
|
||||
#include "tonlib/ExtClient.h"
|
||||
|
||||
#include "td/utils/tl_helpers.h"
|
||||
|
||||
namespace block {
|
||||
struct BlockProofChain;
|
||||
}
|
||||
@ -89,25 +91,44 @@ struct LastBlockState {
|
||||
ton::BlockIdExt last_key_block_id;
|
||||
ton::BlockIdExt last_block_id;
|
||||
td::int64 utime{0};
|
||||
ton::BlockIdExt init_block_id;
|
||||
|
||||
static constexpr td::int32 magic = 0xa7f171a4;
|
||||
enum Version { None = 0, Magic, InitBlock, Next };
|
||||
static constexpr td::int32 version = Version::Next - 1;
|
||||
|
||||
template <class StorerT>
|
||||
void store(StorerT &storer) const {
|
||||
using td::store;
|
||||
using tonlib::store;
|
||||
store(magic, storer);
|
||||
store(version, storer);
|
||||
|
||||
store(zero_state_id, storer);
|
||||
store(last_key_block_id, storer);
|
||||
store(last_block_id, storer);
|
||||
store(utime, storer);
|
||||
store(init_block_id, storer);
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void parse(ParserT &parser) {
|
||||
using td::parse;
|
||||
using tonlib::parse;
|
||||
td::int32 version = 0;
|
||||
if (parser.can_prefetch_int() && parser.prefetch_int_unsafe() == magic) {
|
||||
td::int32 magic;
|
||||
parse(magic, parser);
|
||||
parse(version, parser);
|
||||
}
|
||||
|
||||
parse(zero_state_id, parser);
|
||||
parse(last_key_block_id, parser);
|
||||
parse(last_block_id, parser);
|
||||
parse(utime, parser);
|
||||
if (version >= InitBlock) {
|
||||
parse(init_block_id, parser);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -132,20 +153,36 @@ class LastBlock : public td::actor::Actor {
|
||||
td::Status fatal_error_;
|
||||
|
||||
enum class QueryState { Empty, Active, Done };
|
||||
QueryState get_mc_info_state_{QueryState::Empty};
|
||||
QueryState get_last_block_state_{QueryState::Empty};
|
||||
QueryState check_init_block_state_{QueryState::Empty};
|
||||
QueryState get_mc_info_state_{QueryState::Empty}; // just to check zero state
|
||||
QueryState check_init_block_state_{QueryState::Empty}; // init_block <---> last_key_block (from older to newer)
|
||||
QueryState get_last_block_state_{QueryState::Empty}; // last_key_block_id --> ?
|
||||
|
||||
// stats
|
||||
td::Timer total_sync_;
|
||||
td::Timer validate_;
|
||||
td::uint32 queries_;
|
||||
struct Stats {
|
||||
td::Timer total_sync_;
|
||||
td::Timer validate_;
|
||||
td::uint32 queries_;
|
||||
|
||||
void start() {
|
||||
total_sync_ = td::Timer();
|
||||
validate_ = td::Timer(true);
|
||||
queries_ = 0;
|
||||
}
|
||||
|
||||
friend td::StringBuilder &operator<<(td::StringBuilder &sb, const Stats &stats) {
|
||||
return sb << " net queries: " << stats.queries_ << "\n"
|
||||
<< " total: " << stats.total_sync_ << " validation: " << stats.validate_;
|
||||
}
|
||||
};
|
||||
|
||||
Stats check_init_block_stats_;
|
||||
Stats get_last_block_stats_;
|
||||
|
||||
std::vector<td::Promise<LastBlockState>> promises_;
|
||||
|
||||
void do_check_init_block(ton::BlockIdExt from);
|
||||
void do_check_init_block(ton::BlockIdExt from, ton::BlockIdExt to);
|
||||
void on_init_block_proof(
|
||||
ton::BlockIdExt from,
|
||||
ton::BlockIdExt from, ton::BlockIdExt to,
|
||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof);
|
||||
void on_masterchain_info(td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_masterchainInfo>> r_info);
|
||||
void do_get_last_block();
|
||||
@ -155,7 +192,11 @@ class LastBlock : public td::actor::Actor {
|
||||
ton::BlockIdExt from,
|
||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof);
|
||||
|
||||
void update_zero_state(ton::ZeroStateIdExt zero_state_id);
|
||||
td::Result<std::unique_ptr<block::BlockProofChain>> process_block_proof(
|
||||
ton::BlockIdExt from, ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof> block_proof);
|
||||
|
||||
void update_state(block::BlockProofChain &chain);
|
||||
void update_zero_state(ton::ZeroStateIdExt zero_state_id, td::Slice source);
|
||||
|
||||
bool update_mc_last_block(ton::BlockIdExt mc_block_id);
|
||||
bool update_mc_last_key_block(ton::BlockIdExt mc_key_block_id);
|
||||
|
@ -18,6 +18,8 @@
|
||||
*/
|
||||
#include "LastBlockStorage.h"
|
||||
|
||||
#include "tonlib/utils.h"
|
||||
|
||||
#include "td/utils/as.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/port/path.h"
|
||||
@ -25,22 +27,18 @@
|
||||
|
||||
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();
|
||||
void LastBlockStorage::set_key_value(std::shared_ptr<KeyValue> kv) {
|
||||
kv_ = std::move(kv);
|
||||
}
|
||||
|
||||
std::string LastBlockStorage::get_file_name(td::Slice name) {
|
||||
return directory_ + TD_DIR_SLASH + td::buffer_to_hex(name) + ".blkstate";
|
||||
namespace {
|
||||
std::string get_file_name(td::Slice name) {
|
||||
return td::buffer_to_hex(name) + ".blkstate";
|
||||
}
|
||||
} // namespace
|
||||
|
||||
td::Result<LastBlockState> LastBlockStorage::get_state(td::Slice name) {
|
||||
TRY_RESULT(data, td::read_file(get_file_name(name)));
|
||||
TRY_RESULT(data, kv_->get(get_file_name(name)));
|
||||
if (data.size() < 8) {
|
||||
return td::Status::Error("too short");
|
||||
}
|
||||
@ -53,10 +51,11 @@ td::Result<LastBlockState> LastBlockStorage::get_state(td::Slice name) {
|
||||
}
|
||||
|
||||
void LastBlockStorage::save_state(td::Slice name, LastBlockState state) {
|
||||
VLOG(last_block) << "Save to cache: " << 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);
|
||||
kv_->set(get_file_name(name), y);
|
||||
}
|
||||
} // namespace tonlib
|
||||
|
@ -20,15 +20,16 @@
|
||||
|
||||
#include "tonlib/LastBlock.h"
|
||||
|
||||
#include "tonlib/KeyValue.h"
|
||||
|
||||
namespace tonlib {
|
||||
class LastBlockStorage {
|
||||
public:
|
||||
td::Status set_directory(std::string directory);
|
||||
void set_key_value(std::shared_ptr<KeyValue> kv);
|
||||
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);
|
||||
std::shared_ptr<KeyValue> kv_;
|
||||
};
|
||||
} // namespace tonlib
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user