mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Update tonlib
This commit is contained in:
parent
fb07f06a26
commit
69fb8c7603
@ -757,15 +757,28 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
|> deliverOnMainQueue).start(next: { records, publicKey in
|
||||
if let record = records.first {
|
||||
if let publicKey = publicKey {
|
||||
if record.info.encryptedSecret.publicKey == publicKey {
|
||||
if record.exportCompleted {
|
||||
let _ = (walletAddress(publicKey: record.info.publicKey, tonInstance: walletContext.tonInstance)
|
||||
let recordPublicKey: Data
|
||||
switch record.info {
|
||||
case let .ready(info, _, _):
|
||||
recordPublicKey = info.encryptedSecret.publicKey
|
||||
case let .imported(info):
|
||||
recordPublicKey = info.encryptedSecret.publicKey
|
||||
}
|
||||
if recordPublicKey == publicKey {
|
||||
switch record.info {
|
||||
case let .ready(info, exportCompleted, _):
|
||||
if exportCompleted {
|
||||
let _ = (walletAddress(walletInfo: info, tonInstance: walletContext.tonInstance)
|
||||
|> deliverOnMainQueue).start(next: { address in
|
||||
let infoScreen = WalletInfoScreen(context: walletContext, walletInfo: record.info, address: address, enableDebugActions: false)
|
||||
let infoScreen = WalletInfoScreen(context: walletContext, walletInfo: info, address: address, enableDebugActions: false)
|
||||
beginWithController(infoScreen)
|
||||
})
|
||||
} else {
|
||||
let createdScreen = WalletSplashScreen(context: walletContext, mode: .created(walletInfo: record.info, words: nil), walletCreatedPreloadState: nil)
|
||||
let createdScreen = WalletSplashScreen(context: walletContext, mode: .created(walletInfo: info, words: nil), walletCreatedPreloadState: nil)
|
||||
beginWithController(createdScreen)
|
||||
}
|
||||
case let .imported(info):
|
||||
let createdScreen = WalletSplashScreen(context: walletContext, mode: .successfullyImported(importedInfo: info), walletCreatedPreloadState: nil)
|
||||
beginWithController(createdScreen)
|
||||
}
|
||||
} else {
|
||||
|
@ -1004,6 +1004,8 @@ public func channelAdminController(context: AccountContext, peerId: PeerId, admi
|
||||
if let peer = adminView.peers[adminView.peerId] {
|
||||
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(peer.compactDisplayTitle, peer.compactDisplayTitle).0
|
||||
}
|
||||
case .notMutualContact:
|
||||
text = presentationData.strings.GroupInfo_AddUserLeftError
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -396,6 +396,8 @@ public func channelMembersController(context: AccountContext, peerId: PeerId) ->
|
||||
text = presentationData.strings.Login_UnknownError
|
||||
case .restricted:
|
||||
text = presentationData.strings.Channel_ErrorAddBlocked
|
||||
case .notMutualContact:
|
||||
text = presentationData.strings.GroupInfo_AddUserLeftError
|
||||
case let .bot(memberId):
|
||||
let _ = (context.account.postbox.transaction { transaction in
|
||||
return transaction.getPeer(peerId)
|
||||
|
@ -1750,7 +1750,7 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId:
|
||||
return state.withUpdatedTemporaryParticipants(temporaryParticipants).withUpdatedSuccessfullyAddedParticipantIds(successfullyAddedParticipantIds)
|
||||
}
|
||||
return .complete()
|
||||
case .privacy:
|
||||
case .privacy, .notMutualContact:
|
||||
let _ = (context.account.postbox.loadedPeerWithId(memberId)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(peer.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
|
@ -10,6 +10,7 @@ public enum AddGroupMemberError {
|
||||
case generic
|
||||
case groupFull
|
||||
case privacy
|
||||
case notMutualContact
|
||||
case tooManyChannels
|
||||
}
|
||||
|
||||
@ -26,6 +27,8 @@ public func addGroupMember(account: Account, peerId: PeerId, memberId: PeerId) -
|
||||
return .privacy
|
||||
case "USER_CHANNELS_TOO_MUCH":
|
||||
return .tooManyChannels
|
||||
case "USER_NOT_MUTUAL_CONTACT":
|
||||
return .notMutualContact
|
||||
default:
|
||||
return .generic
|
||||
}
|
||||
@ -68,6 +71,7 @@ public func addGroupMember(account: Account, peerId: PeerId, memberId: PeerId) -
|
||||
public enum AddChannelMemberError {
|
||||
case generic
|
||||
case restricted
|
||||
case notMutualContact
|
||||
case limitExceeded
|
||||
case tooMuchJoined
|
||||
case bot(PeerId)
|
||||
@ -98,8 +102,10 @@ public func addChannelMember(account: Account, peerId: PeerId, memberId: PeerId)
|
||||
return .fail(.tooMuchJoined)
|
||||
case "USERS_TOO_MUCH":
|
||||
return .fail(.limitExceeded)
|
||||
case "USER_PRIVACY_RESTRICTED", "USER_NOT_MUTUAL_CONTACT":
|
||||
case "USER_PRIVACY_RESTRICTED":
|
||||
return .fail(.restricted)
|
||||
case "USER_NOT_MUTUAL_CONTACT":
|
||||
return .fail(.notMutualContact)
|
||||
case "USER_BOT":
|
||||
return .fail(.bot(memberId))
|
||||
case "BOT_GROUPS_BLOCKED":
|
||||
@ -194,8 +200,10 @@ public func addChannelMembers(account: Account, peerId: PeerId, memberIds: [Peer
|
||||
switch error.errorDescription {
|
||||
case "CHANNELS_TOO_MUCH":
|
||||
return .tooMuchJoined
|
||||
case "USER_PRIVACY_RESTRICTED", "USER_NOT_MUTUAL_CONTACT":
|
||||
case "USER_PRIVACY_RESTRICTED":
|
||||
return .restricted
|
||||
case "USER_NOT_MUTUAL_CONTACT":
|
||||
return .notMutualContact
|
||||
case "USERS_TOO_MUCH":
|
||||
return .limitExceeded
|
||||
default:
|
||||
|
@ -3342,6 +3342,12 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(peer.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
})
|
||||
return .complete()
|
||||
case .notMutualContact:
|
||||
let _ = (context.account.postbox.loadedPeerWithId(memberId)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.GroupInfo_AddUserLeftError, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
})
|
||||
return .complete()
|
||||
case .tooManyChannels:
|
||||
let _ = (context.account.postbox.loadedPeerWithId(memberId)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
@ -3479,6 +3485,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
default:
|
||||
break
|
||||
}
|
||||
} else if peers.count == 1, case .notMutualContact = error {
|
||||
self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.GroupInfo_AddUserLeftError, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
} else if case .tooMuchJoined = error {
|
||||
self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.Invite_ChannelsTooMuch, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
|
@ -30,12 +30,15 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@interface TONAccountState : NSObject
|
||||
|
||||
@property (nonatomic, readonly) bool isInitialized;
|
||||
@property (nonatomic, readonly) bool isRWallet;
|
||||
@property (nonatomic, readonly) int64_t balance;
|
||||
@property (nonatomic, readonly) int64_t unlockedBalance;
|
||||
|
||||
@property (nonatomic, readonly) int32_t seqno;
|
||||
@property (nonatomic, strong, readonly) TONTransactionId * _Nullable lastTransactionId;
|
||||
@property (nonatomic, readonly) int64_t syncUtime;
|
||||
|
||||
- (instancetype)initWithIsInitialized:(bool)isInitialized balance:(int64_t)balance seqno:(int32_t)seqno lastTransactionId:(TONTransactionId * _Nullable)lastTransactionId syncUtime:(int64_t)syncUtime;
|
||||
- (instancetype)initWithIsInitialized:(bool)isInitialized isRWallet:(bool)isRWallet balance:(int64_t)balance unlockedBalance:(int64_t)unlockedBalance seqno:(int32_t)seqno lastTransactionId:(TONTransactionId * _Nullable)lastTransactionId syncUtime:(int64_t)syncUtime;
|
||||
|
||||
@end
|
||||
|
||||
@ -166,7 +169,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (SSignal *)validateConfig:(NSString *)config blockchainName:(NSString *)blockchainName;
|
||||
|
||||
- (SSignal *)createKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword;
|
||||
- (SSignal *)getWalletAccountAddressWithPublicKey:(NSString *)publicKey initialWalletId:(int64_t)initialWalletId;
|
||||
- (SSignal *)getWalletAccountAddressWithPublicKey:(NSString *)publicKey initialWalletId:(int64_t)initialWalletId rwalletInitialPublicKey:(NSString * _Nullable)rwalletInitialPublicKey;
|
||||
- (SSignal *)getAccountStateWithAddress:(NSString *)accountAddress;
|
||||
- (SSignal *)generateSendGramsQueryFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount comment:(NSData *)comment encryptComment:(bool)encryptComment forceIfDestinationNotInitialized:(bool)forceIfDestinationNotInitialized timeout:(int32_t)timeout randomId:(int64_t)randomId;
|
||||
- (SSignal *)generateFakeSendGramsQueryFromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount comment:(NSData *)comment encryptComment:(bool)encryptComment forceIfDestinationNotInitialized:(bool)forceIfDestinationNotInitialized timeout:(int32_t)timeout;
|
||||
|
@ -98,11 +98,13 @@ static TONTransactionMessage * _Nullable parseTransactionMessage(tonlib_api::obj
|
||||
|
||||
@implementation TONAccountState
|
||||
|
||||
- (instancetype)initWithIsInitialized:(bool)isInitialized balance:(int64_t)balance seqno:(int32_t)seqno lastTransactionId:(TONTransactionId * _Nullable)lastTransactionId syncUtime:(int64_t)syncUtime {
|
||||
- (instancetype)initWithIsInitialized:(bool)isInitialized isRWallet:(bool)isRWallet balance:(int64_t)balance unlockedBalance:(int64_t)unlockedBalance seqno:(int32_t)seqno lastTransactionId:(TONTransactionId * _Nullable)lastTransactionId syncUtime:(int64_t)syncUtime {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_isInitialized = isInitialized;
|
||||
_isRWallet = isRWallet;
|
||||
_balance = balance;
|
||||
_unlockedBalance = unlockedBalance;
|
||||
_seqno = seqno;
|
||||
_lastTransactionId = lastTransactionId;
|
||||
_syncUtime = syncUtime;
|
||||
@ -632,7 +634,7 @@ typedef enum {
|
||||
}] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
|
||||
}
|
||||
|
||||
- (SSignal *)getWalletAccountAddressWithPublicKey:(NSString *)publicKey initialWalletId:(int64_t)initialWalletId {
|
||||
- (SSignal *)getWalletAccountAddressWithPublicKey:(NSString *)publicKey initialWalletId:(int64_t)initialWalletId rwalletInitialPublicKey:(NSString * _Nullable)rwalletInitialPublicKey {
|
||||
return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
|
||||
NSData *publicKeyData = [publicKey dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if (publicKeyData == nil) {
|
||||
@ -640,6 +642,15 @@ typedef enum {
|
||||
return [[SBlockDisposable alloc] initWithBlock:^{}];
|
||||
}
|
||||
|
||||
NSData *rwalletInitialPublicKeyData = nil;
|
||||
if (rwalletInitialPublicKey != nil) {
|
||||
rwalletInitialPublicKeyData = [rwalletInitialPublicKey dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if (rwalletInitialPublicKeyData == nil) {
|
||||
[subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string for rwalletInitialPublicKey in getWalletAccountAddressWithPublicKey"]];
|
||||
return [[SBlockDisposable alloc] initWithBlock:^{}];
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t requestId = _nextRequestId;
|
||||
_nextRequestId += 1;
|
||||
|
||||
@ -656,14 +667,27 @@ typedef enum {
|
||||
}
|
||||
}];
|
||||
|
||||
auto initialAccountState = make_object<tonlib_api::wallet_v3_initialAccountState>(
|
||||
tonlib_api::object_ptr<tonlib_api::InitialAccountState> initialAccountState;
|
||||
|
||||
std::int32_t revision;
|
||||
if (rwalletInitialPublicKey != nil) {
|
||||
initialAccountState = make_object<tonlib_api::rwallet_initialAccountState>(
|
||||
makeString(rwalletInitialPublicKeyData),
|
||||
makeString(publicKeyData),
|
||||
initialWalletId
|
||||
);
|
||||
revision = -1;
|
||||
} else {
|
||||
initialAccountState = tonlib_api::move_object_as<tonlib_api::InitialAccountState>(make_object<tonlib_api::wallet_v3_initialAccountState>(
|
||||
makeString(publicKeyData),
|
||||
initialWalletId
|
||||
));
|
||||
revision = 1;
|
||||
}
|
||||
|
||||
auto query = make_object<tonlib_api::getAccountAddress>(
|
||||
tonlib_api::move_object_as<tonlib_api::InitialAccountState>(initialAccountState),
|
||||
1
|
||||
revision
|
||||
);
|
||||
_client->send({ requestId, std::move(query) });
|
||||
|
||||
@ -684,12 +708,21 @@ typedef enum {
|
||||
} else if (object->get_id() == tonlib_api::fullAccountState::ID) {
|
||||
auto fullAccountState = tonlib_api::move_object_as<tonlib_api::fullAccountState>(object);
|
||||
int32_t seqNo = -1;
|
||||
|
||||
bool isRWallet = false;
|
||||
int64_t unlockedBalance = INT64_MAX;
|
||||
|
||||
if (fullAccountState->account_state_->get_id() == tonlib_api::uninited_accountState::ID) {
|
||||
seqNo = -1;
|
||||
} else if (fullAccountState->account_state_->get_id() == tonlib_api::wallet_v3_accountState::ID) {
|
||||
auto v3AccountState = tonlib_api::move_object_as<tonlib_api::wallet_v3_accountState>(fullAccountState->account_state_);
|
||||
seqNo = v3AccountState->seqno_;
|
||||
} else {
|
||||
} else if (fullAccountState->account_state_->get_id() == tonlib_api::rwallet_accountState::ID) {
|
||||
auto rwalletAccountState = tonlib_api::move_object_as<tonlib_api::rwallet_accountState>(fullAccountState->account_state_);
|
||||
isRWallet = true;
|
||||
unlockedBalance = rwalletAccountState->unlocked_balance_;
|
||||
seqNo = rwalletAccountState->seqno_;
|
||||
}else {
|
||||
[subscriber putError:[[TONError alloc] initWithText:@"Unknown type"]];
|
||||
return;
|
||||
}
|
||||
@ -698,7 +731,7 @@ typedef enum {
|
||||
if (fullAccountState->last_transaction_id_ != nullptr) {
|
||||
lastTransactionId = [[TONTransactionId alloc] initWithLt:fullAccountState->last_transaction_id_->lt_ transactionHash:makeData(fullAccountState->last_transaction_id_->hash_)];
|
||||
}
|
||||
[subscriber putNext:[[TONAccountState alloc] initWithIsInitialized:false balance:fullAccountState->balance_ seqno:-1 lastTransactionId:lastTransactionId syncUtime:fullAccountState->sync_utime_]];
|
||||
[subscriber putNext:[[TONAccountState alloc] initWithIsInitialized:false isRWallet:isRWallet balance:fullAccountState->balance_ unlockedBalance:unlockedBalance seqno:-1 lastTransactionId:lastTransactionId syncUtime:fullAccountState->sync_utime_]];
|
||||
[subscriber putCompletion];
|
||||
} else {
|
||||
assert(false);
|
||||
@ -785,7 +818,8 @@ typedef enum {
|
||||
),
|
||||
make_object<tonlib_api::accountAddress>(fromAddress.UTF8String),
|
||||
timeout,
|
||||
tonlib_api::move_object_as<tonlib_api::Action>(inputAction)
|
||||
tonlib_api::move_object_as<tonlib_api::Action>(inputAction),
|
||||
nil
|
||||
);
|
||||
_client->send({ requestId, std::move(query) });
|
||||
|
||||
@ -840,7 +874,8 @@ typedef enum {
|
||||
make_object<tonlib_api::inputKeyFake>(),
|
||||
make_object<tonlib_api::accountAddress>(fromAddress.UTF8String),
|
||||
timeout,
|
||||
tonlib_api::move_object_as<tonlib_api::Action>(inputAction)
|
||||
tonlib_api::move_object_as<tonlib_api::Action>(inputAction),
|
||||
nil
|
||||
);
|
||||
_client->send({ requestId, std::move(query) });
|
||||
|
||||
|
@ -198,7 +198,7 @@ public final class TonInstance {
|
||||
}
|
||||
let _ = keychain.encrypt(key.secret).start(next: { encryptedSecretData in
|
||||
let _ = self.exportKey(key: key, localPassword: localPassword).start(next: { wordList in
|
||||
subscriber.putNext((WalletInfo(publicKey: WalletPublicKey(rawValue: key.publicKey), encryptedSecret: encryptedSecretData), wordList))
|
||||
subscriber.putNext((WalletInfo(publicKey: WalletPublicKey(rawValue: key.publicKey), rWalletInitialPublicKey: nil, encryptedSecret: encryptedSecretData), wordList))
|
||||
subscriber.putCompletion()
|
||||
}, error: { error in
|
||||
subscriber.putError(.generic)
|
||||
@ -220,7 +220,7 @@ public final class TonInstance {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func importWallet(keychain: TonKeychain, wordList: [String], localPassword: Data) -> Signal<WalletInfo, ImportWalletInternalError> {
|
||||
fileprivate func importWallet(keychain: TonKeychain, wordList: [String], localPassword: Data) -> Signal<ImportedWalletInfo, ImportWalletInternalError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
@ -232,7 +232,7 @@ public final class TonInstance {
|
||||
return
|
||||
}
|
||||
let _ = keychain.encrypt(key.secret).start(next: { encryptedSecretData in
|
||||
subscriber.putNext(WalletInfo(publicKey: WalletPublicKey(rawValue: key.publicKey), encryptedSecret: encryptedSecretData))
|
||||
subscriber.putNext(ImportedWalletInfo(publicKey: WalletPublicKey(rawValue: key.publicKey), encryptedSecret: encryptedSecretData))
|
||||
subscriber.putCompletion()
|
||||
}, error: { _ in
|
||||
subscriber.putError(.generic)
|
||||
@ -283,7 +283,7 @@ public final class TonInstance {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func walletAddress(publicKey: WalletPublicKey) -> Signal<String, NoError> {
|
||||
fileprivate func walletAddress(publicKey: WalletPublicKey, rwalletInitialPublicKey: WalletInitialPublicKey?) -> Signal<String, NoError> {
|
||||
return self.getInitialWalletId()
|
||||
|> `catch` { _ -> Signal<Int64, NoError> in
|
||||
return .single(0)
|
||||
@ -294,7 +294,7 @@ public final class TonInstance {
|
||||
|
||||
self.impl.with { impl in
|
||||
impl.withInstance { ton in
|
||||
let cancel = ton.getWalletAccountAddress(withPublicKey: publicKey.rawValue, initialWalletId: initialWalletId).start(next: { address in
|
||||
let cancel = ton.getWalletAccountAddress(withPublicKey: publicKey.rawValue, initialWalletId: initialWalletId, rwalletInitialPublicKey: rwalletInitialPublicKey?.rawValue).start(next: { address in
|
||||
guard let address = address as? String else {
|
||||
return
|
||||
}
|
||||
@ -353,7 +353,7 @@ public final class TonInstance {
|
||||
fileprivate func getWalletState(address: String) -> Signal<(WalletState, Int64), GetWalletStateError> {
|
||||
return self.getWalletStateRaw(address: address)
|
||||
|> map { state in
|
||||
return (WalletState(balance: state.balance, lastTransactionId: state.lastTransactionId.flatMap(WalletTransactionId.init(tonTransactionId:))), state.syncUtime)
|
||||
return (WalletState(totalBalance: state.balance, unlockedBalance: state.isRWallet ? state.unlockedBalance : nil, lastTransactionId: state.lastTransactionId.flatMap(WalletTransactionId.init(tonTransactionId:))), state.syncUtime)
|
||||
}
|
||||
}
|
||||
|
||||
@ -717,7 +717,27 @@ public struct WalletPublicKey: Codable, Hashable {
|
||||
}
|
||||
}
|
||||
|
||||
public struct WalletInitialPublicKey: Codable, Hashable {
|
||||
public var rawValue: String
|
||||
|
||||
public init(rawValue: String) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
}
|
||||
|
||||
public struct WalletInfo: Codable, Equatable {
|
||||
public let publicKey: WalletPublicKey
|
||||
public let rWalletInitialPublicKey: WalletInitialPublicKey?
|
||||
public let encryptedSecret: TonKeychainEncryptedData
|
||||
|
||||
public init(publicKey: WalletPublicKey, rWalletInitialPublicKey: WalletInitialPublicKey?, encryptedSecret: TonKeychainEncryptedData) {
|
||||
self.publicKey = publicKey
|
||||
self.rWalletInitialPublicKey = rWalletInitialPublicKey
|
||||
self.encryptedSecret = encryptedSecret
|
||||
}
|
||||
}
|
||||
|
||||
public struct ImportedWalletInfo: Codable, Equatable {
|
||||
public let publicKey: WalletPublicKey
|
||||
public let encryptedSecret: TonKeychainEncryptedData
|
||||
|
||||
@ -743,15 +763,50 @@ public struct CombinedWalletState: Codable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public struct WalletStateRecord: Codable, Equatable {
|
||||
public let info: WalletInfo
|
||||
public var exportCompleted: Bool
|
||||
public var state: CombinedWalletState?
|
||||
public enum WalletStateRecordDecodingError: Error {
|
||||
case generic
|
||||
}
|
||||
|
||||
public init(info: WalletInfo, exportCompleted: Bool, state: CombinedWalletState?) {
|
||||
public struct WalletStateRecord: Codable, Equatable {
|
||||
enum Key: CodingKey {
|
||||
case info
|
||||
case exportCompleted
|
||||
case state
|
||||
case importedInfo
|
||||
}
|
||||
|
||||
public enum Info: Equatable {
|
||||
case ready(info: WalletInfo, exportCompleted: Bool, state: CombinedWalletState?)
|
||||
case imported(info: ImportedWalletInfo)
|
||||
}
|
||||
|
||||
public var info: WalletStateRecord.Info
|
||||
|
||||
public init(info: WalletStateRecord.Info) {
|
||||
self.info = info
|
||||
self.exportCompleted = exportCompleted
|
||||
self.state = state
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: Key.self)
|
||||
if let info = try? container.decode(WalletInfo.self, forKey: .info) {
|
||||
self.info = .ready(info: info, exportCompleted: (try? container.decode(Bool.self, forKey: .exportCompleted)) ?? false, state: try? container.decode(Optional<CombinedWalletState>.self, forKey: .state))
|
||||
} else if let info = try? container.decode(ImportedWalletInfo.self, forKey: .importedInfo) {
|
||||
self.info = .imported(info: info)
|
||||
} else {
|
||||
throw WalletStateRecordDecodingError.generic
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: Key.self)
|
||||
switch info {
|
||||
case let .ready(info, exportCompleted, state):
|
||||
try container.encode(info, forKey: .info)
|
||||
try container.encode(exportCompleted, forKey: .exportCompleted)
|
||||
try container.encode(state, forKey: .state)
|
||||
case let .imported(info):
|
||||
try container.encode(info, forKey: .importedInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -771,7 +826,7 @@ public func createWallet(storage: WalletStorageInterface, tonInstance: TonInstan
|
||||
|> mapToSignal { walletInfo, wordList -> Signal<(WalletInfo, [String]), CreateWalletError> in
|
||||
return storage.updateWalletRecords({ records in
|
||||
var records = records
|
||||
records.append(WalletStateRecord(info: walletInfo, exportCompleted: false, state: nil))
|
||||
records.append(WalletStateRecord(info: .ready(info: walletInfo, exportCompleted: false, state: nil)))
|
||||
return records
|
||||
})
|
||||
|> map { _ -> (WalletInfo, [String]) in
|
||||
@ -785,8 +840,13 @@ public func confirmWalletExported(storage: WalletStorageInterface, publicKey: Wa
|
||||
return storage.updateWalletRecords { records in
|
||||
var records = records
|
||||
for i in 0 ..< records.count {
|
||||
if records[i].info.publicKey == publicKey {
|
||||
records[i].exportCompleted = true
|
||||
switch records[i].info {
|
||||
case let .ready(info, _, state):
|
||||
if info.publicKey == publicKey {
|
||||
records[i].info = .ready(info: info, exportCompleted: true, state: state)
|
||||
}
|
||||
case .imported:
|
||||
break
|
||||
}
|
||||
}
|
||||
return records
|
||||
@ -802,21 +862,21 @@ public enum ImportWalletError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public func importWallet(storage: WalletStorageInterface, tonInstance: TonInstance, keychain: TonKeychain, wordList: [String], localPassword: Data) -> Signal<WalletInfo, ImportWalletError> {
|
||||
public func importWallet(storage: WalletStorageInterface, tonInstance: TonInstance, keychain: TonKeychain, wordList: [String], localPassword: Data) -> Signal<ImportedWalletInfo, ImportWalletError> {
|
||||
return tonInstance.importWallet(keychain: keychain, wordList: wordList, localPassword: localPassword)
|
||||
|> `catch` { error -> Signal<WalletInfo, ImportWalletError> in
|
||||
|> `catch` { error -> Signal<ImportedWalletInfo, ImportWalletError> in
|
||||
switch error {
|
||||
case .generic:
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|> mapToSignal { walletInfo -> Signal<WalletInfo, ImportWalletError> in
|
||||
|> mapToSignal { walletInfo -> Signal<ImportedWalletInfo, ImportWalletError> in
|
||||
return storage.updateWalletRecords { records in
|
||||
var records = records
|
||||
records.append(WalletStateRecord(info: walletInfo, exportCompleted: true, state: nil))
|
||||
records.append(WalletStateRecord(info: .imported(info: walletInfo)))
|
||||
return records
|
||||
}
|
||||
|> map { _ -> WalletInfo in
|
||||
|> map { _ -> ImportedWalletInfo in
|
||||
return walletInfo
|
||||
}
|
||||
|> castError(ImportWalletError.self)
|
||||
@ -848,17 +908,29 @@ public func walletRestoreWords(tonInstance: TonInstance, publicKey: WalletPublic
|
||||
}
|
||||
|
||||
public struct WalletState: Codable, Equatable {
|
||||
public let balance: Int64
|
||||
public let totalBalance: Int64
|
||||
public let unlockedBalance: Int64?
|
||||
public let lastTransactionId: WalletTransactionId?
|
||||
|
||||
public init(balance: Int64, lastTransactionId: WalletTransactionId?) {
|
||||
self.balance = balance
|
||||
public init(totalBalance: Int64, unlockedBalance: Int64?, lastTransactionId: WalletTransactionId?) {
|
||||
self.totalBalance = totalBalance
|
||||
self.unlockedBalance = unlockedBalance
|
||||
self.lastTransactionId = lastTransactionId
|
||||
}
|
||||
}
|
||||
|
||||
public func walletAddress(publicKey: WalletPublicKey, tonInstance: TonInstance) -> Signal<String, NoError> {
|
||||
return tonInstance.walletAddress(publicKey: publicKey)
|
||||
public extension WalletState {
|
||||
var effectiveAvailableBalance: Int64 {
|
||||
if let unlockedBalance = self.unlockedBalance {
|
||||
return unlockedBalance
|
||||
} else {
|
||||
return self.totalBalance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func walletAddress(walletInfo: WalletInfo, tonInstance: TonInstance) -> Signal<String, NoError> {
|
||||
return tonInstance.walletAddress(publicKey: walletInfo.publicKey, rwalletInitialPublicKey: walletInfo.rWalletInitialPublicKey)
|
||||
}
|
||||
|
||||
private enum GetWalletStateError {
|
||||
@ -882,7 +954,39 @@ public enum CombinedWalletStateResult {
|
||||
|
||||
public enum CombinedWalletStateSubject {
|
||||
case wallet(WalletInfo)
|
||||
case address(String)
|
||||
}
|
||||
|
||||
public enum GetWalletInfoError {
|
||||
case generic
|
||||
case network
|
||||
}
|
||||
|
||||
public func getWalletInfo(importedInfo: ImportedWalletInfo, tonInstance: TonInstance) -> Signal<WalletInfo, GetWalletInfoError> {
|
||||
let rwalletInitialPublicKey = WalletInitialPublicKey(rawValue: "Pua8zmvG8934jf2mAysxTMUJUaxoXQskZKfqsAoGUjS2Kj4J")
|
||||
return tonInstance.walletAddress(publicKey: importedInfo.publicKey, rwalletInitialPublicKey: rwalletInitialPublicKey)
|
||||
|> castError(GetWalletInfoError.self)
|
||||
|> mapToSignal { address -> Signal<WalletInfo, GetWalletInfoError> in
|
||||
return tonInstance.getWalletState(address: address)
|
||||
|> mapError { error -> GetWalletInfoError in
|
||||
switch error {
|
||||
case .generic:
|
||||
return .generic
|
||||
case .network:
|
||||
return .network
|
||||
}
|
||||
}
|
||||
|> mapToSignal { state -> Signal<WalletInfo, GetWalletInfoError> in
|
||||
if state.0.unlockedBalance != nil {
|
||||
return .single(WalletInfo(publicKey: importedInfo.publicKey, rWalletInitialPublicKey: rwalletInitialPublicKey, encryptedSecret: importedInfo.encryptedSecret))
|
||||
} else {
|
||||
return tonInstance.walletAddress(publicKey: importedInfo.publicKey, rwalletInitialPublicKey: nil)
|
||||
|> castError(GetWalletInfoError.self)
|
||||
|> map { address -> WalletInfo in
|
||||
return WalletInfo(publicKey: importedInfo.publicKey, rWalletInitialPublicKey: nil, encryptedSecret: importedInfo.encryptedSecret)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func getCombinedWalletState(storage: WalletStorageInterface, subject: CombinedWalletStateSubject, tonInstance: TonInstance, onlyCached: Bool) -> Signal<CombinedWalletStateResult, GetCombinedWalletStateError> {
|
||||
@ -891,8 +995,13 @@ public func getCombinedWalletState(storage: WalletStorageInterface, subject: Com
|
||||
return storage.getWalletRecords()
|
||||
|> map { records -> CombinedWalletState? in
|
||||
for item in records {
|
||||
if item.info.publicKey == walletInfo.publicKey {
|
||||
return item.state
|
||||
switch item.info {
|
||||
case let .ready(itemInfo, _, state):
|
||||
if itemInfo.publicKey == walletInfo.publicKey {
|
||||
return state
|
||||
}
|
||||
case .imported:
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -904,7 +1013,7 @@ public func getCombinedWalletState(storage: WalletStorageInterface, subject: Com
|
||||
}
|
||||
return .single(.cached(cachedState))
|
||||
|> then(
|
||||
tonInstance.walletAddress(publicKey: walletInfo.publicKey)
|
||||
tonInstance.walletAddress(publicKey: walletInfo.publicKey, rwalletInitialPublicKey: walletInfo.rWalletInitialPublicKey)
|
||||
|> castError(GetCombinedWalletStateError.self)
|
||||
|> mapToSignal { address -> Signal<CombinedWalletStateResult, GetCombinedWalletStateError> in
|
||||
|
||||
@ -981,8 +1090,13 @@ public func getCombinedWalletState(storage: WalletStorageInterface, subject: Com
|
||||
return storage.updateWalletRecords { records in
|
||||
var records = records
|
||||
for i in 0 ..< records.count {
|
||||
if records[i].info.publicKey == walletInfo.publicKey {
|
||||
records[i].state = combinedState
|
||||
switch records[i].info {
|
||||
case let .ready(itemInfo, exportCompleted, _):
|
||||
if itemInfo.publicKey == walletInfo.publicKey {
|
||||
records[i].info = .ready(info: itemInfo, exportCompleted: exportCompleted, state: combinedState)
|
||||
}
|
||||
case .imported:
|
||||
break
|
||||
}
|
||||
}
|
||||
return records
|
||||
@ -996,26 +1110,6 @@ public func getCombinedWalletState(storage: WalletStorageInterface, subject: Com
|
||||
}
|
||||
)
|
||||
}
|
||||
case let .address(address):
|
||||
let updated = getWalletState(address: address, tonInstance: tonInstance)
|
||||
|> mapError { _ -> GetCombinedWalletStateError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { walletState, syncUtime -> Signal<CombinedWalletStateResult, GetCombinedWalletStateError> in
|
||||
let topTransactions: Signal<[WalletTransaction], GetCombinedWalletStateError>
|
||||
|
||||
topTransactions = getWalletTransactions(address: address, previousId: nil, tonInstance: tonInstance)
|
||||
|> mapError { _ -> GetCombinedWalletStateError in
|
||||
return .generic
|
||||
}
|
||||
return topTransactions
|
||||
|> mapToSignal { topTransactions -> Signal<CombinedWalletStateResult, GetCombinedWalletStateError> in
|
||||
let combinedState = CombinedWalletState(walletState: walletState, timestamp: syncUtime, topTransactions: topTransactions, pendingTransactions: [])
|
||||
return .single(.updated(combinedState))
|
||||
}
|
||||
}
|
||||
return .single(.cached(nil))
|
||||
|> then(updated)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1042,7 +1136,7 @@ public struct SendGramsVerificationResult {
|
||||
}
|
||||
|
||||
public func verifySendGramsRequestAndEstimateFees(tonInstance: TonInstance, walletInfo: WalletInfo, toAddress: String, amount: Int64, comment: Data, encryptComment: Bool, timeout: Int32) -> Signal<SendGramsVerificationResult, SendGramsFromWalletError> {
|
||||
return walletAddress(publicKey: walletInfo.publicKey, tonInstance: tonInstance)
|
||||
return walletAddress(walletInfo: walletInfo, tonInstance: tonInstance)
|
||||
|> castError(SendGramsFromWalletError.self)
|
||||
|> mapToSignal { fromAddress -> Signal<SendGramsVerificationResult, SendGramsFromWalletError> in
|
||||
struct QueryWithInfo {
|
||||
@ -1074,7 +1168,7 @@ public func verifySendGramsRequestAndEstimateFees(tonInstance: TonInstance, wall
|
||||
}
|
||||
|
||||
public func sendGramsFromWallet(storage: WalletStorageInterface, tonInstance: TonInstance, walletInfo: WalletInfo, decryptedSecret: Data, localPassword: Data, toAddress: String, amount: Int64, comment: Data, encryptComment: Bool, forceIfDestinationNotInitialized: Bool, timeout: Int32, randomId: Int64) -> Signal<PendingWalletTransaction, SendGramsFromWalletError> {
|
||||
return walletAddress(publicKey: walletInfo.publicKey, tonInstance: tonInstance)
|
||||
return walletAddress(walletInfo: walletInfo, tonInstance: tonInstance)
|
||||
|> castError(SendGramsFromWalletError.self)
|
||||
|> mapToSignal { fromAddress -> Signal<PendingWalletTransaction, SendGramsFromWalletError> in
|
||||
return tonInstance.prepareSendGramsFromWalletQuery(decryptedSecret: decryptedSecret, localPassword: localPassword, walletInfo: walletInfo, fromAddress: fromAddress, toAddress: toAddress, amount: amount, comment: comment, encryptComment: encryptComment, forceIfDestinationNotInitialized: forceIfDestinationNotInitialized, timeout: timeout, randomId: randomId)
|
||||
@ -1094,11 +1188,14 @@ public func sendGramsFromWallet(storage: WalletStorageInterface, tonInstance: To
|
||||
return storage.updateWalletRecords { records in
|
||||
var records = records
|
||||
for i in 0 ..< records.count {
|
||||
if records[i].info.publicKey == walletInfo.publicKey {
|
||||
if var state = records[i].state {
|
||||
switch records[i].info {
|
||||
case let .ready(itemInfo, exportCompleted, itemState):
|
||||
if itemInfo.publicKey == walletInfo.publicKey, var state = itemState {
|
||||
state.pendingTransactions.insert(result, at: 0)
|
||||
records[i].state = state
|
||||
records[i].info = .ready(info: itemInfo, exportCompleted: exportCompleted, state: state)
|
||||
}
|
||||
case .imported:
|
||||
break
|
||||
}
|
||||
}
|
||||
return records
|
||||
|
@ -44,7 +44,7 @@ private class WalletInfoTitleView: UIView, NavigationBarTitleView {
|
||||
|
||||
public final class WalletInfoScreen: ViewController {
|
||||
private let context: WalletContext
|
||||
private let walletInfo: WalletInfo?
|
||||
private let walletInfo: WalletInfo
|
||||
private let address: String
|
||||
private let enableDebugActions: Bool
|
||||
|
||||
@ -55,7 +55,7 @@ public final class WalletInfoScreen: ViewController {
|
||||
return self._ready
|
||||
}
|
||||
|
||||
public init(context: WalletContext, walletInfo: WalletInfo?, address: String, enableDebugActions: Bool) {
|
||||
public init(context: WalletContext, walletInfo: WalletInfo, address: String, enableDebugActions: Bool) {
|
||||
self.context = context
|
||||
self.walletInfo = walletInfo
|
||||
self.address = address
|
||||
@ -73,9 +73,7 @@ public final class WalletInfoScreen: ViewController {
|
||||
self.navigationBar?.intrinsicCanTransitionInline = false
|
||||
|
||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Wallet_Navigation_Back, style: .plain, target: nil, action: nil)
|
||||
if let _ = walletInfo {
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: generateTintedImage(image: UIImage(bundleImageName: "Wallet/NavigationSettingsIcon"), color: .white), style: .plain, target: self, action: #selector(self.settingsPressed))
|
||||
}
|
||||
|
||||
self.navigationItem.titleView = WalletInfoTitleView(action: { [weak self] in self?.scrollToTop?() })
|
||||
|
||||
@ -93,16 +91,15 @@ public final class WalletInfoScreen: ViewController {
|
||||
}
|
||||
|
||||
@objc private func settingsPressed() {
|
||||
if let walletInfo = self.walletInfo {
|
||||
self.push(walletSettingsController(context: self.context, walletInfo: walletInfo))
|
||||
}
|
||||
self.push(walletSettingsController(context: self.context, walletInfo: self.walletInfo))
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = WalletInfoScreenNode(context: self.context, presentationData: self.presentationData, walletInfo: self.walletInfo, address: self.address, sendAction: { [weak self] in
|
||||
guard let strongSelf = self, let walletInfo = strongSelf.walletInfo else {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let walletInfo = strongSelf.walletInfo
|
||||
guard let combinedState = (strongSelf.displayNode as! WalletInfoScreenNode).combinedState else {
|
||||
return
|
||||
}
|
||||
@ -122,10 +119,16 @@ public final class WalletInfoScreen: ViewController {
|
||||
strongSelf.push(walletSendScreen(context: strongSelf.context, randomId: randomId, walletInfo: walletInfo))
|
||||
}
|
||||
}, receiveAction: { [weak self] in
|
||||
guard let strongSelf = self, let _ = strongSelf.walletInfo else {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.push(WalletReceiveScreen(context: strongSelf.context, mode: .receive(address: strongSelf.address)))
|
||||
let _ = (walletAddress(walletInfo: strongSelf.walletInfo, tonInstance: strongSelf.context.tonInstance)
|
||||
|> deliverOnMainQueue).start(next: { address in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.push(WalletReceiveScreen(context: strongSelf.context, mode: .receive(address: address)))
|
||||
})
|
||||
}, openTransaction: { [weak self] transaction in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -274,7 +277,8 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
|
||||
|
||||
let balanceNode: WalletInfoBalanceNode
|
||||
let refreshNode: WalletRefreshNode
|
||||
private let balanceSubtitleNode: ImmediateTextNode
|
||||
let balanceSubtitleNode: ImmediateTextNode
|
||||
let balanceSubtitleIconNode: AnimatedStickerNode
|
||||
private let receiveButtonNode: SolidRoundedButtonNode
|
||||
private let receiveGramsButtonNode: SolidRoundedButtonNode
|
||||
private let sendButtonNode: SolidRoundedButtonNode
|
||||
@ -288,7 +292,15 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
|
||||
|
||||
self.balanceSubtitleNode = ImmediateTextNode()
|
||||
self.balanceSubtitleNode.displaysAsynchronously = false
|
||||
self.balanceSubtitleNode.attributedText = NSAttributedString(string: hasActions ? presentationData.strings.Wallet_Info_YourBalance : "balance", font: Font.regular(13), textColor: UIColor(white: 1.0, alpha: 0.6))
|
||||
self.balanceSubtitleNode.attributedText = NSAttributedString(string: presentationData.strings.Wallet_Info_YourBalance, font: Font.regular(13), textColor: UIColor(white: 1.0, alpha: 0.6))
|
||||
|
||||
self.balanceSubtitleIconNode = AnimatedStickerNode()
|
||||
self.balanceSubtitleIconNode.isHidden = true
|
||||
if let path = getAppBundle().path(forResource: "WalletIntroStatic", ofType: "tgs") {
|
||||
self.balanceSubtitleIconNode.setup(source: AnimatedStickerNodeLocalFileSource(path: path), width: 36, height: 36, mode: .direct)
|
||||
self.balanceSubtitleIconNode.visibility = true
|
||||
}
|
||||
self.balanceSubtitleNode.addSubnode(self.balanceSubtitleIconNode)
|
||||
|
||||
self.headerBackgroundNode = ASDisplayNode()
|
||||
self.headerBackgroundNode.backgroundColor = .black
|
||||
@ -353,6 +365,9 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
|
||||
let buttonAlpha: CGFloat = buttonTransition
|
||||
|
||||
let balanceSubtitleSize = self.balanceSubtitleNode.updateLayout(CGSize(width: size.width - sideInset * 2.0, height: 200.0))
|
||||
let balanceSubtitleIconSize = CGSize(width: 18.0, height: 18.0)
|
||||
self.balanceSubtitleIconNode.frame = CGRect(origin: CGPoint(x: -balanceSubtitleIconSize.width - 2.0, y: -2.0), size: balanceSubtitleIconSize)
|
||||
self.balanceSubtitleIconNode.updateLayout(size: balanceSubtitleIconSize)
|
||||
|
||||
let headerScaleTransition: CGFloat = max(0.0, min(1.0, (effectiveOffset - minHeaderOffset) / (maxHeaderOffset - minHeaderOffset)))
|
||||
|
||||
@ -544,7 +559,7 @@ private func preparedTransition(from fromEntries: [WalletInfoListEntry], to toEn
|
||||
private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
private let context: WalletContext
|
||||
private var presentationData: WalletPresentationData
|
||||
private let walletInfo: WalletInfo?
|
||||
private let walletInfo: WalletInfo
|
||||
private let address: String
|
||||
|
||||
private let openTransaction: (WalletInfoTransaction) -> Void
|
||||
@ -585,7 +600,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
private var watchCombinedStateDisposable: Disposable?
|
||||
private var refreshProgressDisposable: Disposable?
|
||||
|
||||
init(context: WalletContext, presentationData: WalletPresentationData, walletInfo: WalletInfo?, address: String, sendAction: @escaping () -> Void, receiveAction: @escaping () -> Void, openTransaction: @escaping (WalletInfoTransaction) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
||||
init(context: WalletContext, presentationData: WalletPresentationData, walletInfo: WalletInfo, address: String, sendAction: @escaping () -> Void, receiveAction: @escaping () -> Void, openTransaction: @escaping (WalletInfoTransaction) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
||||
self.context = context
|
||||
self.presentationData = presentationData
|
||||
self.walletInfo = walletInfo
|
||||
@ -593,7 +608,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
self.openTransaction = openTransaction
|
||||
self.present = present
|
||||
|
||||
self.headerNode = WalletInfoHeaderNode(presentationData: presentationData, hasActions: walletInfo != nil, sendAction: sendAction, receiveAction: receiveAction)
|
||||
self.headerNode = WalletInfoHeaderNode(presentationData: presentationData, hasActions: true, sendAction: sendAction, receiveAction: receiveAction)
|
||||
|
||||
self.listNode = ListView()
|
||||
self.listNode.verticalScrollIndicatorColor = UIColor(white: 0.0, alpha: 0.3)
|
||||
@ -681,26 +696,23 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
}, queue: .mainQueue())
|
||||
self.updateTimestampTimer?.start()
|
||||
|
||||
let subject: CombinedWalletStateSubject
|
||||
if let walletInfo = walletInfo {
|
||||
subject = .wallet(walletInfo)
|
||||
let subject: CombinedWalletStateSubject = .wallet(walletInfo)
|
||||
|
||||
let watchCombinedStateSignal = context.storage.watchWalletRecords()
|
||||
|> map { records -> WalletStateRecord? in
|
||||
|> map { records -> CombinedWalletState? in
|
||||
for record in records {
|
||||
if record.info.publicKey == walletInfo.publicKey {
|
||||
return record
|
||||
switch record.info {
|
||||
case let .ready(itemInfo, _, state):
|
||||
if itemInfo.publicKey == walletInfo.publicKey {
|
||||
return state
|
||||
}
|
||||
case .imported:
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { wallet -> Signal<CombinedWalletState?, NoError> in
|
||||
guard let wallet = wallet, let state = wallet.state else {
|
||||
return .single(nil)
|
||||
}
|
||||
return .single(state)
|
||||
}
|
||||
|
||||
let tonInstance = self.context.tonInstance
|
||||
let decryptedWalletState = combineLatest(queue: .mainQueue(),
|
||||
@ -732,9 +744,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
subject = .address(address)
|
||||
}
|
||||
|
||||
let pollCombinedState: Signal<Never, NoError> = (
|
||||
getCombinedWalletState(storage: context.storage, subject: subject, tonInstance: context.tonInstance, onlyCached: false)
|
||||
|> ignoreValues
|
||||
@ -908,12 +918,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
self.headerNode.isRefreshing = true
|
||||
self.headerNode.refreshNode.refreshProgress = 0.0
|
||||
|
||||
let subject: CombinedWalletStateSubject
|
||||
if let walletInfo = self.walletInfo {
|
||||
subject = .wallet(walletInfo)
|
||||
} else {
|
||||
subject = .address(self.address)
|
||||
}
|
||||
let subject: CombinedWalletStateSubject = .wallet(self.walletInfo)
|
||||
|
||||
let transactionDecryptionKey = self.transactionDecryptionKey
|
||||
let tonInstance = self.context.tonInstance
|
||||
@ -1017,8 +1022,23 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
private func updateCombinedState(combinedState: CombinedWalletState?, isUpdated: Bool) {
|
||||
self.combinedState = combinedState
|
||||
if let combinedState = combinedState {
|
||||
self.headerNode.balanceNode.balance = (formatBalanceText(max(0, combinedState.walletState.balance), decimalSeparator: self.presentationData.dateTimeFormat.decimalSeparator), .white)
|
||||
self.headerNode.balance = max(0, combinedState.walletState.balance)
|
||||
self.headerNode.balanceNode.balance = (formatBalanceText(max(0, combinedState.walletState.effectiveAvailableBalance), decimalSeparator: self.presentationData.dateTimeFormat.decimalSeparator), .white)
|
||||
if let unlockedBalance = combinedState.walletState.unlockedBalance {
|
||||
let lockedBalance = combinedState.walletState.totalBalance - unlockedBalance
|
||||
|
||||
let balanceText = formatBalanceText(max(0, lockedBalance), decimalSeparator: self.presentationData.dateTimeFormat.decimalSeparator)
|
||||
|
||||
let string = NSMutableAttributedString()
|
||||
string.append(NSAttributedString(string: "\(balanceText)", font: Font.semibold(13), textColor: .white))
|
||||
string.append(NSAttributedString(string: " locked", font: Font.regular(13), textColor: .white))
|
||||
|
||||
self.headerNode.balanceSubtitleNode.attributedText = string
|
||||
self.headerNode.balanceSubtitleIconNode.isHidden = false
|
||||
} else {
|
||||
self.headerNode.balanceSubtitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.Wallet_Info_YourBalance, font: Font.regular(13), textColor: UIColor(white: 1.0, alpha: 0.6))
|
||||
self.headerNode.balanceSubtitleIconNode.isHidden = true
|
||||
}
|
||||
self.headerNode.balance = max(0, combinedState.walletState.effectiveAvailableBalance)
|
||||
|
||||
if self.isReady, let (layout, navigationHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate)
|
||||
@ -1117,7 +1137,12 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
let transactionDecryptionKey = self.transactionDecryptionKey
|
||||
let tonInstance = self.context.tonInstance
|
||||
let processedTransactions = getWalletTransactions(address: self.address, previousId: lastTransactionId, tonInstance: self.context.tonInstance)
|
||||
let requestTransactions = walletAddress(walletInfo: self.walletInfo, tonInstance: self.context.tonInstance)
|
||||
|> castError(GetWalletTransactionsError.self)
|
||||
|> mapToSignal { address -> Signal<[WalletTransaction], GetWalletTransactionsError> in
|
||||
getWalletTransactions(address: address, previousId: lastTransactionId, tonInstance: tonInstance)
|
||||
}
|
||||
let processedTransactions = requestTransactions
|
||||
|> mapToSignal { transactions -> Signal<[WalletTransaction], GetWalletTransactionsError> in
|
||||
return transactionDecryptionKey.get()
|
||||
|> castError(GetWalletTransactionsError.self)
|
||||
|
@ -501,7 +501,7 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
||||
})
|
||||
}
|
||||
|
||||
let _ = (walletAddress(publicKey: walletInfo.publicKey, tonInstance: context.tonInstance)
|
||||
let _ = (walletAddress(walletInfo: walletInfo, tonInstance: context.tonInstance)
|
||||
|> deliverOnMainQueue).start(next: { walletAddress in
|
||||
let presentationData = context.presentationData
|
||||
let state = stateValue.with { $0 }
|
||||
@ -572,7 +572,7 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
||||
var emptyItem: ItemListControllerEmptyStateItem?
|
||||
if let walletState = walletState {
|
||||
let textLength: Int = state.comment.data(using: .utf8, allowLossyConversion: true)?.count ?? 0
|
||||
sendEnabled = isValidAddress(state.address, exactLength: true) && amount > 0 && amount <= walletState.balance && textLength <= walletTextLimit
|
||||
sendEnabled = isValidAddress(state.address, exactLength: true) && amount > 0 && amount <= walletState.effectiveAvailableBalance && textLength <= walletTextLimit
|
||||
|
||||
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Wallet_Send_Send), style: .bold, enabled: sendEnabled, action: {
|
||||
arguments.proceed()
|
||||
@ -583,7 +583,7 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
||||
}
|
||||
|
||||
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Wallet_Send_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Wallet_Navigation_Back), animateChanges: false)
|
||||
let listState = ItemListNodeState(entries: walletSendScreenEntries(presentationData: presentationData, balance: walletState?.balance, state: state, sendEnabled: sendEnabled), style: .blocks, focusItemTag: focusItemTag, emptyStateItem: emptyItem, animateChanges: false)
|
||||
let listState = ItemListNodeState(entries: walletSendScreenEntries(presentationData: presentationData, balance: walletState?.effectiveAvailableBalance, state: state, sendEnabled: sendEnabled), style: .blocks, focusItemTag: focusItemTag, emptyStateItem: emptyItem, animateChanges: false)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|
@ -48,7 +48,8 @@ public struct WalletSplashModeSending {
|
||||
public enum WalletSplashMode {
|
||||
case intro
|
||||
case created(walletInfo: WalletInfo, words: [String]?)
|
||||
case success(walletInfo: WalletInfo)
|
||||
case successfullyCreated(walletInfo: WalletInfo)
|
||||
case successfullyImported(importedInfo: ImportedWalletInfo)
|
||||
case restoreFailed
|
||||
case sending(WalletSplashModeSending)
|
||||
case sent(walletInfo: WalletInfo, amount: Int64)
|
||||
@ -56,16 +57,21 @@ public enum WalletSplashMode {
|
||||
case secureStorageReset(WalletSecureStorageResetReason)
|
||||
}
|
||||
|
||||
public struct WalletCreatedPreloadState {
|
||||
let info: WalletInfo
|
||||
let state: CombinedWalletStateResult
|
||||
}
|
||||
|
||||
public final class WalletSplashScreen: ViewController {
|
||||
private let context: WalletContext
|
||||
private var presentationData: WalletPresentationData
|
||||
private var mode: WalletSplashMode
|
||||
|
||||
private let walletCreatedPreloadState: Promise<CombinedWalletStateResult?>?
|
||||
private let walletCreatedPreloadState: Promise<WalletCreatedPreloadState?>?
|
||||
|
||||
private let actionDisposable = MetaDisposable()
|
||||
|
||||
public init(context: WalletContext, mode: WalletSplashMode, walletCreatedPreloadState: Promise<CombinedWalletStateResult?>?) {
|
||||
public init(context: WalletContext, mode: WalletSplashMode, walletCreatedPreloadState: Promise<WalletCreatedPreloadState?>?) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
|
||||
@ -81,22 +87,70 @@ public final class WalletSplashScreen: ViewController {
|
||||
} else {
|
||||
self.walletCreatedPreloadState = Promise()
|
||||
self.walletCreatedPreloadState?.set(getCombinedWalletState(storage: context.storage, subject: .wallet(walletInfo), tonInstance: context.tonInstance, onlyCached: false)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<CombinedWalletStateResult?, NoError> in
|
||||
|> map { state -> WalletCreatedPreloadState? in
|
||||
return WalletCreatedPreloadState(info: walletInfo, state: state)
|
||||
}
|
||||
|> `catch` { _ -> Signal<WalletCreatedPreloadState?, NoError> in
|
||||
return .single(nil)
|
||||
})
|
||||
}
|
||||
case let .success(walletInfo):
|
||||
case let .successfullyCreated(walletInfo):
|
||||
if let walletCreatedPreloadState = walletCreatedPreloadState {
|
||||
self.walletCreatedPreloadState = walletCreatedPreloadState
|
||||
} else {
|
||||
self.walletCreatedPreloadState = Promise()
|
||||
self.walletCreatedPreloadState?.set(getCombinedWalletState(storage: context.storage, subject: .wallet(walletInfo), tonInstance: context.tonInstance, onlyCached: false)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<CombinedWalletStateResult?, NoError> in
|
||||
|> map { state -> WalletCreatedPreloadState? in
|
||||
return WalletCreatedPreloadState(info: walletInfo, state: state)
|
||||
}
|
||||
|> `catch` { _ -> Signal<WalletCreatedPreloadState?, NoError> in
|
||||
return .single(nil)
|
||||
})
|
||||
}
|
||||
case let .successfullyImported(importedInfo):
|
||||
if let walletCreatedPreloadState = walletCreatedPreloadState {
|
||||
self.walletCreatedPreloadState = walletCreatedPreloadState
|
||||
} else {
|
||||
self.walletCreatedPreloadState = Promise()
|
||||
|
||||
let signal = getWalletInfo(importedInfo: importedInfo, tonInstance: context.tonInstance)
|
||||
|> mapError { error -> GetCombinedWalletStateError in
|
||||
switch error {
|
||||
case .generic:
|
||||
return .generic
|
||||
case .network:
|
||||
return .network
|
||||
}
|
||||
}
|
||||
|> mapToSignal { walletInfo -> Signal<WalletCreatedPreloadState?, GetCombinedWalletStateError> in
|
||||
return context.storage.updateWalletRecords { records in
|
||||
var records = records
|
||||
for i in 0 ..< records.count {
|
||||
switch records[i].info {
|
||||
case .ready:
|
||||
break
|
||||
case let .imported(info):
|
||||
if info.publicKey == importedInfo.publicKey {
|
||||
records[i].info = .ready(info: walletInfo, exportCompleted: true, state: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
return records
|
||||
}
|
||||
|> castError(GetCombinedWalletStateError.self)
|
||||
|> mapToSignal { _ -> Signal<WalletCreatedPreloadState?, GetCombinedWalletStateError> in
|
||||
return getCombinedWalletState(storage: context.storage, subject: .wallet(walletInfo), tonInstance: context.tonInstance, onlyCached: false)
|
||||
|> map { state -> WalletCreatedPreloadState? in
|
||||
return WalletCreatedPreloadState(info: walletInfo, state: state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|> `catch` { _ -> Signal<WalletCreatedPreloadState?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|
||||
self.walletCreatedPreloadState?.set(signal)
|
||||
}
|
||||
default:
|
||||
self.walletCreatedPreloadState = nil
|
||||
}
|
||||
@ -139,7 +193,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
self.navigationItem.setLeftBarButton(UIBarButtonItem(customDisplayNode: ASDisplayNode())!, animated: false)
|
||||
case .restoreFailed, .secureStorageNotAvailable, .secureStorageReset, .created:
|
||||
break
|
||||
case .success:
|
||||
case .successfullyCreated, .successfullyImported:
|
||||
break
|
||||
}
|
||||
|
||||
@ -197,7 +251,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
return
|
||||
}
|
||||
if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
let _ = (walletAddress(publicKey: walletInfo.publicKey, tonInstance: strongSelf.context.tonInstance)
|
||||
let _ = (walletAddress(walletInfo: walletInfo, tonInstance: strongSelf.context.tonInstance)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] address in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -222,7 +276,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
return
|
||||
}
|
||||
if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
let _ = (walletAddress(publicKey: walletInfo.publicKey, tonInstance: strongSelf.context.tonInstance)
|
||||
let _ = (walletAddress(walletInfo: walletInfo, tonInstance: strongSelf.context.tonInstance)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] address in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -315,7 +369,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
return true
|
||||
}
|
||||
|
||||
let _ = (walletAddress(publicKey: sending.walletInfo.publicKey, tonInstance: self.context.tonInstance)
|
||||
let _ = (walletAddress(walletInfo: sending.walletInfo, tonInstance: self.context.tonInstance)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] address in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -426,8 +480,8 @@ public final class WalletSplashScreen: ViewController {
|
||||
}
|
||||
})
|
||||
}
|
||||
case let .success(walletInfo):
|
||||
let _ = (walletAddress(publicKey: walletInfo.publicKey, tonInstance: strongSelf.context.tonInstance)
|
||||
case let .successfullyCreated(walletInfo):
|
||||
let _ = (walletAddress(walletInfo: walletInfo, tonInstance: strongSelf.context.tonInstance)
|
||||
|> deliverOnMainQueue).start(next: { address in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -452,6 +506,46 @@ public final class WalletSplashScreen: ViewController {
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
})
|
||||
case .successfullyImported:
|
||||
let controller = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: nil))
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
|
||||
let _ = (strongSelf.walletCreatedPreloadState!.get()
|
||||
|> filter { $0 != nil }
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { state in
|
||||
controller.dismiss()
|
||||
|
||||
guard let state = state else {
|
||||
return
|
||||
}
|
||||
let walletInfo = state.info
|
||||
let _ = (walletAddress(walletInfo: walletInfo, tonInstance: strongSelf.context.tonInstance)
|
||||
|> deliverOnMainQueue).start(next: { address in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
var controllers = navigationController.viewControllers
|
||||
controllers = controllers.filter { controller in
|
||||
if controller is WalletSplashScreen {
|
||||
return false
|
||||
}
|
||||
if controller is WalletWordDisplayScreen {
|
||||
return false
|
||||
}
|
||||
if controller is WalletWordCheckScreen {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(WalletInfoScreen(context: strongSelf.context, walletInfo: walletInfo, address: address, enableDebugActions: false))
|
||||
strongSelf.view.endEditing(true)
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
})
|
||||
})
|
||||
case let .sent(walletInfo, _):
|
||||
if let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
var controllers = navigationController.viewControllers
|
||||
@ -474,7 +568,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
return true
|
||||
}
|
||||
|
||||
let _ = (walletAddress(publicKey: walletInfo.publicKey, tonInstance: strongSelf.context.tonInstance)
|
||||
let _ = (walletAddress(walletInfo: walletInfo, tonInstance: strongSelf.context.tonInstance)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] address in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -527,7 +621,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
return true
|
||||
}
|
||||
|
||||
let _ = (walletAddress(publicKey: sending.walletInfo.publicKey, tonInstance: strongSelf.context.tonInstance)
|
||||
let _ = (walletAddress(walletInfo: sending.walletInfo, tonInstance: strongSelf.context.tonInstance)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] address in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -627,7 +721,7 @@ private final class WalletSplashScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
}
|
||||
|
||||
init(context: WalletContext, walletCreatedPreloadState: Promise<CombinedWalletStateResult?>?, presentationData: WalletPresentationData, mode: WalletSplashMode, action: @escaping () -> Void, secondaryAction: @escaping () -> Void, openTerms: @escaping () -> Void) {
|
||||
init(context: WalletContext, walletCreatedPreloadState: Promise<WalletCreatedPreloadState?>?, presentationData: WalletPresentationData, mode: WalletSplashMode, action: @escaping () -> Void, secondaryAction: @escaping () -> Void, openTerms: @escaping () -> Void) {
|
||||
self.presentationData = presentationData
|
||||
self.mode = mode
|
||||
self.secondaryAction = secondaryAction
|
||||
@ -680,7 +774,7 @@ private final class WalletSplashScreenNode: ViewControllerTracingNode {
|
||||
self.animationNode.visibility = true
|
||||
}
|
||||
secondaryActionText = ""
|
||||
case .success:
|
||||
case .successfullyCreated, .successfullyImported:
|
||||
title = self.presentationData.strings.Wallet_Completed_Title
|
||||
text = NSAttributedString(string: self.presentationData.strings.Wallet_Completed_Text, font: textFont, textColor: textColor)
|
||||
buttonText = self.presentationData.strings.Wallet_Completed_ViewWallet
|
||||
@ -899,7 +993,7 @@ private final class WalletSplashScreenNode: ViewControllerTracingNode {
|
||||
let iconSize: CGSize = self.animationSize
|
||||
var iconOffset = CGPoint()
|
||||
switch self.mode {
|
||||
case .success:
|
||||
case .successfullyCreated, .successfullyImported:
|
||||
iconOffset.x = 10.0
|
||||
default:
|
||||
break
|
||||
|
@ -2073,9 +2073,9 @@ public final class WalletWordCheckScreen: ViewController {
|
||||
|
||||
private let startTime: Double
|
||||
|
||||
private let walletCreatedPreloadState: Promise<CombinedWalletStateResult?>?
|
||||
private let walletCreatedPreloadState: Promise<WalletCreatedPreloadState?>?
|
||||
|
||||
public init(context: WalletContext, mode: WalletWordCheckMode, walletCreatedPreloadState: Promise<CombinedWalletStateResult?>?) {
|
||||
public init(context: WalletContext, mode: WalletWordCheckMode, walletCreatedPreloadState: Promise<WalletCreatedPreloadState?>?) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
self.walletCreatedPreloadState = walletCreatedPreloadState
|
||||
@ -2137,7 +2137,7 @@ public final class WalletWordCheckScreen: ViewController {
|
||||
return true
|
||||
}
|
||||
let _ = confirmWalletExported(storage: strongSelf.context.storage, publicKey: walletInfo.publicKey).start()
|
||||
controllers.append(WalletSplashScreen(context: strongSelf.context, mode: .success(walletInfo: walletInfo), walletCreatedPreloadState: strongSelf.walletCreatedPreloadState))
|
||||
controllers.append(WalletSplashScreen(context: strongSelf.context, mode: .successfullyCreated(walletInfo: walletInfo), walletCreatedPreloadState: strongSelf.walletCreatedPreloadState))
|
||||
strongSelf.view.endEditing(true)
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
@ -2205,7 +2205,7 @@ public final class WalletWordCheckScreen: ViewController {
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(WalletSplashScreen(context: strongSelf.context, mode: .success(walletInfo: walletInfo), walletCreatedPreloadState: strongSelf.walletCreatedPreloadState))
|
||||
controllers.append(WalletSplashScreen(context: strongSelf.context, mode: .successfullyImported(importedInfo: walletInfo), walletCreatedPreloadState: strongSelf.walletCreatedPreloadState))
|
||||
strongSelf.view.endEditing(true)
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
|
@ -24,9 +24,9 @@ public final class WalletWordDisplayScreen: ViewController {
|
||||
private let startTime: Double
|
||||
private let idleTimerExtensionDisposable: Disposable
|
||||
|
||||
private let walletCreatedPreloadState: Promise<CombinedWalletStateResult?>?
|
||||
private let walletCreatedPreloadState: Promise<WalletCreatedPreloadState?>?
|
||||
|
||||
public init(context: WalletContext, walletInfo: WalletInfo, wordList: [String], mode: WalletWordDisplayScreenMode, walletCreatedPreloadState: Promise<CombinedWalletStateResult?>?) {
|
||||
public init(context: WalletContext, walletInfo: WalletInfo, wordList: [String], mode: WalletWordDisplayScreenMode, walletCreatedPreloadState: Promise<WalletCreatedPreloadState?>?) {
|
||||
self.context = context
|
||||
self.walletInfo = walletInfo
|
||||
self.wordList = wordList
|
||||
|
3
submodules/ton/tonlib-src/CMakeLists.txt
vendored
3
submodules/ton/tonlib-src/CMakeLists.txt
vendored
@ -104,6 +104,7 @@ if (TON_USE_ROCKSDB)
|
||||
if (ANDROID)
|
||||
set(PORTABLE ON CACHE BOOL "portable")
|
||||
endif()
|
||||
set(WITH_GFLAGS OFF CACHE BOOL "build with GFlags")
|
||||
set(WITH_TESTS OFF CACHE BOOL "build with tests")
|
||||
set(WITH_TOOLS OFF CACHE BOOL "build with tools")
|
||||
set(FAIL_ON_WARNINGS OFF CACHE BOOL "fail on warnings")
|
||||
@ -220,7 +221,7 @@ elseif (CLANG OR GCC)
|
||||
if (APPLE)
|
||||
#use "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/export_list" for exported symbols
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fvisibility=hidden -Wl,-dead_strip,-x,-S")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fvisibility=hidden -Wl,-dead_strip,-x,-S")
|
||||
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fvisibility=hidden -Wl,-dead_strip,-x,-S")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections -Wl,--exclude-libs,ALL")
|
||||
|
@ -49,6 +49,7 @@ set(TON_CRYPTO_SOURCE
|
||||
common/bigexp.h
|
||||
common/util.h
|
||||
common/linalloc.hpp
|
||||
common/promiseop.hpp
|
||||
|
||||
ellcurve/Ed25519.h
|
||||
ellcurve/Fp25519.h
|
||||
@ -212,6 +213,7 @@ set(SMC_ENVELOPE_SOURCE
|
||||
smc-envelope/HighloadWalletV2.cpp
|
||||
smc-envelope/ManualDns.cpp
|
||||
smc-envelope/MultisigWallet.cpp
|
||||
smc-envelope/PaymentChannel.cpp
|
||||
smc-envelope/SmartContract.cpp
|
||||
smc-envelope/SmartContractCode.cpp
|
||||
smc-envelope/TestGiver.cpp
|
||||
@ -341,7 +343,7 @@ if (NOT CMAKE_CROSSCOMPILING)
|
||||
set(multiValueArgs SOURCE)
|
||||
set(FUNC_LIB_SOURCE smartcont/stdlib.fc)
|
||||
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
||||
string(REGEX REPLACE "[^a-zA-Z_]" "_" ID ${ARG_DEST})
|
||||
string(REGEX REPLACE "[^0-9a-zA-Z_]" "_" ID ${ARG_DEST})
|
||||
set(ARG_DEST_FIF "${ARG_DEST}.fif")
|
||||
add_custom_command(
|
||||
COMMENT "Generate ${ARG_DEST_FIF}"
|
||||
@ -374,10 +376,13 @@ if (NOT CMAKE_CROSSCOMPILING)
|
||||
GenFif(DEST smartcont/auto/multisig-code SOURCE smartcont/multisig-code.fc NAME multisig)
|
||||
GenFif(DEST smartcont/auto/restricted-wallet-code SOURCE smartcont/restricted-wallet-code.fc NAME restricted-wallet)
|
||||
GenFif(DEST smartcont/auto/restricted-wallet2-code SOURCE smartcont/restricted-wallet2-code.fc NAME restricted-wallet2)
|
||||
GenFif(DEST smartcont/auto/restricted-wallet3-code SOURCE smartcont/restricted-wallet3-code.fc NAME restricted-wallet3)
|
||||
|
||||
GenFif(DEST smartcont/auto/dns-manual-code SOURCE smartcont/dns-manual-code.fc NAME dns-manual)
|
||||
GenFif(DEST smartcont/auto/dns-auto-code SOURCE smartcont/dns-auto-code.fc NAME dns-auto)
|
||||
|
||||
GenFif(DEST smartcont/auto/payment-channel-code SOURCE smartcont/payment-channel-code.fc NAME payment-channel)
|
||||
|
||||
GenFif(DEST smartcont/auto/simple-wallet-ext-code SOURCE smartcont/simple-wallet-ext-code.fc NAME simple-wallet-ext)
|
||||
endif()
|
||||
|
||||
@ -420,5 +425,13 @@ if (WINGETOPT_FOUND)
|
||||
target_link_libraries_system(dump-block wingetopt)
|
||||
endif()
|
||||
|
||||
add_executable(test-weight-distr block/test-weight-distr.cpp)
|
||||
target_include_directories(test-weight-distr PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(test-weight-distr PUBLIC ton_crypto fift-lib ton_block)
|
||||
if (WINGETOPT_FOUND)
|
||||
target_link_libraries_system(test-weight-distr wingetopt)
|
||||
endif()
|
||||
|
||||
install(TARGETS fift func RUNTIME DESTINATION bin)
|
||||
install(DIRECTORY fift/lib/ DESTINATION lib/fift)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -28,6 +28,7 @@
|
||||
// uses built-in type `uint256`
|
||||
// uses built-in type `int257`
|
||||
// uses built-in type `bits256`
|
||||
// uses built-in type `bits512`
|
||||
|
||||
namespace block {
|
||||
|
||||
@ -3284,6 +3285,54 @@ struct HASH_UPDATE final : TLB_Complex {
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// headers for type `MERKLE_PROOF`
|
||||
//
|
||||
|
||||
struct MERKLE_PROOF final : TLB_Complex {
|
||||
enum { _merkle_proof };
|
||||
static constexpr int cons_len_exact = 8;
|
||||
static constexpr unsigned char cons_tag[1] = { 3 };
|
||||
const TLB &X_;
|
||||
MERKLE_PROOF(const TLB& X) : X_(X) {}
|
||||
struct Record;
|
||||
bool always_special() const override {
|
||||
return true;
|
||||
}
|
||||
int get_size(const vm::CellSlice& cs) const override {
|
||||
return 0x10118;
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override {
|
||||
return cs.advance_ext(0x10118);
|
||||
}
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool unpack(vm::CellSlice& cs, Record& data) const;
|
||||
bool unpack__merkle_proof(vm::CellSlice& cs, td::BitArray<256>& virtual_hash, int& depth, Ref<Cell>& virtual_root) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record& data) const;
|
||||
bool cell_unpack__merkle_proof(Ref<vm::Cell> cell_ref, td::BitArray<256>& virtual_hash, int& depth, Ref<Cell>& virtual_root) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record& data) const;
|
||||
bool pack__merkle_proof(vm::CellBuilder& cb, td::BitArray<256> virtual_hash, int depth, Ref<Cell> virtual_root) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record& data) const;
|
||||
bool cell_pack__merkle_proof(Ref<vm::Cell>& cell_ref, td::BitArray<256> virtual_hash, int depth, Ref<Cell> virtual_root) const;
|
||||
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
|
||||
std::ostream& print_type(std::ostream& os) const override {
|
||||
return os << "(MERKLE_PROOF " << X_ << ")";
|
||||
}
|
||||
int check_tag(const vm::CellSlice& cs) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct MERKLE_PROOF::Record {
|
||||
typedef MERKLE_PROOF type_class;
|
||||
td::BitArray<256> virtual_hash; // virtual_hash : bits256
|
||||
int depth; // depth : uint16
|
||||
Ref<Cell> virtual_root; // virtual_root : ^X
|
||||
Record() = default;
|
||||
Record(const td::BitArray<256>& _virtual_hash, int _depth, Ref<Cell> _virtual_root) : virtual_hash(_virtual_hash), depth(_depth), virtual_root(std::move(_virtual_root)) {}
|
||||
};
|
||||
|
||||
//
|
||||
// headers for type `AccountBlock`
|
||||
//
|
||||
@ -7727,19 +7776,19 @@ struct TopBlockDescrSet final : TLB_Complex {
|
||||
extern const TopBlockDescrSet t_TopBlockDescrSet;
|
||||
|
||||
//
|
||||
// headers for type `ComplaintDescr`
|
||||
// headers for type `ProducerInfo`
|
||||
//
|
||||
|
||||
struct ComplaintDescr final : TLB_Complex {
|
||||
enum { no_blk_gen };
|
||||
static constexpr int cons_len_exact = 32;
|
||||
static constexpr unsigned cons_tag[1] = { 0x7e545dda };
|
||||
struct ProducerInfo final : TLB_Complex {
|
||||
enum { prod_info };
|
||||
static constexpr int cons_len_exact = 8;
|
||||
static constexpr unsigned char cons_tag[1] = { 0x34 };
|
||||
struct Record;
|
||||
int get_size(const vm::CellSlice& cs) const override {
|
||||
return 0x202c0;
|
||||
return 0x20288;
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override {
|
||||
return cs.advance_ext(0x202c0);
|
||||
return cs.advance_ext(0x20288);
|
||||
}
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool unpack(vm::CellSlice& cs, Record& data) const;
|
||||
@ -7748,7 +7797,7 @@ struct ComplaintDescr final : TLB_Complex {
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record& data) const;
|
||||
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
|
||||
std::ostream& print_type(std::ostream& os) const override {
|
||||
return os << "ComplaintDescr";
|
||||
return os << "ProducerInfo";
|
||||
}
|
||||
int check_tag(const vm::CellSlice& cs) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
@ -7756,15 +7805,66 @@ struct ComplaintDescr final : TLB_Complex {
|
||||
}
|
||||
};
|
||||
|
||||
struct ComplaintDescr::Record {
|
||||
typedef ComplaintDescr type_class;
|
||||
struct ProducerInfo::Record {
|
||||
typedef ProducerInfo type_class;
|
||||
unsigned utime; // utime : uint32
|
||||
Ref<CellSlice> mc_blk_ref; // mc_blk_ref : ExtBlkRef
|
||||
unsigned from_utime; // from_utime : uint32
|
||||
unsigned to_utime; // to_utime : uint32
|
||||
Ref<Cell> state_proof; // state_proof : ^Cell
|
||||
Ref<Cell> prod_proof; // prod_proof : ^Cell
|
||||
Ref<Cell> state_proof; // state_proof : ^(MERKLE_PROOF Block)
|
||||
Ref<Cell> prod_proof; // prod_proof : ^(MERKLE_PROOF ShardState)
|
||||
Record() = default;
|
||||
Record(Ref<CellSlice> _mc_blk_ref, unsigned _from_utime, unsigned _to_utime, Ref<Cell> _state_proof, Ref<Cell> _prod_proof) : mc_blk_ref(std::move(_mc_blk_ref)), from_utime(_from_utime), to_utime(_to_utime), state_proof(std::move(_state_proof)), prod_proof(std::move(_prod_proof)) {}
|
||||
Record(unsigned _utime, Ref<CellSlice> _mc_blk_ref, Ref<Cell> _state_proof, Ref<Cell> _prod_proof) : utime(_utime), mc_blk_ref(std::move(_mc_blk_ref)), state_proof(std::move(_state_proof)), prod_proof(std::move(_prod_proof)) {}
|
||||
};
|
||||
|
||||
extern const ProducerInfo t_ProducerInfo;
|
||||
|
||||
//
|
||||
// headers for type `ComplaintDescr`
|
||||
//
|
||||
|
||||
struct ComplaintDescr final : TLB_Complex {
|
||||
enum { no_blk_gen, no_blk_gen_diff };
|
||||
static constexpr int cons_len_exact = 32;
|
||||
static constexpr unsigned cons_tag[2] = { 0x450e8bd9, 0xc737b0caU };
|
||||
struct Record_no_blk_gen {
|
||||
typedef ComplaintDescr type_class;
|
||||
unsigned from_utime; // from_utime : uint32
|
||||
Ref<Cell> prod_info; // prod_info : ^ProducerInfo
|
||||
Record_no_blk_gen() = default;
|
||||
Record_no_blk_gen(unsigned _from_utime, Ref<Cell> _prod_info) : from_utime(_from_utime), prod_info(std::move(_prod_info)) {}
|
||||
};
|
||||
struct Record_no_blk_gen_diff {
|
||||
typedef ComplaintDescr type_class;
|
||||
Ref<Cell> prod_info_old; // prod_info_old : ^ProducerInfo
|
||||
Ref<Cell> prod_info_new; // prod_info_new : ^ProducerInfo
|
||||
Record_no_blk_gen_diff() = default;
|
||||
Record_no_blk_gen_diff(Ref<Cell> _prod_info_old, Ref<Cell> _prod_info_new) : prod_info_old(std::move(_prod_info_old)), prod_info_new(std::move(_prod_info_new)) {}
|
||||
};
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool unpack(vm::CellSlice& cs, Record_no_blk_gen& data) const;
|
||||
bool unpack_no_blk_gen(vm::CellSlice& cs, unsigned& from_utime, Ref<Cell>& prod_info) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record_no_blk_gen& data) const;
|
||||
bool cell_unpack_no_blk_gen(Ref<vm::Cell> cell_ref, unsigned& from_utime, Ref<Cell>& prod_info) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record_no_blk_gen& data) const;
|
||||
bool pack_no_blk_gen(vm::CellBuilder& cb, unsigned from_utime, Ref<Cell> prod_info) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record_no_blk_gen& data) const;
|
||||
bool cell_pack_no_blk_gen(Ref<vm::Cell>& cell_ref, unsigned from_utime, Ref<Cell> prod_info) const;
|
||||
bool unpack(vm::CellSlice& cs, Record_no_blk_gen_diff& data) const;
|
||||
bool unpack_no_blk_gen_diff(vm::CellSlice& cs, Ref<Cell>& prod_info_old, Ref<Cell>& prod_info_new) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record_no_blk_gen_diff& data) const;
|
||||
bool cell_unpack_no_blk_gen_diff(Ref<vm::Cell> cell_ref, Ref<Cell>& prod_info_old, Ref<Cell>& prod_info_new) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record_no_blk_gen_diff& data) const;
|
||||
bool pack_no_blk_gen_diff(vm::CellBuilder& cb, Ref<Cell> prod_info_old, Ref<Cell> prod_info_new) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record_no_blk_gen_diff& data) const;
|
||||
bool cell_pack_no_blk_gen_diff(Ref<vm::Cell>& cell_ref, Ref<Cell> prod_info_old, Ref<Cell> prod_info_new) const;
|
||||
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
|
||||
std::ostream& print_type(std::ostream& os) const override {
|
||||
return os << "ComplaintDescr";
|
||||
}
|
||||
int check_tag(const vm::CellSlice& cs) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return (int)cs.prefetch_ulong(1);
|
||||
}
|
||||
};
|
||||
|
||||
extern const ComplaintDescr t_ComplaintDescr;
|
||||
@ -9035,6 +9135,344 @@ struct SmcCapability final : TLB_Complex {
|
||||
|
||||
extern const SmcCapability t_SmcCapability;
|
||||
|
||||
//
|
||||
// headers for type `ChanConfig`
|
||||
//
|
||||
|
||||
struct ChanConfig final : TLB_Complex {
|
||||
enum { chan_config };
|
||||
static constexpr int cons_len_exact = 0;
|
||||
struct Record;
|
||||
int get_size(const vm::CellSlice& cs) const override {
|
||||
return 0x20280;
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override {
|
||||
return cs.advance_ext(0x20280);
|
||||
}
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool unpack(vm::CellSlice& cs, Record& data) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record& data) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record& data) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record& data) const;
|
||||
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
|
||||
std::ostream& print_type(std::ostream& os) const override {
|
||||
return os << "ChanConfig";
|
||||
}
|
||||
int check_tag(const vm::CellSlice& cs) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct ChanConfig::Record {
|
||||
typedef ChanConfig type_class;
|
||||
unsigned init_timeout; // init_timeout : uint32
|
||||
unsigned close_timeout; // close_timeout : uint32
|
||||
td::BitArray<256> a_key; // a_key : bits256
|
||||
td::BitArray<256> b_key; // b_key : bits256
|
||||
Ref<Cell> a_addr; // a_addr : ^MsgAddressInt
|
||||
Ref<Cell> b_addr; // b_addr : ^MsgAddressInt
|
||||
unsigned long long channel_id; // channel_id : uint64
|
||||
Record() = default;
|
||||
Record(unsigned _init_timeout, unsigned _close_timeout, const td::BitArray<256>& _a_key, const td::BitArray<256>& _b_key, Ref<Cell> _a_addr, Ref<Cell> _b_addr, unsigned long long _channel_id) : init_timeout(_init_timeout), close_timeout(_close_timeout), a_key(_a_key), b_key(_b_key), a_addr(std::move(_a_addr)), b_addr(std::move(_b_addr)), channel_id(_channel_id) {}
|
||||
};
|
||||
|
||||
extern const ChanConfig t_ChanConfig;
|
||||
|
||||
//
|
||||
// headers for type `ChanState`
|
||||
//
|
||||
|
||||
struct ChanState final : TLB_Complex {
|
||||
enum { chan_state_init, chan_state_close, chan_state_payout };
|
||||
static constexpr int cons_len_exact = 3;
|
||||
struct Record_chan_state_init;
|
||||
struct Record_chan_state_close;
|
||||
struct Record_chan_state_payout {
|
||||
typedef ChanState type_class;
|
||||
Ref<CellSlice> A; // A : Grams
|
||||
Ref<CellSlice> B; // B : Grams
|
||||
Record_chan_state_payout() = default;
|
||||
Record_chan_state_payout(Ref<CellSlice> _A, Ref<CellSlice> _B) : A(std::move(_A)), B(std::move(_B)) {}
|
||||
};
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool unpack(vm::CellSlice& cs, Record_chan_state_init& data) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record_chan_state_init& data) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record_chan_state_init& data) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record_chan_state_init& data) const;
|
||||
bool unpack(vm::CellSlice& cs, Record_chan_state_close& data) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record_chan_state_close& data) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record_chan_state_close& data) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record_chan_state_close& data) const;
|
||||
bool unpack(vm::CellSlice& cs, Record_chan_state_payout& data) const;
|
||||
bool unpack_chan_state_payout(vm::CellSlice& cs, Ref<CellSlice>& A, Ref<CellSlice>& B) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record_chan_state_payout& data) const;
|
||||
bool cell_unpack_chan_state_payout(Ref<vm::Cell> cell_ref, Ref<CellSlice>& A, Ref<CellSlice>& B) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record_chan_state_payout& data) const;
|
||||
bool pack_chan_state_payout(vm::CellBuilder& cb, Ref<CellSlice> A, Ref<CellSlice> B) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record_chan_state_payout& data) const;
|
||||
bool cell_pack_chan_state_payout(Ref<vm::Cell>& cell_ref, Ref<CellSlice> A, Ref<CellSlice> B) const;
|
||||
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
|
||||
std::ostream& print_type(std::ostream& os) const override {
|
||||
return os << "ChanState";
|
||||
}
|
||||
int check_tag(const vm::CellSlice& cs) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return cs.bselect(3, 7);
|
||||
}
|
||||
};
|
||||
|
||||
struct ChanState::Record_chan_state_init {
|
||||
typedef ChanState type_class;
|
||||
bool signed_A; // signed_A : Bool
|
||||
bool signed_B; // signed_B : Bool
|
||||
Ref<CellSlice> min_A; // min_A : Grams
|
||||
Ref<CellSlice> min_B; // min_B : Grams
|
||||
unsigned expire_at; // expire_at : uint32
|
||||
Ref<CellSlice> A; // A : Grams
|
||||
Ref<CellSlice> B; // B : Grams
|
||||
Record_chan_state_init() = default;
|
||||
Record_chan_state_init(bool _signed_A, bool _signed_B, Ref<CellSlice> _min_A, Ref<CellSlice> _min_B, unsigned _expire_at, Ref<CellSlice> _A, Ref<CellSlice> _B) : signed_A(_signed_A), signed_B(_signed_B), min_A(std::move(_min_A)), min_B(std::move(_min_B)), expire_at(_expire_at), A(std::move(_A)), B(std::move(_B)) {}
|
||||
};
|
||||
|
||||
struct ChanState::Record_chan_state_close {
|
||||
typedef ChanState type_class;
|
||||
bool signed_A; // signed_A : Bool
|
||||
bool signed_B; // signed_B : Bool
|
||||
Ref<CellSlice> promise_A; // promise_A : Grams
|
||||
Ref<CellSlice> promise_B; // promise_B : Grams
|
||||
unsigned expire_at; // expire_at : uint32
|
||||
Ref<CellSlice> A; // A : Grams
|
||||
Ref<CellSlice> B; // B : Grams
|
||||
Record_chan_state_close() = default;
|
||||
Record_chan_state_close(bool _signed_A, bool _signed_B, Ref<CellSlice> _promise_A, Ref<CellSlice> _promise_B, unsigned _expire_at, Ref<CellSlice> _A, Ref<CellSlice> _B) : signed_A(_signed_A), signed_B(_signed_B), promise_A(std::move(_promise_A)), promise_B(std::move(_promise_B)), expire_at(_expire_at), A(std::move(_A)), B(std::move(_B)) {}
|
||||
};
|
||||
|
||||
extern const ChanState t_ChanState;
|
||||
|
||||
//
|
||||
// headers for type `ChanPromise`
|
||||
//
|
||||
|
||||
struct ChanPromise final : TLB_Complex {
|
||||
enum { chan_promise };
|
||||
static constexpr int cons_len_exact = 0;
|
||||
struct Record;
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool unpack(vm::CellSlice& cs, Record& data) const;
|
||||
bool unpack_chan_promise(vm::CellSlice& cs, unsigned long long& channel_id, Ref<CellSlice>& promise_A, Ref<CellSlice>& promise_B) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record& data) const;
|
||||
bool cell_unpack_chan_promise(Ref<vm::Cell> cell_ref, unsigned long long& channel_id, Ref<CellSlice>& promise_A, Ref<CellSlice>& promise_B) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record& data) const;
|
||||
bool pack_chan_promise(vm::CellBuilder& cb, unsigned long long channel_id, Ref<CellSlice> promise_A, Ref<CellSlice> promise_B) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record& data) const;
|
||||
bool cell_pack_chan_promise(Ref<vm::Cell>& cell_ref, unsigned long long channel_id, Ref<CellSlice> promise_A, Ref<CellSlice> promise_B) const;
|
||||
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
|
||||
std::ostream& print_type(std::ostream& os) const override {
|
||||
return os << "ChanPromise";
|
||||
}
|
||||
int check_tag(const vm::CellSlice& cs) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct ChanPromise::Record {
|
||||
typedef ChanPromise type_class;
|
||||
unsigned long long channel_id; // channel_id : uint64
|
||||
Ref<CellSlice> promise_A; // promise_A : Grams
|
||||
Ref<CellSlice> promise_B; // promise_B : Grams
|
||||
Record() = default;
|
||||
Record(unsigned long long _channel_id, Ref<CellSlice> _promise_A, Ref<CellSlice> _promise_B) : channel_id(_channel_id), promise_A(std::move(_promise_A)), promise_B(std::move(_promise_B)) {}
|
||||
};
|
||||
|
||||
extern const ChanPromise t_ChanPromise;
|
||||
|
||||
//
|
||||
// headers for type `ChanSignedPromise`
|
||||
//
|
||||
|
||||
struct ChanSignedPromise final : TLB_Complex {
|
||||
enum { chan_signed_promise };
|
||||
static constexpr int cons_len_exact = 0;
|
||||
struct Record {
|
||||
typedef ChanSignedPromise type_class;
|
||||
Ref<CellSlice> sig; // sig : Maybe ^bits512
|
||||
Ref<CellSlice> promise; // promise : ChanPromise
|
||||
Record() = default;
|
||||
Record(Ref<CellSlice> _sig, Ref<CellSlice> _promise) : sig(std::move(_sig)), promise(std::move(_promise)) {}
|
||||
};
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool unpack(vm::CellSlice& cs, Record& data) const;
|
||||
bool unpack_chan_signed_promise(vm::CellSlice& cs, Ref<CellSlice>& sig, Ref<CellSlice>& promise) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record& data) const;
|
||||
bool cell_unpack_chan_signed_promise(Ref<vm::Cell> cell_ref, Ref<CellSlice>& sig, Ref<CellSlice>& promise) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record& data) const;
|
||||
bool pack_chan_signed_promise(vm::CellBuilder& cb, Ref<CellSlice> sig, Ref<CellSlice> promise) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record& data) const;
|
||||
bool cell_pack_chan_signed_promise(Ref<vm::Cell>& cell_ref, Ref<CellSlice> sig, Ref<CellSlice> promise) const;
|
||||
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
|
||||
std::ostream& print_type(std::ostream& os) const override {
|
||||
return os << "ChanSignedPromise";
|
||||
}
|
||||
int check_tag(const vm::CellSlice& cs) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
extern const ChanSignedPromise t_ChanSignedPromise;
|
||||
|
||||
//
|
||||
// headers for type `ChanMsg`
|
||||
//
|
||||
|
||||
struct ChanMsg final : TLB_Complex {
|
||||
enum { chan_msg_init, chan_msg_timeout, chan_msg_close };
|
||||
static constexpr int cons_len_exact = 32;
|
||||
static constexpr unsigned cons_tag[3] = { 0x27317822, 0x43278a28, 0xf28ae183U };
|
||||
struct Record_chan_msg_init;
|
||||
struct Record_chan_msg_close;
|
||||
struct Record_chan_msg_timeout {
|
||||
typedef ChanMsg type_class;
|
||||
};
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool unpack(vm::CellSlice& cs, Record_chan_msg_init& data) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record_chan_msg_init& data) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record_chan_msg_init& data) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record_chan_msg_init& data) const;
|
||||
bool unpack(vm::CellSlice& cs, Record_chan_msg_close& data) const;
|
||||
bool unpack_chan_msg_close(vm::CellSlice& cs, Ref<CellSlice>& extra_A, Ref<CellSlice>& extra_B, Ref<CellSlice>& promise) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record_chan_msg_close& data) const;
|
||||
bool cell_unpack_chan_msg_close(Ref<vm::Cell> cell_ref, Ref<CellSlice>& extra_A, Ref<CellSlice>& extra_B, Ref<CellSlice>& promise) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record_chan_msg_close& data) const;
|
||||
bool pack_chan_msg_close(vm::CellBuilder& cb, Ref<CellSlice> extra_A, Ref<CellSlice> extra_B, Ref<CellSlice> promise) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record_chan_msg_close& data) const;
|
||||
bool cell_pack_chan_msg_close(Ref<vm::Cell>& cell_ref, Ref<CellSlice> extra_A, Ref<CellSlice> extra_B, Ref<CellSlice> promise) const;
|
||||
bool unpack(vm::CellSlice& cs, Record_chan_msg_timeout& data) const;
|
||||
bool unpack_chan_msg_timeout(vm::CellSlice& cs) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record_chan_msg_timeout& data) const;
|
||||
bool cell_unpack_chan_msg_timeout(Ref<vm::Cell> cell_ref) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record_chan_msg_timeout& data) const;
|
||||
bool pack_chan_msg_timeout(vm::CellBuilder& cb) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record_chan_msg_timeout& data) const;
|
||||
bool cell_pack_chan_msg_timeout(Ref<vm::Cell>& cell_ref) const;
|
||||
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
|
||||
std::ostream& print_type(std::ostream& os) const override {
|
||||
return os << "ChanMsg";
|
||||
}
|
||||
int check_tag(const vm::CellSlice& cs) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return cs.bselect(2, 11);
|
||||
}
|
||||
};
|
||||
|
||||
struct ChanMsg::Record_chan_msg_init {
|
||||
typedef ChanMsg type_class;
|
||||
Ref<CellSlice> inc_A; // inc_A : Grams
|
||||
Ref<CellSlice> inc_B; // inc_B : Grams
|
||||
Ref<CellSlice> min_A; // min_A : Grams
|
||||
Ref<CellSlice> min_B; // min_B : Grams
|
||||
unsigned long long channel_id; // channel_id : uint64
|
||||
Record_chan_msg_init() = default;
|
||||
Record_chan_msg_init(Ref<CellSlice> _inc_A, Ref<CellSlice> _inc_B, Ref<CellSlice> _min_A, Ref<CellSlice> _min_B, unsigned long long _channel_id) : inc_A(std::move(_inc_A)), inc_B(std::move(_inc_B)), min_A(std::move(_min_A)), min_B(std::move(_min_B)), channel_id(_channel_id) {}
|
||||
};
|
||||
|
||||
struct ChanMsg::Record_chan_msg_close {
|
||||
typedef ChanMsg type_class;
|
||||
Ref<CellSlice> extra_A; // extra_A : Grams
|
||||
Ref<CellSlice> extra_B; // extra_B : Grams
|
||||
Ref<CellSlice> promise; // promise : ChanSignedPromise
|
||||
Record_chan_msg_close() = default;
|
||||
Record_chan_msg_close(Ref<CellSlice> _extra_A, Ref<CellSlice> _extra_B, Ref<CellSlice> _promise) : extra_A(std::move(_extra_A)), extra_B(std::move(_extra_B)), promise(std::move(_promise)) {}
|
||||
};
|
||||
|
||||
extern const ChanMsg t_ChanMsg;
|
||||
|
||||
//
|
||||
// headers for type `ChanSignedMsg`
|
||||
//
|
||||
|
||||
struct ChanSignedMsg final : TLB_Complex {
|
||||
enum { chan_signed_msg };
|
||||
static constexpr int cons_len_exact = 0;
|
||||
struct Record;
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool unpack(vm::CellSlice& cs, Record& data) const;
|
||||
bool unpack_chan_signed_msg(vm::CellSlice& cs, Ref<CellSlice>& sig_A, Ref<CellSlice>& sig_B, Ref<CellSlice>& msg) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record& data) const;
|
||||
bool cell_unpack_chan_signed_msg(Ref<vm::Cell> cell_ref, Ref<CellSlice>& sig_A, Ref<CellSlice>& sig_B, Ref<CellSlice>& msg) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record& data) const;
|
||||
bool pack_chan_signed_msg(vm::CellBuilder& cb, Ref<CellSlice> sig_A, Ref<CellSlice> sig_B, Ref<CellSlice> msg) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record& data) const;
|
||||
bool cell_pack_chan_signed_msg(Ref<vm::Cell>& cell_ref, Ref<CellSlice> sig_A, Ref<CellSlice> sig_B, Ref<CellSlice> msg) const;
|
||||
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
|
||||
std::ostream& print_type(std::ostream& os) const override {
|
||||
return os << "ChanSignedMsg";
|
||||
}
|
||||
int check_tag(const vm::CellSlice& cs) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct ChanSignedMsg::Record {
|
||||
typedef ChanSignedMsg type_class;
|
||||
Ref<CellSlice> sig_A; // sig_A : Maybe ^bits512
|
||||
Ref<CellSlice> sig_B; // sig_B : Maybe ^bits512
|
||||
Ref<CellSlice> msg; // msg : ChanMsg
|
||||
Record() = default;
|
||||
Record(Ref<CellSlice> _sig_A, Ref<CellSlice> _sig_B, Ref<CellSlice> _msg) : sig_A(std::move(_sig_A)), sig_B(std::move(_sig_B)), msg(std::move(_msg)) {}
|
||||
};
|
||||
|
||||
extern const ChanSignedMsg t_ChanSignedMsg;
|
||||
|
||||
//
|
||||
// headers for type `ChanData`
|
||||
//
|
||||
|
||||
struct ChanData final : TLB_Complex {
|
||||
enum { chan_data };
|
||||
static constexpr int cons_len_exact = 0;
|
||||
struct Record {
|
||||
typedef ChanData type_class;
|
||||
Ref<Cell> config; // config : ^ChanConfig
|
||||
Ref<Cell> state; // state : ^ChanState
|
||||
Record() = default;
|
||||
Record(Ref<Cell> _config, Ref<Cell> _state) : config(std::move(_config)), state(std::move(_state)) {}
|
||||
};
|
||||
int get_size(const vm::CellSlice& cs) const override {
|
||||
return 0x20000;
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override {
|
||||
return cs.advance_ext(0x20000);
|
||||
}
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool unpack(vm::CellSlice& cs, Record& data) const;
|
||||
bool unpack_chan_data(vm::CellSlice& cs, Ref<Cell>& config, Ref<Cell>& state) const;
|
||||
bool cell_unpack(Ref<vm::Cell> cell_ref, Record& data) const;
|
||||
bool cell_unpack_chan_data(Ref<vm::Cell> cell_ref, Ref<Cell>& config, Ref<Cell>& state) const;
|
||||
bool pack(vm::CellBuilder& cb, const Record& data) const;
|
||||
bool pack_chan_data(vm::CellBuilder& cb, Ref<Cell> config, Ref<Cell> state) const;
|
||||
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record& data) const;
|
||||
bool cell_pack_chan_data(Ref<vm::Cell>& cell_ref, Ref<Cell> config, Ref<Cell> state) const;
|
||||
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
|
||||
std::ostream& print_type(std::ostream& os) const override {
|
||||
return os << "ChanData";
|
||||
}
|
||||
int check_tag(const vm::CellSlice& cs) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
extern const ChanData t_ChanData;
|
||||
|
||||
// declarations of constant types used
|
||||
|
||||
// ## 1
|
||||
@ -9123,6 +9561,8 @@ extern const HASH_UPDATE t_HASH_UPDATE_Account;
|
||||
extern const RefT t_Ref_HASH_UPDATE_Account;
|
||||
// ^TransactionDescr
|
||||
extern const RefT t_Ref_TransactionDescr;
|
||||
// uint16
|
||||
extern const UInt t_uint16;
|
||||
// HashmapAug 64 ^Transaction CurrencyCollection
|
||||
extern const HashmapAug t_HashmapAug_64_Ref_Transaction_CurrencyCollection;
|
||||
// HashmapAugE 256 AccountBlock CurrencyCollection
|
||||
@ -9134,9 +9574,7 @@ extern const Maybe t_Maybe_VarUInteger_3;
|
||||
// Maybe int32
|
||||
extern const Maybe t_Maybe_int32;
|
||||
// ^[$_ gas_used:(VarUInteger 7) gas_limit:(VarUInteger 7) gas_credit:(Maybe (VarUInteger 3)) mode:int8 exit_code:int32 exit_arg:(Maybe int32) vm_steps:uint32 vm_init_state_hash:bits256 vm_final_state_hash:bits256 ]
|
||||
extern const RefT t_Ref_TYPE_1625;
|
||||
// uint16
|
||||
extern const UInt t_uint16;
|
||||
extern const RefT t_Ref_TYPE_1626;
|
||||
// Maybe TrStoragePhase
|
||||
extern const Maybe t_Maybe_TrStoragePhase;
|
||||
// Maybe TrCreditPhase
|
||||
@ -9168,7 +9606,7 @@ extern const HashmapE t_HashmapE_256_LibDescr;
|
||||
// Maybe BlkMasterInfo
|
||||
extern const Maybe t_Maybe_BlkMasterInfo;
|
||||
// ^[$_ overload_history:uint64 underload_history:uint64 total_balance:CurrencyCollection total_validator_fees:CurrencyCollection libraries:(HashmapE 256 LibDescr) master_ref:(Maybe BlkMasterInfo) ]
|
||||
extern const RefT t_Ref_TYPE_1639;
|
||||
extern const RefT t_Ref_TYPE_1640;
|
||||
// ^McStateExtra
|
||||
extern const RefT t_Ref_McStateExtra;
|
||||
// Maybe ^McStateExtra
|
||||
@ -9206,13 +9644,13 @@ extern const RefT t_Ref_McBlockExtra;
|
||||
// Maybe ^McBlockExtra
|
||||
extern const Maybe t_Maybe_Ref_McBlockExtra;
|
||||
// ^[$_ from_prev_blk:CurrencyCollection to_next_blk:CurrencyCollection imported:CurrencyCollection exported:CurrencyCollection ]
|
||||
extern const RefT t_Ref_TYPE_1650;
|
||||
// ^[$_ fees_imported:CurrencyCollection recovered:CurrencyCollection created:CurrencyCollection minted:CurrencyCollection ]
|
||||
extern const RefT t_Ref_TYPE_1651;
|
||||
// ^[$_ fees_imported:CurrencyCollection recovered:CurrencyCollection created:CurrencyCollection minted:CurrencyCollection ]
|
||||
extern const RefT t_Ref_TYPE_1652;
|
||||
// ## 3
|
||||
extern const NatWidth t_natwidth_3;
|
||||
// ^[$_ fees_collected:CurrencyCollection funds_created:CurrencyCollection ]
|
||||
extern const RefT t_Ref_TYPE_1655;
|
||||
extern const RefT t_Ref_TYPE_1656;
|
||||
// BinTree ShardDescr
|
||||
extern const BinTree t_BinTree_ShardDescr;
|
||||
// ^(BinTree ShardDescr)
|
||||
@ -9236,7 +9674,7 @@ extern const NatWidth t_natwidth_16;
|
||||
// Maybe ExtBlkRef
|
||||
extern const Maybe t_Maybe_ExtBlkRef;
|
||||
// ^[$_ flags:(## 16) {<= flags 1} validator_info:ValidatorInfo prev_blocks:OldMcBlocksInfo after_key_block:Bool last_key_block:(Maybe ExtBlkRef) block_create_stats:flags.0?BlockCreateStats ]
|
||||
extern const RefT t_Ref_TYPE_1669;
|
||||
extern const RefT t_Ref_TYPE_1670;
|
||||
// ^SignedCertificate
|
||||
extern const RefT t_Ref_SignedCertificate;
|
||||
// HashmapE 16 CryptoSignaturePair
|
||||
@ -9244,7 +9682,7 @@ extern const HashmapE t_HashmapE_16_CryptoSignaturePair;
|
||||
// Maybe ^InMsg
|
||||
extern const Maybe t_Maybe_Ref_InMsg;
|
||||
// ^[$_ prev_blk_signatures:(HashmapE 16 CryptoSignaturePair) recover_create_msg:(Maybe ^InMsg) mint_msg:(Maybe ^InMsg) ]
|
||||
extern const RefT t_Ref_TYPE_1677;
|
||||
extern const RefT t_Ref_TYPE_1678;
|
||||
// Hashmap 16 ValidatorDescr
|
||||
extern const Hashmap t_Hashmap_16_ValidatorDescr;
|
||||
// HashmapE 16 ValidatorDescr
|
||||
@ -9289,6 +9727,16 @@ extern const Maybe t_Maybe_Ref_BlockSignatures;
|
||||
extern const RefT t_Ref_TopBlockDescr;
|
||||
// HashmapE 96 ^TopBlockDescr
|
||||
extern const HashmapE t_HashmapE_96_Ref_TopBlockDescr;
|
||||
// MERKLE_PROOF Block
|
||||
extern const MERKLE_PROOF t_MERKLE_PROOF_Block;
|
||||
// ^(MERKLE_PROOF Block)
|
||||
extern const RefT t_Ref_MERKLE_PROOF_Block;
|
||||
// MERKLE_PROOF ShardState
|
||||
extern const MERKLE_PROOF t_MERKLE_PROOF_ShardState;
|
||||
// ^(MERKLE_PROOF ShardState)
|
||||
extern const RefT t_Ref_MERKLE_PROOF_ShardState;
|
||||
// ^ProducerInfo
|
||||
extern const RefT t_Ref_ProducerInfo;
|
||||
// ^ComplaintDescr
|
||||
extern const RefT t_Ref_ComplaintDescr;
|
||||
// ^ValidatorComplaint
|
||||
@ -9306,7 +9754,7 @@ extern const NatWidth t_natwidth_24;
|
||||
// HashmapE 4 VmStackValue
|
||||
extern const HashmapE t_HashmapE_4_VmStackValue;
|
||||
// ^[$_ max_limit:int64 cur_limit:int64 credit:int64 ]
|
||||
extern const RefT t_Ref_TYPE_1715;
|
||||
extern const RefT t_Ref_TYPE_1717;
|
||||
// HashmapE 256 ^Cell
|
||||
extern const HashmapE t_HashmapE_256_Ref_Cell;
|
||||
// uint13
|
||||
@ -9325,6 +9773,18 @@ extern const RefT t_Ref_VmCont;
|
||||
extern const RefT t_Ref_DNSRecord;
|
||||
// HashmapE 16 ^DNSRecord
|
||||
extern const HashmapE t_HashmapE_16_Ref_DNSRecord;
|
||||
// ^MsgAddressInt
|
||||
extern const RefT t_Ref_MsgAddressInt;
|
||||
// bits512
|
||||
extern const Bits t_bits512;
|
||||
// ^bits512
|
||||
extern const RefT t_Ref_bits512;
|
||||
// Maybe ^bits512
|
||||
extern const Maybe t_Maybe_Ref_bits512;
|
||||
// ^ChanConfig
|
||||
extern const RefT t_Ref_ChanConfig;
|
||||
// ^ChanState
|
||||
extern const RefT t_Ref_ChanState;
|
||||
|
||||
// declaration of type name registration function
|
||||
extern bool register_simple_types(std::function<bool(const char*, const TLB*)> func);
|
||||
|
@ -241,6 +241,14 @@ bool MsgAddressInt::extract_std_address(vm::CellSlice& cs, ton::WorkchainId& wor
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MsgAddressInt::extract_std_address(Ref<vm::CellSlice> cs_ref, block::StdAddress& addr, bool rewrite) const {
|
||||
return extract_std_address(std::move(cs_ref), addr.workchain, addr.addr, rewrite);
|
||||
}
|
||||
|
||||
bool MsgAddressInt::extract_std_address(vm::CellSlice& cs, block::StdAddress& addr, bool rewrite) const {
|
||||
return extract_std_address(cs, addr.workchain, addr.addr, rewrite);
|
||||
}
|
||||
|
||||
bool MsgAddressInt::store_std_address(vm::CellBuilder& cb, ton::WorkchainId workchain,
|
||||
const ton::StdSmcAddress& addr) const {
|
||||
if (workchain >= -128 && workchain < 128) {
|
||||
@ -263,6 +271,14 @@ Ref<vm::CellSlice> MsgAddressInt::pack_std_address(ton::WorkchainId workchain, c
|
||||
}
|
||||
}
|
||||
|
||||
bool MsgAddressInt::store_std_address(vm::CellBuilder& cb, const block::StdAddress& addr) const {
|
||||
return store_std_address(cb, addr.workchain, addr.addr);
|
||||
}
|
||||
|
||||
Ref<vm::CellSlice> MsgAddressInt::pack_std_address(const block::StdAddress& addr) const {
|
||||
return pack_std_address(addr.workchain, addr.addr);
|
||||
}
|
||||
|
||||
const MsgAddressInt t_MsgAddressInt;
|
||||
|
||||
bool MsgAddress::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
|
@ -298,8 +298,13 @@ struct MsgAddressInt final : TLB_Complex {
|
||||
bool rewrite = true) const;
|
||||
bool extract_std_address(vm::CellSlice& cs, ton::WorkchainId& workchain, ton::StdSmcAddress& addr,
|
||||
bool rewrite = true) const;
|
||||
bool extract_std_address(Ref<vm::CellSlice> cs_ref, block::StdAddress& addr, bool rewrite = true) const;
|
||||
bool extract_std_address(vm::CellSlice& cs, block::StdAddress& addr, bool rewrite = true) const;
|
||||
bool store_std_address(vm::CellBuilder& cb, ton::WorkchainId workchain, const ton::StdSmcAddress& addr) const;
|
||||
Ref<vm::CellSlice> pack_std_address(ton::WorkchainId workchain, const ton::StdSmcAddress& addr) const;
|
||||
|
||||
bool store_std_address(vm::CellBuilder& cb, const block::StdAddress& addr) const;
|
||||
Ref<vm::CellSlice> pack_std_address(const block::StdAddress& addr) const;
|
||||
};
|
||||
|
||||
extern const MsgAddressInt t_MsgAddressInt;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/tl_storers.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/Random.h"
|
||||
|
||||
namespace block {
|
||||
using namespace std::literals::string_literals;
|
||||
@ -369,14 +370,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)));
|
||||
}
|
||||
@ -1546,6 +1547,89 @@ bool unpack_CreatorStats(Ref<vm::CellSlice> cs, DiscountedCounter& mc_cnt, Disco
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Monte Carlo simulator for computing the share of shardchain blocks generated by each validator
|
||||
*
|
||||
*/
|
||||
|
||||
bool MtCarloComputeShare::compute() {
|
||||
ok = false;
|
||||
if (W.size() >= (1U << 31) || W.empty()) {
|
||||
return false;
|
||||
}
|
||||
K = std::min(K, N);
|
||||
if (K <= 0 || iterations <= 0) {
|
||||
return false;
|
||||
}
|
||||
double tot_weight = 0., acc = 0.;
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (W[i] <= 0.) {
|
||||
return false;
|
||||
}
|
||||
tot_weight += W[i];
|
||||
}
|
||||
CW.resize(N);
|
||||
RW.resize(N);
|
||||
for (int i = 0; i < N; i++) {
|
||||
CW[i] = acc;
|
||||
acc += W[i] /= tot_weight;
|
||||
RW[i] = 0.;
|
||||
}
|
||||
R0 = 0.;
|
||||
H.resize(N);
|
||||
A.resize(K);
|
||||
for (long long it = 0; it < iterations; ++it) {
|
||||
gen_vset();
|
||||
}
|
||||
for (int i = 0; i < N; i++) {
|
||||
RW[i] = W[i] * (RW[i] + R0) / (double)iterations;
|
||||
}
|
||||
return ok = true;
|
||||
}
|
||||
|
||||
void MtCarloComputeShare::gen_vset() {
|
||||
double total_wt = 1.;
|
||||
int hc = 0;
|
||||
for (int i = 0; i < K; i++) {
|
||||
CHECK(total_wt > 0);
|
||||
double inv_wt = 1. / total_wt;
|
||||
R0 += inv_wt;
|
||||
for (int j = 0; j < i; j++) {
|
||||
RW[A[j]] -= inv_wt;
|
||||
}
|
||||
// double p = drand48() * total_wt;
|
||||
double p = (double)td::Random::fast_uint64() * total_wt / (1. * (1LL << 32) * (1LL << 32));
|
||||
for (int h = 0; h < hc; h++) {
|
||||
if (p < H[h].first) {
|
||||
break;
|
||||
}
|
||||
p += H[h].second;
|
||||
}
|
||||
int a = -1, b = N, c;
|
||||
while (b - a > 1) {
|
||||
c = ((a + b) >> 1);
|
||||
if (CW[c] <= p) {
|
||||
a = c;
|
||||
} else {
|
||||
b = c;
|
||||
}
|
||||
}
|
||||
CHECK(a >= 0 && a < N);
|
||||
CHECK(total_wt >= W[a]);
|
||||
total_wt -= W[a];
|
||||
double x = CW[a];
|
||||
c = hc++;
|
||||
while (c > 0 && H[c - 1].first > x) {
|
||||
H[c] = H[c - 1];
|
||||
--c;
|
||||
}
|
||||
H[c].first = x;
|
||||
H[c].second = W[a];
|
||||
A[i] = a;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Other block-related functions
|
||||
@ -1723,7 +1807,7 @@ ton::AccountIdPrefixFull interpolate_addr(const ton::AccountIdPrefixFull& src, c
|
||||
unsigned long long mask = (std::numeric_limits<td::uint64>::max() >> (d - 32));
|
||||
return ton::AccountIdPrefixFull{dest.workchain, (dest.account_id_prefix & ~mask) | (src.account_id_prefix & mask)};
|
||||
} else {
|
||||
int mask = (-1 >> d);
|
||||
int mask = (int)(~0U >> d);
|
||||
return ton::AccountIdPrefixFull{(dest.workchain & ~mask) | (src.workchain & mask), src.account_id_prefix};
|
||||
}
|
||||
}
|
||||
|
@ -163,12 +163,12 @@ struct MsgProcessedUpto {
|
||||
MsgProcessedUpto(ton::ShardId _shard, ton::BlockSeqno _mcseqno, ton::LogicalTime _lt, td::ConstBitPtr _hash)
|
||||
: shard(_shard), mc_seqno(_mcseqno), last_inmsg_lt(_lt), last_inmsg_hash(_hash) {
|
||||
}
|
||||
bool operator<(const MsgProcessedUpto& other) const & {
|
||||
bool operator<(const MsgProcessedUpto& other) const& {
|
||||
return shard < other.shard || (shard == other.shard && mc_seqno < other.mc_seqno);
|
||||
}
|
||||
bool contains(const MsgProcessedUpto& other) const &;
|
||||
bool contains(const MsgProcessedUpto& other) const&;
|
||||
bool 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&;
|
||||
// NB: this is for checking whether we have already imported an internal message
|
||||
bool already_processed(const EnqueuedMsgDescr& msg) const;
|
||||
bool can_check_processed() const {
|
||||
@ -596,6 +596,62 @@ struct BlockProofChain {
|
||||
td::Status validate(td::CancellationToken cancellation_token = {});
|
||||
};
|
||||
|
||||
// compute the share of shardchain blocks generated by each validator using Monte Carlo method
|
||||
class MtCarloComputeShare {
|
||||
int K, N;
|
||||
long long iterations;
|
||||
std::vector<double> W;
|
||||
std::vector<double> CW, RW;
|
||||
std::vector<std::pair<double, double>> H;
|
||||
std::vector<int> A;
|
||||
double R0;
|
||||
bool ok;
|
||||
|
||||
public:
|
||||
MtCarloComputeShare(int subset_size, const std::vector<double>& weights, long long iteration_count = 1000000)
|
||||
: K(subset_size), N((int)weights.size()), iterations(iteration_count), W(weights), ok(false) {
|
||||
compute();
|
||||
}
|
||||
MtCarloComputeShare(int subset_size, int set_size, const double* weights, long long iteration_count = 1000000)
|
||||
: K(subset_size), N(set_size), iterations(iteration_count), W(weights, weights + set_size), ok(false) {
|
||||
compute();
|
||||
}
|
||||
bool is_ok() const {
|
||||
return ok;
|
||||
}
|
||||
const double* share_array() const {
|
||||
return ok ? RW.data() : nullptr;
|
||||
}
|
||||
const double* weights_array() const {
|
||||
return ok ? W.data() : nullptr;
|
||||
}
|
||||
double operator[](int i) const {
|
||||
return ok ? RW.at(i) : -1.;
|
||||
}
|
||||
double share(int i) const {
|
||||
return ok ? RW.at(i) : -1.;
|
||||
}
|
||||
double weight(int i) const {
|
||||
return ok ? W.at(i) : -1.;
|
||||
}
|
||||
int size() const {
|
||||
return N;
|
||||
}
|
||||
int subset_size() const {
|
||||
return K;
|
||||
}
|
||||
long long performed_iterations() const {
|
||||
return iterations;
|
||||
}
|
||||
|
||||
private:
|
||||
bool set_error() {
|
||||
return ok = false;
|
||||
}
|
||||
bool compute();
|
||||
void gen_vset();
|
||||
};
|
||||
|
||||
int filter_out_msg_queue(vm::AugmentedDictionary& out_queue, ton::ShardIdFull old_shard, ton::ShardIdFull subshard);
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const ShardId& shard_id);
|
||||
|
@ -272,6 +272,7 @@ transaction$0111 account_addr:bits256 lt:uint64
|
||||
old:^X new:^X = MERKLE_UPDATE X;
|
||||
update_hashes#72 {X:Type} old_hash:bits256 new_hash:bits256
|
||||
= HASH_UPDATE X;
|
||||
!merkle_proof#03 {X:Type} virtual_hash:bits256 depth:uint16 virtual_root:^X = MERKLE_PROOF X;
|
||||
|
||||
acc_trans#5 account_addr:bits256
|
||||
transactions:(HashmapAug 64 ^Transaction CurrencyCollection)
|
||||
@ -731,7 +732,10 @@ top_block_descr_set#4ac789f3 collection:(HashmapE 96 ^TopBlockDescr) = TopBlockD
|
||||
//
|
||||
// VALIDATOR MISBEHAVIOR COMPLAINTS
|
||||
//
|
||||
no_blk_gen mc_blk_ref:ExtBlkRef from_utime:uint32 to_utime:uint32 state_proof:^Cell prod_proof:^Cell = ComplaintDescr;
|
||||
prod_info#34 utime:uint32 mc_blk_ref:ExtBlkRef state_proof:^(MERKLE_PROOF Block)
|
||||
prod_proof:^(MERKLE_PROOF ShardState) = ProducerInfo;
|
||||
no_blk_gen from_utime:uint32 prod_info:^ProducerInfo = ComplaintDescr;
|
||||
no_blk_gen_diff prod_info_old:^ProducerInfo prod_info_new:^ProducerInfo = ComplaintDescr;
|
||||
validator_complaint#bc validator_pubkey:uint256 description:^ComplaintDescr created_at:uint32 severity:uint8 reward_addr:uint256 paid:Grams suggested_fine:Grams suggested_fine_part:uint32 = ValidatorComplaint;
|
||||
complaint_status#2d complaint:^ValidatorComplaint voters:(HashmapE 16 True) vset_id:uint256 weight_remaining:int64 = ValidatorComplaintStatus;
|
||||
|
||||
@ -808,3 +812,25 @@ cap_method_pubkey#71f4 = SmcCapability;
|
||||
cap_is_wallet#2177 = SmcCapability;
|
||||
cap_name#ff name:Text = SmcCapability;
|
||||
|
||||
//
|
||||
// PAYMENT CHANNELS
|
||||
//
|
||||
|
||||
chan_config$_ init_timeout:uint32 close_timeout:uint32 a_key:bits256 b_key:bits256
|
||||
a_addr:^MsgAddressInt b_addr:^MsgAddressInt channel_id:uint64 = ChanConfig;
|
||||
|
||||
chan_state_init$000 signed_A:Bool signed_B:Bool min_A:Grams min_B:Grams expire_at:uint32 A:Grams B:Grams = ChanState;
|
||||
chan_state_close$001 signed_A:Bool signed_B:Bool promise_A:Grams promise_B:Grams expire_at:uint32 A:Grams B:Grams = ChanState;
|
||||
chan_state_payout$010 A:Grams B:Grams = ChanState;
|
||||
|
||||
chan_promise$_ channel_id:uint64 promise_A:Grams promise_B:Grams = ChanPromise;
|
||||
chan_signed_promise#_ sig:(Maybe ^bits512) promise:ChanPromise = ChanSignedPromise;
|
||||
|
||||
chan_msg_init#27317822 inc_A:Grams inc_B:Grams min_A:Grams min_B:Grams channel_id:uint64 = ChanMsg;
|
||||
chan_msg_close#f28ae183 extra_A:Grams extra_B:Grams promise:ChanSignedPromise = ChanMsg;
|
||||
chan_msg_timeout#43278a28 = ChanMsg;
|
||||
|
||||
chan_signed_msg$_ sig_A:(Maybe ^bits512) sig_B:(Maybe ^bits512) msg:ChanMsg = ChanSignedMsg;
|
||||
|
||||
chan_data$_ config:^ChanConfig state:^ChanState = ChanData;
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
namespace block {
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
td::Status check_block_header_proof(td::Ref<vm::Cell> root, ton::BlockIdExt blkid, ton::Bits256* store_shard_hash_to,
|
||||
td::Status check_block_header_proof(td::Ref<vm::Cell> root, ton::BlockIdExt blkid, ton::Bits256* store_state_hash_to,
|
||||
bool check_state_hash, td::uint32* save_utime, ton::LogicalTime* save_lt) {
|
||||
ton::RootHash vhash{root->get_hash().bits()};
|
||||
if (vhash != blkid.root_hash) {
|
||||
@ -53,7 +53,7 @@ td::Status check_block_header_proof(td::Ref<vm::Cell> root, ton::BlockIdExt blki
|
||||
if (save_lt) {
|
||||
*save_lt = info.end_lt;
|
||||
}
|
||||
if (store_shard_hash_to) {
|
||||
if (store_state_hash_to) {
|
||||
vm::CellSlice upd_cs{vm::NoVmSpec(), blk.state_update};
|
||||
if (!(upd_cs.is_special() && upd_cs.prefetch_long(8) == 4 // merkle update
|
||||
&& upd_cs.size_ext() == 0x20228)) {
|
||||
@ -61,11 +61,11 @@ td::Status check_block_header_proof(td::Ref<vm::Cell> root, ton::BlockIdExt blki
|
||||
}
|
||||
auto upd_hash = upd_cs.prefetch_ref(1)->get_hash(0);
|
||||
if (!check_state_hash) {
|
||||
*store_shard_hash_to = upd_hash.bits();
|
||||
} else if (store_shard_hash_to->compare(upd_hash.bits())) {
|
||||
*store_state_hash_to = upd_hash.bits();
|
||||
} else if (store_state_hash_to->compare(upd_hash.bits())) {
|
||||
return td::Status::Error(PSTRING() << "state hash mismatch in block header of " << blkid.to_str()
|
||||
<< " : header declares " << upd_hash.bits().to_hex(256) << " expected "
|
||||
<< store_shard_hash_to->to_hex());
|
||||
<< store_state_hash_to->to_hex());
|
||||
}
|
||||
}
|
||||
return td::Status::OK();
|
||||
|
@ -25,7 +25,7 @@ namespace block {
|
||||
using td::Ref;
|
||||
|
||||
td::Status check_block_header_proof(td::Ref<vm::Cell> root, ton::BlockIdExt blkid,
|
||||
ton::Bits256* store_shard_hash_to = nullptr, bool check_state_hash = false,
|
||||
ton::Bits256* store_state_hash_to = nullptr, bool check_state_hash = false,
|
||||
td::uint32* save_utime = nullptr, ton::LogicalTime* save_lt = nullptr);
|
||||
td::Status check_shard_proof(ton::BlockIdExt blk, ton::BlockIdExt shard_blk, td::Slice shard_proof);
|
||||
td::Status check_account_proof(td::Slice proof, ton::BlockIdExt shard_blk, const block::StdAddress& addr,
|
||||
|
@ -1785,6 +1785,22 @@ std::vector<ton::ValidatorDescr> ValidatorSet::export_validator_set() const {
|
||||
return l;
|
||||
}
|
||||
|
||||
std::map<ton::Bits256, int> ValidatorSet::compute_validator_map() const {
|
||||
std::map<ton::Bits256, int> res;
|
||||
for (int i = 0; i < (int)list.size(); i++) {
|
||||
res.emplace(list[i].pubkey.as_bits256(), i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<double> ValidatorSet::export_scaled_validator_weights() const {
|
||||
std::vector<double> res;
|
||||
for (const auto& node : list) {
|
||||
res.push_back((double)node.weight / (double)total_weight);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<ton::ValidatorDescr> Config::do_compute_validator_set(const block::CatchainValidatorsConfig& ccv_conf,
|
||||
ton::ShardIdFull shard,
|
||||
const block::ValidatorSet& vset, ton::UnixTime time,
|
||||
|
@ -71,6 +71,8 @@ struct ValidatorSet {
|
||||
}
|
||||
const ValidatorDescr& at_weight(td::uint64 weight_pos) const;
|
||||
std::vector<ton::ValidatorDescr> export_validator_set() const;
|
||||
std::map<ton::Bits256, int> compute_validator_map() const;
|
||||
std::vector<double> export_scaled_validator_weights() const;
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
@ -1,248 +0,0 @@
|
||||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
TON Blockchain is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
You must obey the GNU General Public License in all respects for all
|
||||
of the code used other than OpenSSL. If you modify file(s) with this
|
||||
exception, you may extend this exception to your version of the file(s),
|
||||
but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "block/block.h"
|
||||
#include "vm/boc.h"
|
||||
#include <iostream>
|
||||
#include "block-db.h"
|
||||
#include "block-auto.h"
|
||||
#include "block-parse.h"
|
||||
#include "vm/cp0.h"
|
||||
#include <getopt.h>
|
||||
|
||||
using td::Ref;
|
||||
|
||||
int verbosity;
|
||||
|
||||
struct IntError {
|
||||
std::string err_msg;
|
||||
IntError(std::string _msg) : err_msg(_msg) {
|
||||
}
|
||||
IntError(const char* _msg) : err_msg(_msg) {
|
||||
}
|
||||
};
|
||||
|
||||
td::Ref<vm::Cell> load_boc(std::string filename) {
|
||||
std::cerr << "loading bag-of-cell file " << filename << std::endl;
|
||||
auto bytes_res = block::load_binary_file(filename);
|
||||
if (bytes_res.is_error()) {
|
||||
throw IntError{PSTRING() << "cannot load file `" << filename << "` : " << bytes_res.move_as_error()};
|
||||
}
|
||||
vm::BagOfCells boc;
|
||||
auto res = boc.deserialize(bytes_res.move_as_ok());
|
||||
if (res.is_error()) {
|
||||
throw IntError{PSTRING() << "cannot deserialize bag-of-cells " << res.move_as_error()};
|
||||
}
|
||||
if (res.move_as_ok() <= 0 || boc.get_root_cell().is_null()) {
|
||||
throw IntError{"cannot deserialize bag-of-cells "};
|
||||
}
|
||||
return boc.get_root_cell();
|
||||
}
|
||||
|
||||
void test1() {
|
||||
block::ShardId id{ton::masterchainId}, id2{ton::basechainId, 0x11efULL << 48};
|
||||
std::cout << '[' << id << "][" << id2 << ']' << std::endl;
|
||||
vm::CellBuilder cb;
|
||||
cb << id << id2;
|
||||
std::cout << "ShardIdent.pack() = " << block::tlb::t_ShardIdent.pack(cb, {12, 3, 0x3aeULL << 52}) << std::endl;
|
||||
std::cout << cb << std::endl;
|
||||
auto cref = cb.finalize();
|
||||
td::Ref<vm::CellSlice> cs{true, cref}, cs2;
|
||||
block::ShardId id3{cs.write()}, id4, id5;
|
||||
cs >> id4 >> id5;
|
||||
std::cout << '[' << id3 << "][" << id4 << "][" << id5 << ']' << std::endl;
|
||||
vm::CellSlice csl{std::move(cref)};
|
||||
std::cout << "ShardIdent.get_size() = " << block::tlb::t_ShardIdent.get_size(csl) << std::endl;
|
||||
std::cout << "MsgAddress.get_size() = " << block::tlb::t_MsgAddress.get_size(csl) << std::endl;
|
||||
std::cout << "Grams.get_size() = " << block::tlb::t_Grams.get_size(csl) << std::endl;
|
||||
std::cout << "Grams.as_integer() = " << block::tlb::t_Grams.as_integer(csl) << std::endl;
|
||||
(csl + 8).print_rec(std::cout);
|
||||
std::cout << "Grams.get_size() = " << block::tlb::t_Grams.get_size(csl + 8) << std::endl;
|
||||
std::cout << "Grams.as_integer() = " << block::tlb::t_Grams.as_integer(csl + 8) << std::endl;
|
||||
|
||||
vm::CellSlice csl2{csl};
|
||||
block::gen::ShardIdent::Record sh_id;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
std::cout << csl2 << std::endl;
|
||||
bool ok = tlb::unpack(csl2, sh_id);
|
||||
std::cout << "block::gen::ShardIdent.unpack() = " << ok << std::endl;
|
||||
if (ok) {
|
||||
std::cout << " (shard_ident shard_pfx_bits:" << sh_id.shard_pfx_bits << " workchain_id:" << sh_id.workchain_id
|
||||
<< " shard_prefix:" << std::hex << sh_id.shard_prefix << std::dec << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
block::tlb::ShardIdent::Record shard_id;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
std::cout << "ShardIdent.validate() = " << block::tlb::t_ShardIdent.validate(csl) << std::endl;
|
||||
csl.print_rec(std::cerr);
|
||||
csl.dump(std::cerr, 7);
|
||||
std::cout << "ShardIdent.unpack() = " << block::tlb::t_ShardIdent.unpack(csl, shard_id) << std::endl;
|
||||
if (shard_id.is_valid()) {
|
||||
std::cout << "shard_pfx_bits:" << shard_id.shard_pfx_bits << " workchain_id:" << shard_id.workchain_id
|
||||
<< " shard_prefix:" << shard_id.shard_prefix << std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip(csl) << std::endl;
|
||||
std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip(csl) << std::endl;
|
||||
std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip(csl) << std::endl;
|
||||
using namespace td::literals;
|
||||
std::cout << "Grams.store_intval(239) = " << block::tlb::t_Grams.store_integer_value(cb, "239"_i256) << std::endl;
|
||||
std::cout << "Grams.store_intval(17239) = " << block::tlb::t_Grams.store_integer_value(cb, "17239"_i256) << std::endl;
|
||||
std::cout << "Grams.store_intval(-17) = " << block::tlb::t_Grams.store_integer_value(cb, "-17"_i256) << std::endl;
|
||||
std::cout << "Grams.store_intval(0) = " << block::tlb::t_Grams.store_integer_value(cb, "0"_i256) << std::endl;
|
||||
std::cout << cb << std::endl;
|
||||
cs = td::Ref<vm::CellSlice>{true, cb.finalize()};
|
||||
std::cout << "Grams.store_intval(666) = " << block::tlb::t_Grams.store_integer_value(cb, "666"_i256) << std::endl;
|
||||
std::cout << cb << std::endl;
|
||||
cs2 = td::Ref<vm::CellSlice>{true, cb.finalize()};
|
||||
std::cout << "Grams.validate(cs) = " << block::tlb::t_Grams.validate(*cs) << std::endl;
|
||||
std::cout << "Grams.validate(cs2) = " << block::tlb::t_Grams.validate(*cs2) << std::endl;
|
||||
//
|
||||
block::gen::SplitMergeInfo::Record data;
|
||||
block::gen::Grams::Record data2;
|
||||
std::cout << "block::gen::Grams.validate(cs) = " << block::gen::t_Grams.validate(*cs) << std::endl;
|
||||
std::cout << "block::gen::Grams.validate(cs2) = " << block::gen::t_Grams.validate(*cs2) << std::endl;
|
||||
std::cout << "[cs = " << cs << "]" << std::endl;
|
||||
bool ok = tlb::csr_unpack_inexact(cs, data);
|
||||
std::cout << "block::gen::SplitMergeInfo.unpack(cs, data) = " << ok << std::endl;
|
||||
if (ok) {
|
||||
std::cout << " cur_shard_pfx_len = " << data.cur_shard_pfx_len << "; acc_split_depth = " << data.acc_split_depth
|
||||
<< "; this_addr = " << data.this_addr << "; sibling_addr = " << data.sibling_addr << std::endl;
|
||||
}
|
||||
ok = tlb::csr_unpack_inexact(cs, data2);
|
||||
std::cout << "block::gen::Grams.unpack(cs, data2) = " << ok << std::endl;
|
||||
if (ok) {
|
||||
std::cout << " amount = " << data2.amount << std::endl;
|
||||
block::gen::VarUInteger::Record data3;
|
||||
ok = tlb::csr_type_unpack(data2.amount, block::gen::t_VarUInteger_16, data3);
|
||||
std::cout << " block::gen::VarUInteger16.unpack(amount, data3) = " << ok << std::endl;
|
||||
if (ok) {
|
||||
std::cout << " len = " << data3.len << "; value = " << data3.value << std::endl;
|
||||
vm::CellBuilder cb;
|
||||
std::cout << " block::gen::VarUInteger16.pack(cb, data3) = "
|
||||
<< tlb::type_pack(cb, block::gen::t_VarUInteger_16, data3) << std::endl;
|
||||
std::cout << " cb = " << cb.finalize() << std::endl;
|
||||
}
|
||||
}
|
||||
/*
|
||||
{
|
||||
vm::CellBuilder cb;
|
||||
td::BitArray<256> hash;
|
||||
std::memset(hash.data(), 0x69, 32);
|
||||
bool ok = tlb::pack(
|
||||
cb, block::gen::Test::Record{1000000000000, {170239, -888, {239017, "1000000000000000000"_ri256}, hash}, 17});
|
||||
std::cout << " block::gen::Test::pack(cb, {1000000000000, ...}) = " << ok << std::endl;
|
||||
std::cout << " cb = " << cb << std::endl;
|
||||
auto cell = cb.finalize();
|
||||
vm::CellSlice cs{cell};
|
||||
cs.print_rec(std::cout);
|
||||
block::gen::Test::Record data;
|
||||
std::cout << " block::gen::Test::validate_ref(cell) = " << block::gen::t_Test.validate_ref(cell) << std::endl;
|
||||
ok = tlb::unpack(cs, data);
|
||||
std::cout << " block::gen::Test::unpack(cs, data) = " << ok << std::endl;
|
||||
if (ok) {
|
||||
std::cout << "a:" << data.a << " b:" << data.r1.b << " c:" << data.r1.c << " d:" << data.r1.r1.d
|
||||
<< " e:" << data.r1.r1.e << " f:" << data.r1.f << " g:" << data.g << std::endl;
|
||||
}
|
||||
std::cout << " block::gen::Test::print_ref(cell) = ";
|
||||
block::gen::t_Test.print_ref(std::cout, cell, 2);
|
||||
block::gen::t_CurrencyCollection.print_ref(std::cout, cell, 2);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
*/
|
||||
std::cout << "Grams.add_values() = " << block::tlb::t_Grams.add_values(cb, cs.write(), cs2.write()) << std::endl;
|
||||
std::cout << cb << std::endl;
|
||||
std::cout << "block::gen::t_HashmapAug_64_...print_type() = "
|
||||
<< block::gen::t_HashmapAug_64_Ref_Transaction_CurrencyCollection << std::endl;
|
||||
}
|
||||
|
||||
void test2(vm::CellSlice& cs) {
|
||||
std::cout << "Bool.validate() = " << block::tlb::t_Bool.validate(cs) << std::endl;
|
||||
std::cout << "UInt16.validate() = " << block::tlb::t_uint16.validate(cs) << std::endl;
|
||||
std::cout << "HashmapE(32,UInt16).validate() = " << block::tlb::HashmapE(32, block::tlb::t_uint16).validate(cs)
|
||||
<< std::endl;
|
||||
std::cout << "block::gen::HashmapE(32,UInt16).validate() = "
|
||||
<< block::gen::HashmapE{32, block::gen::t_uint16}.validate(cs) << std::endl;
|
||||
}
|
||||
|
||||
void usage() {
|
||||
std::cout << "usage: test-block [<boc-file>]\n\tor test-block -h\n";
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
int main(int argc, char* const argv[]) {
|
||||
int i;
|
||||
int new_verbosity_level = VERBOSITY_NAME(INFO);
|
||||
auto zerostate = std::make_unique<block::ZerostateInfo>();
|
||||
while ((i = getopt(argc, argv, "hv:")) != -1) {
|
||||
switch (i) {
|
||||
case 'v':
|
||||
new_verbosity_level = VERBOSITY_NAME(FATAL) + (verbosity = td::to_integer<int>(td::Slice(optarg)));
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
std::exit(2);
|
||||
default:
|
||||
usage();
|
||||
std::exit(2);
|
||||
}
|
||||
}
|
||||
SET_VERBOSITY_LEVEL(new_verbosity_level);
|
||||
try {
|
||||
bool done = false;
|
||||
while (optind < argc) {
|
||||
auto boc = load_boc(argv[optind++]);
|
||||
if (boc.is_null()) {
|
||||
std::cerr << "(invalid boc)" << std::endl;
|
||||
std::exit(2);
|
||||
} else {
|
||||
done = true;
|
||||
vm::CellSlice cs{vm::NoVm(), boc};
|
||||
cs.print_rec(std::cout);
|
||||
std::cout << std::endl;
|
||||
block::gen::t_Block.print_ref(std::cout, boc);
|
||||
std::cout << std::endl;
|
||||
if (!block::gen::t_Block.validate_ref(boc)) {
|
||||
std::cout << "(invalid Block)" << std::endl;
|
||||
} else {
|
||||
std::cout << "(valid Block)" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
test1();
|
||||
}
|
||||
} catch (IntError& err) {
|
||||
std::cerr << "caught internal error " << err.err_msg << std::endl;
|
||||
return 1;
|
||||
} catch (vm::VmError& err) {
|
||||
std::cerr << "caught vm error " << err.get_msg() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
199
submodules/ton/tonlib-src/crypto/block/test-weight-distr.cpp
Normal file
199
submodules/ton/tonlib-src/crypto/block/test-weight-distr.cpp
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
TON Blockchain is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
You must obey the GNU General Public License in all respects for all
|
||||
of the code used other than OpenSSL. If you modify file(s) with this
|
||||
exception, you may extend this exception to your version of the file(s),
|
||||
but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2020 Telegram Systems LLP
|
||||
*/
|
||||
#include <iostream>
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "block/block.h"
|
||||
#include <getopt.h>
|
||||
|
||||
const int MAX_N = 1000, MAX_K = 100, DEFAULT_K = 7;
|
||||
|
||||
int verbosity;
|
||||
int N, K = DEFAULT_K;
|
||||
long long iterations = 1000000;
|
||||
|
||||
td::uint64 TWL, WL[MAX_N];
|
||||
double W[MAX_N], CW[MAX_N + 1], RW[MAX_N], R0;
|
||||
int A[MAX_N], C[MAX_N];
|
||||
long long TC;
|
||||
|
||||
void gen_vset() {
|
||||
static std::pair<double, double> H[MAX_N];
|
||||
double total_wt = 1.;
|
||||
int hc = 0;
|
||||
for (int i = 0; i < K; i++) {
|
||||
CHECK(total_wt > 0);
|
||||
double inv_wt = 1. / total_wt;
|
||||
R0 += inv_wt; // advanced mtcarlo stats
|
||||
for (int j = 0; j < i; j++) {
|
||||
RW[A[j]] -= inv_wt; // advanced mtcarlo stats
|
||||
}
|
||||
// double p = drand48() * total_wt;
|
||||
double p = (double)td::Random::fast_uint64() * total_wt / (1. * (1LL << 32) * (1LL << 32));
|
||||
for (int h = 0; h < hc; h++) {
|
||||
if (p < H[h].first) {
|
||||
break;
|
||||
}
|
||||
p += H[h].second;
|
||||
}
|
||||
int a = -1, b = N, c;
|
||||
while (b - a > 1) {
|
||||
c = ((a + b) >> 1);
|
||||
if (CW[c] <= p) {
|
||||
a = c;
|
||||
} else {
|
||||
b = c;
|
||||
}
|
||||
}
|
||||
CHECK(a >= 0 && a < N);
|
||||
CHECK(total_wt >= W[a]);
|
||||
total_wt -= W[a];
|
||||
double x = CW[a];
|
||||
c = hc++;
|
||||
while (c > 0 && H[c - 1].first > x) {
|
||||
H[c] = H[c - 1];
|
||||
--c;
|
||||
}
|
||||
H[c].first = x;
|
||||
H[c].second = W[a];
|
||||
A[i] = a;
|
||||
C[a]++; // simple mtcarlo stats
|
||||
// std::cout << a << ' ';
|
||||
}
|
||||
// std::cout << std::endl;
|
||||
++TC; // simple mtcarlo stats
|
||||
}
|
||||
|
||||
void mt_carlo() {
|
||||
for (int i = 0; i < N; i++) {
|
||||
C[i] = 0;
|
||||
RW[i] = 0.;
|
||||
}
|
||||
TC = 0;
|
||||
R0 = 0.;
|
||||
std::cout << "running " << iterations << " steps of Monte Carlo simulation\n";
|
||||
for (long long it = 0; it < iterations; ++it) {
|
||||
gen_vset();
|
||||
}
|
||||
for (int i = 0; i < N; i++) {
|
||||
RW[i] = W[i] * (RW[i] + R0) / (double)iterations;
|
||||
}
|
||||
}
|
||||
|
||||
double B[MAX_N];
|
||||
|
||||
void compute_bad_approx() {
|
||||
static double S[MAX_K + 1];
|
||||
S[0] = 1.;
|
||||
for (int i = 1; i <= K; i++) {
|
||||
S[i] = 0.;
|
||||
}
|
||||
for (int i = 0; i < N; i++) {
|
||||
double p = W[i];
|
||||
for (int j = K; j > 0; j--) {
|
||||
S[j] += p * S[j - 1];
|
||||
}
|
||||
}
|
||||
double Sk = S[K];
|
||||
for (int i = 0; i < N; i++) {
|
||||
double t = 1., p = W[i];
|
||||
for (int j = 1; j <= K; j++) {
|
||||
t = S[j] - p * t;
|
||||
}
|
||||
B[i] = 1. - t / Sk;
|
||||
}
|
||||
}
|
||||
|
||||
void usage() {
|
||||
std::cout
|
||||
<< "usage: test-weight-distr [-k<shard-val-num>][-m<iterations>][-s<rand-seed>]\nReads the set of validator "
|
||||
"weights from stdin and emulates validator shard distribution load\n\t-k <shard-val-num>\tSets the number of "
|
||||
"validators generating each shard\n\t-m <iterations>\tMonte Carlo simulation steps\n";
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
int main(int argc, char* const argv[]) {
|
||||
int i;
|
||||
int new_verbosity_level = VERBOSITY_NAME(INFO);
|
||||
// long seed = 0;
|
||||
while ((i = getopt(argc, argv, "hs:k:m:v:")) != -1) {
|
||||
switch (i) {
|
||||
case 'k':
|
||||
K = td::to_integer<int>(td::Slice(optarg));
|
||||
CHECK(K > 0 && K <= 100);
|
||||
break;
|
||||
case 'm':
|
||||
iterations = td::to_integer<long long>(td::Slice(optarg));
|
||||
CHECK(iterations > 0);
|
||||
break;
|
||||
case 's':
|
||||
// seed = td::to_integer<long>(td::Slice(optarg));
|
||||
// srand48(seed);
|
||||
break;
|
||||
case 'v':
|
||||
new_verbosity_level = VERBOSITY_NAME(FATAL) + (verbosity = td::to_integer<int>(td::Slice(optarg)));
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
std::exit(2);
|
||||
default:
|
||||
usage();
|
||||
std::exit(2);
|
||||
}
|
||||
}
|
||||
SET_VERBOSITY_LEVEL(new_verbosity_level);
|
||||
for (N = 0; N < MAX_N && (std::cin >> WL[N]); N++) {
|
||||
CHECK(WL[N] > 0);
|
||||
TWL += WL[N];
|
||||
}
|
||||
CHECK(std::cin.eof());
|
||||
CHECK(N > 0 && TWL > 0 && N <= MAX_N);
|
||||
K = std::min(K, N);
|
||||
CHECK(K > 0 && K <= MAX_K);
|
||||
double acc = 0.;
|
||||
for (i = 0; i < N; i++) {
|
||||
CW[i] = acc;
|
||||
acc += W[i] = (double)WL[i] / (double)TWL;
|
||||
std::cout << "#" << i << ":\t" << W[i] << std::endl;
|
||||
}
|
||||
compute_bad_approx();
|
||||
mt_carlo();
|
||||
std::cout << "result of Monte Carlo simulation (" << iterations << " iterations):" << std::endl;
|
||||
std::cout << "idx\tweight\tmtcarlo1\tmtcarlo2\tapprox\n";
|
||||
for (i = 0; i < N; i++) {
|
||||
std::cout << "#" << i << ":\t" << W[i] << '\t' << (double)C[i] / (double)iterations << '\t' << RW[i] << '\t' << B[i]
|
||||
<< std::endl;
|
||||
}
|
||||
// same computation, but using a MtCarloComputeShare object
|
||||
block::MtCarloComputeShare MT(K, N, W, iterations);
|
||||
std::cout << "-----------------------\n";
|
||||
for (i = 0; i < N; i++) {
|
||||
std::cout << '#' << i << ":\t" << MT.weight(i) << '\t' << MT.share(i) << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1429,6 +1429,9 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
|
||||
if (!tlb::csr_unpack(msg.info, erec)) {
|
||||
return -1;
|
||||
}
|
||||
if (act_rec.mode & ~3) {
|
||||
return -1; // invalid mode for an external message
|
||||
}
|
||||
info.src = std::move(erec.src);
|
||||
info.dest = std::move(erec.dest);
|
||||
// created_lt and created_at are ignored
|
||||
|
@ -151,8 +151,6 @@ struct ActionPhaseConfig {
|
||||
struct CreditPhase {
|
||||
td::RefInt256 due_fees_collected;
|
||||
block::CurrencyCollection credit;
|
||||
// td::RefInt256 credit;
|
||||
// Ref<vm::Cell> credit_extra;
|
||||
};
|
||||
|
||||
struct ComputePhase {
|
||||
@ -233,8 +231,6 @@ struct Account {
|
||||
ton::UnixTime last_paid;
|
||||
vm::CellStorageStat storage_stat;
|
||||
block::CurrencyCollection balance;
|
||||
// td::RefInt256 balance;
|
||||
// Ref<vm::Cell> extra_balance;
|
||||
td::RefInt256 due_payment;
|
||||
Ref<vm::Cell> orig_total_state; // ^Account
|
||||
Ref<vm::Cell> total_state; // ^Account
|
||||
@ -325,8 +321,6 @@ struct Transaction {
|
||||
Ref<vm::Cell> root;
|
||||
Ref<vm::Cell> new_total_state;
|
||||
Ref<vm::CellSlice> new_inner_state;
|
||||
// Ref<vm::Cell> extra_balance;
|
||||
// Ref<vm::Cell> msg_extra;
|
||||
Ref<vm::Cell> new_code, new_data, new_library;
|
||||
Ref<vm::Cell> in_msg, in_msg_state;
|
||||
Ref<vm::CellSlice> in_msg_body;
|
||||
|
72
submodules/ton/tonlib-src/crypto/common/promiseop.hpp
Normal file
72
submodules/ton/tonlib-src/crypto/common/promiseop.hpp
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "refcnt.hpp"
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
template <typename S, typename T>
|
||||
class BinaryPromiseMerger : public CntObject {
|
||||
Result<S> first_;
|
||||
Result<T> second_;
|
||||
Promise<std::pair<S, T>> promise_;
|
||||
std::atomic<int> pending_;
|
||||
|
||||
public:
|
||||
BinaryPromiseMerger(Promise<std::pair<S, T>> promise) : promise_(std::move(promise)), pending_(2) {
|
||||
}
|
||||
static std::pair<Promise<S>, Promise<T>> split(Promise<std::pair<S, T>> promise) {
|
||||
auto ref = make_ref<BinaryPromiseMerger>(std::move(promise));
|
||||
auto& obj = ref.write();
|
||||
return std::make_pair(obj.left(), obj.right());
|
||||
}
|
||||
|
||||
private:
|
||||
Promise<S> left() {
|
||||
return [this, self = Ref<BinaryPromiseMerger>(this)](Result<S> res) {
|
||||
first_ = std::move(res);
|
||||
work();
|
||||
};
|
||||
}
|
||||
Promise<T> right() {
|
||||
return [this, self = Ref<BinaryPromiseMerger>(this)](Result<T> res) {
|
||||
second_ = std::move(res);
|
||||
work();
|
||||
};
|
||||
}
|
||||
void work() {
|
||||
if (!--pending_) {
|
||||
if (first_.is_error()) {
|
||||
promise_.set_error(first_.move_as_error());
|
||||
} else if (second_.is_error()) {
|
||||
promise_.set_error(second_.move_as_error());
|
||||
} else {
|
||||
promise_.set_result(std::pair<S, T>(first_.move_as_ok(), second_.move_as_ok()));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename S, typename T>
|
||||
std::pair<Promise<S>, Promise<T>> split_promise(Promise<std::pair<S, T>> promise) {
|
||||
return BinaryPromiseMerger<S, T>::split(std::move(promise));
|
||||
}
|
||||
|
||||
} // namespace td
|
@ -36,6 +36,7 @@ library TonUtil // TON Blockchain Fift Library
|
||||
|
||||
// ( x -- ) Displays a 64-digit hex number
|
||||
{ 64 0x. } : 64x.
|
||||
{ 64 0X. } : 64X.
|
||||
// ( wc addr -- ) Show address in <workchain>:<account> form
|
||||
{ swap ._ .":" 64x. } : .addr
|
||||
// ( wc addr flags -- ) Show address in base64url form
|
||||
|
63
submodules/ton/tonlib-src/crypto/openssl/digest.cpp
Normal file
63
submodules/ton/tonlib-src/crypto/openssl/digest.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "openssl/digest_td.h"
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
namespace digest {
|
||||
const EVP_MD *OpensslEVP_SHA1::get_evp() {
|
||||
return EVP_sha1();
|
||||
}
|
||||
|
||||
const EVP_MD *OpensslEVP_SHA256::get_evp() {
|
||||
return EVP_sha256();
|
||||
}
|
||||
|
||||
const EVP_MD *OpensslEVP_SHA512::get_evp() {
|
||||
return EVP_sha512();
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
void HashCtx<H>::init() {
|
||||
ctx = EVP_MD_CTX_create();
|
||||
reset();
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
void HashCtx<H>::reset() {
|
||||
EVP_DigestInit_ex(ctx, H::get_evp(), 0);
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
void HashCtx<H>::clear() {
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
ctx = nullptr;
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
void HashCtx<H>::feed(const void *data, std::size_t len) {
|
||||
EVP_DigestUpdate(ctx, data, len);
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
std::size_t HashCtx<H>::extract(unsigned char buffer[digest_bytes]) {
|
||||
unsigned olen = 0;
|
||||
EVP_DigestFinal_ex(ctx, buffer, &olen);
|
||||
assert(olen == digest_bytes);
|
||||
return olen;
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
std::size_t HashCtx<H>::extract(td::MutableSlice slice) {
|
||||
return extract(slice.ubegin());
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
std::string HashCtx<H>::extract() {
|
||||
unsigned char buffer[digest_bytes];
|
||||
unsigned olen = 0;
|
||||
EVP_DigestFinal_ex(ctx, buffer, &olen);
|
||||
assert(olen == digest_bytes);
|
||||
return std::string((char *)buffer, olen);
|
||||
}
|
||||
} // namespace digest
|
@ -230,21 +230,24 @@ variable special-dict
|
||||
} : create-wallet1
|
||||
|
||||
// D x t -- D'
|
||||
{ <b rot Gram, swap rot 16 b>idict! not abort"cannot add value"
|
||||
{ <b rot Gram, swap rot 32 b>idict! not abort"cannot add value"
|
||||
} : rdict-entry
|
||||
{ 86400 * } : days*
|
||||
// balance -- dict
|
||||
{ dictnew
|
||||
over -32768 rdict-entry
|
||||
over 3/4 */ 92 rdict-entry
|
||||
over 1/2 */ 183 rdict-entry
|
||||
swap 1/4 */ 366 rdict-entry
|
||||
0 548 rdict-entry
|
||||
over 31 -1<< rdict-entry
|
||||
over 3/4 */ 91 days* rdict-entry
|
||||
over 1/2 */ 183 days* rdict-entry
|
||||
swap 1/4 */ 365 days* rdict-entry
|
||||
0 548 days* rdict-entry
|
||||
} : make-rdict
|
||||
|
||||
variable wallet2-start-at wallet2-start-at 0!
|
||||
now 86400 / 1+ 86400 * wallet2-start-at !
|
||||
// pubkey amount --
|
||||
{ over ."Key " pubkey>$ type ." -> "
|
||||
RWCode2 // code
|
||||
<b 1 32 u, 3 pick 256 u, 3 roll make-rdict dict, b> // data
|
||||
<b 1 32 u, 3 pick 256 u, 3 roll wallet2-start-at @ 32 u, make-rdict dict, b> // data
|
||||
empty_cell // libs
|
||||
3 roll // balance
|
||||
0 // split_depth
|
||||
|
File diff suppressed because one or more lines are too long
@ -52,6 +52,7 @@ PROGRAM{
|
||||
130944 DECLMETHOD compute_returned_stake
|
||||
104565 DECLMETHOD past_election_ids
|
||||
81558 DECLMETHOD past_elections
|
||||
74376 DECLMETHOD past_elections_list
|
||||
DECLPROC complete_unpack_complaint
|
||||
DECLPROC get_past_complaints
|
||||
77853 DECLMETHOD show_complaint
|
||||
@ -2263,7 +2264,7 @@ PROGRAM{
|
||||
}>
|
||||
past_elections PROC:<{
|
||||
//
|
||||
load_data INLINECALLDICT // _23 _24 _25 _26 _27 _28
|
||||
load_data INLINECALLDICT // _21 _22 _23 _24 _25 _26
|
||||
s3 s5 XCHG
|
||||
5 BLKDROP // past_elections
|
||||
32 PUSHPOW2 // past_elections id
|
||||
@ -2276,19 +2277,51 @@ PROGRAM{
|
||||
DUP // past_elections list fs id found found
|
||||
IF:<{ // past_elections list fs id found
|
||||
s0 s2 XCHG // past_elections list found id fs
|
||||
unpack_past_election INLINECALLDICT // past_elections list found id _32 _33 _34 _35 _36 _37 _38
|
||||
7 TUPLE // past_elections list found id info
|
||||
s1 s(-1) PUXC // past_elections list found id id info
|
||||
PAIR // past_elections list found id _20
|
||||
s0 s3 XCHG2 // past_elections id found _20 list
|
||||
unpack_past_election INLINECALLDICT // past_elections list found id _30 _31 _32 _33 _34 _35 _36
|
||||
s7 PUSH
|
||||
7 -ROLL // past_elections list found id id _30 _31 _32 _33 _34 _35 _36
|
||||
8 TUPLE // past_elections list found id _17
|
||||
s0 s3 XCHG2 // past_elections id found _17 list
|
||||
CONS // past_elections id found list
|
||||
s0 s2 XCHG // past_elections list found id
|
||||
}>ELSE<{
|
||||
s2 POP // past_elections list found id
|
||||
}>
|
||||
SWAP // past_elections list id found
|
||||
NOT // past_elections list id _22
|
||||
s1 s2 XCHG // past_elections id list _22
|
||||
NOT // past_elections list id _20
|
||||
s1 s2 XCHG // past_elections id list _20
|
||||
}> // past_elections id list
|
||||
2 1 BLKDROP2 // list
|
||||
}>
|
||||
past_elections_list PROC:<{
|
||||
//
|
||||
load_data INLINECALLDICT // _28 _29 _30 _31 _32 _33
|
||||
s3 s5 XCHG
|
||||
5 BLKDROP // past_elections
|
||||
32 PUSHPOW2 // past_elections id
|
||||
PUSHNULL // past_elections id list
|
||||
UNTIL:<{
|
||||
s1 s2 XCPU
|
||||
32 PUSHINT // past_elections list id past_elections _15=32
|
||||
DICTUGETPREV
|
||||
NULLSWAPIFNOT2 // past_elections list fs id found
|
||||
DUP // past_elections list fs id found found
|
||||
IF:<{ // past_elections list fs id found
|
||||
s0 s2 XCHG // past_elections list found id fs
|
||||
unpack_past_election INLINECALLDICT // past_elections list found id _37 _38 _39 _40 _41 _42 _43
|
||||
4 BLKDROP // past_elections list found id unfreeze_at stake_held vset_hash
|
||||
s3 PUSH
|
||||
s3 s1 s3 XCHG3 // past_elections list found id id unfreeze_at vset_hash stake_held
|
||||
4 TUPLE // past_elections list found id _25
|
||||
s0 s3 XCHG2 // past_elections id found _25 list
|
||||
CONS // past_elections id found list
|
||||
s0 s2 XCHG // past_elections list found id
|
||||
}>ELSE<{
|
||||
s2 POP // past_elections list found id
|
||||
}>
|
||||
SWAP // past_elections list id found
|
||||
NOT // past_elections list id _27
|
||||
s1 s2 XCHG // past_elections id list _27
|
||||
}> // past_elections id list
|
||||
2 1 BLKDROP2 // list
|
||||
}>
|
||||
|
@ -0,0 +1 @@
|
||||
with_tvm_code("payment-channel", "te6ccgECHgEAA2oAART/APSkE/S88sgLAQIBIAIDAgLOBAUACvJwAfANAgEgBgcCASAPEAIBIAgJAgEgCgsAB0MfANgAKV0NMf0x/T/9P/1AHQAdQB0AHTP9GAIBIAwOAgEgDQ4AiwC0gBTAZgw1AHQgwjXGd4B0gBTAZgw1AHQgwjXGd4h+QElnIAfVEFo+RAU8vQQJJI0NeIhmoAgQ1b5EBTy9BKTNTMw4gGAANRwyMoCF8oAFcoAUAP6AgH6AssfAfoCAfoCyYAAfNIA0gD6APoA0x/6APoAMIAIBIBESAgFIGBkCASATFAIBIBUWADUccjKAhfKABXKAFAD+gIB+gLLHwH6AgH6AsmAAQSCEDf+eBBwgBDIywVQBs8WUAT6AhTLahLLH8s/yQH7AIABnPgAUFahI6NSELmTMCKj3lMCvJIwId5RM6BQI6FUMSRz8AlUIgRz8AlyyMoCAfoCAfoCyYAH3AjwBSLAAJgy+CNQB6BQBpE34gvTH4IQQyeKKFIguo4WECZfBjQ0NYAjAvgjuRLy9HBRRAbwCuCAJIIQJzF4IhO6EvL0+gD6APoA+gDTPzCAJwFWErry9IAhU0OgARERAbkBERAB8vKAIlPYuVPYubHy9FDSoFB8oFBasYBcAhFMluZIyFJE14lAnsVNpuZM2EFiROeJTKLCOHjhbUVS8USO8ErGWcFFEBvAK4DBsInBUcAAgVRTwCOAzMzdBRAPwBgL3AnwByLAAJgy+CNQB6BQBpE34g3TH4IQQyeKKFIguo4YWzMzNjY2NoAjBPgjuRTy9BYQNRA0WfAK4IAlghDyiuGDE7oS8vSAIlPWuVPWubHy9FFcsVFLsQX6APoA0gABjhM7WzmAJlC6sBny9HAgEIoHUJkI4w0J0z/6AIBobAoc2zwh8ANUOUPwBCnQ0wJwUiC6jhE7VErgVGRAVHhwD1YS8AsJCJI6PeJxHbqeOBBpCBBqEEUQNEE68AyUXwhsIuLbPIBwdAGbUAdCDCNcZIfkBERCRPZ4zgB9Ub0/5EB3y9BtwAuINlRAtOjownDCAIE26+RAY8vRwB+IAevoAMIAnUT+6E/L0+ABQCaBcuZExkTDiUHagU3C5kTeRMOJTULCcMDQ1FhA1EDRAM/AK4GwiNxAmRUAS8AgADO1E0NTU0QAOAcjMzMntVA==");
|
@ -0,0 +1,571 @@
|
||||
// automatically generated from `smartcont/stdlib.fc` `smartcont/payment-channel-code.fc`
|
||||
PROGRAM{
|
||||
DECLPROC unpack_data
|
||||
DECLPROC pack_data
|
||||
DECLPROC unpack_config
|
||||
DECLPROC unwrap_signatures
|
||||
DECLPROC unpack_state_init
|
||||
DECLPROC pack_state_init
|
||||
DECLPROC unpack_state_close
|
||||
DECLPROC pack_state_close
|
||||
DECLPROC send_payout
|
||||
DECLPROC do_payout
|
||||
DECLPROC with_init
|
||||
DECLPROC with_close
|
||||
DECLPROC recv_any
|
||||
DECLPROC recv_internal
|
||||
DECLPROC recv_external
|
||||
unpack_data PROCREF:<{
|
||||
//
|
||||
c4 PUSH // _1
|
||||
CTOS // cs
|
||||
LDREF // _4 cs
|
||||
LDREF // res res cs
|
||||
ENDS
|
||||
}>
|
||||
pack_data PROCREF:<{
|
||||
// config state
|
||||
SWAP
|
||||
NEWC // state config _2
|
||||
STREF // state _3
|
||||
STREF // _4
|
||||
ENDC // _5
|
||||
c4 POP
|
||||
}>
|
||||
unpack_config PROC:<{
|
||||
// config
|
||||
CTOS // cs
|
||||
32 LDU // _4 cs
|
||||
32 LDU // _4 _7 cs
|
||||
256 LDU // _4 _7 _10 cs
|
||||
256 LDU // _4 _7 _10 _13 cs
|
||||
LDREF // _4 _7 _10 _13 _16 cs
|
||||
SWAP // _4 _7 _10 _13 cs _16
|
||||
CTOS // _4 _7 _10 _13 cs _18
|
||||
SWAP // _4 _7 _10 _13 _18 cs
|
||||
LDREF // _4 _7 _10 _13 _18 _19 cs
|
||||
SWAP // _4 _7 _10 _13 _18 cs _19
|
||||
CTOS // _4 _7 _10 _13 _18 cs _21
|
||||
SWAP // _4 _7 _10 _13 _18 _21 cs
|
||||
64 LDU // res res res res res res res cs
|
||||
ENDS
|
||||
}>
|
||||
unwrap_signatures PROC:<{
|
||||
// cs a_key b_key
|
||||
s0 s2 XCHG // b_key a_key cs
|
||||
1 LDI // b_key a_key a? cs
|
||||
s0 s1 PUSH2 // b_key a_key a? cs a_sig a?
|
||||
IF:<{ // b_key a_key a? cs a_sig
|
||||
DROP // b_key a_key a? cs
|
||||
LDREF // b_key a_key a? _8 cs
|
||||
SWAP // b_key a_key a? cs _8
|
||||
CTOS // b_key a_key a? cs _10
|
||||
9 PUSHPOW2 // b_key a_key a? cs _10 _11=512
|
||||
PLDSLICEX // b_key a_key a? cs a_sig
|
||||
}> // b_key a_key a? cs a_sig
|
||||
SWAP // b_key a_key a? a_sig cs
|
||||
1 LDI // b_key a_key a? a_sig b? cs
|
||||
s0 s1 PUSH2 // b_key a_key a? a_sig b? cs b_sig b?
|
||||
IF:<{ // b_key a_key a? a_sig b? cs b_sig
|
||||
DROP // b_key a_key a? a_sig b? cs
|
||||
LDREF // b_key a_key a? a_sig b? _18 cs
|
||||
SWAP // b_key a_key a? a_sig b? cs _18
|
||||
CTOS // b_key a_key a? a_sig b? cs _20
|
||||
9 PUSHPOW2 // b_key a_key a? a_sig b? cs _20 _21=512
|
||||
PLDSLICEX // b_key a_key a? a_sig b? cs b_sig
|
||||
}> // b_key a_key a? a_sig b? cs b_sig
|
||||
OVER // b_key a_key a? a_sig b? cs b_sig cs
|
||||
HASHSU // b_key a_key a? a_sig b? cs b_sig hash
|
||||
s5 PUSH // b_key a_key a? a_sig b? cs b_sig hash a?
|
||||
IF:<{ // b_key a_key a? a_sig b? cs b_sig hash
|
||||
31 PUSHINT // b_key a_key a? a_sig b? cs b_sig hash _25
|
||||
s1 s5 s7 PUXC2 // b_key hash a? _25 b? cs b_sig hash a_sig a_key
|
||||
CHKSIGNU // b_key hash a? _25 b? cs b_sig _26
|
||||
s1 s4 XCHG // b_key hash a? b_sig b? cs _25 _26
|
||||
THROWANYIFNOT
|
||||
s2 s4 XCHG // b_key b_sig a? hash b? cs
|
||||
}>ELSE<{
|
||||
s4 POP
|
||||
s5 POP // b_key b_sig a? hash b? cs
|
||||
}>
|
||||
OVER // b_key b_sig a? hash b? cs b?
|
||||
IF:<{ // b_key b_sig a? hash b? cs
|
||||
32 PUSHINT // b_key b_sig a? hash b? cs _28
|
||||
s3 s5 s6 XCHG3 // _28 cs a? b? hash b_sig b_key
|
||||
CHKSIGNU // _28 cs a? b? _29
|
||||
s1 s4 XCHG // b? cs a? _28 _29
|
||||
THROWANYIFNOT
|
||||
s1 s2 XCHG // cs b? a?
|
||||
}>ELSE<{
|
||||
s5 POP
|
||||
s3 POP
|
||||
DROP // cs b? a?
|
||||
}>
|
||||
SWAP // cs a? b?
|
||||
}>
|
||||
unpack_state_init PROC:<{
|
||||
// state
|
||||
1 LDI // _1 state
|
||||
1 LDI // _1 _4 state
|
||||
LDGRAMS // _1 _4 _7 state
|
||||
LDGRAMS // _1 _4 _7 _9 state
|
||||
32 LDU // _1 _4 _7 _9 _11 state
|
||||
LDGRAMS // _1 _4 _7 _9 _11 _14 state
|
||||
LDGRAMS // _1 _4 _7 _9 _11 _14 _31 _30
|
||||
DROP // _1 _4 _7 _9 _11 _14 _16
|
||||
}>
|
||||
pack_state_init PROC:<{
|
||||
// signed_A? signed_B? min_A min_B expire_at A B
|
||||
0 PUSHINT // signed_A? signed_B? min_A min_B expire_at A B _7
|
||||
NEWC // signed_A? signed_B? min_A min_B expire_at A B _7 _8
|
||||
3 STI // signed_A? signed_B? min_A min_B expire_at A B _10
|
||||
s1 s7 XCHG // B signed_B? min_A min_B expire_at A signed_A? _10
|
||||
1 STI // B signed_B? min_A min_B expire_at A _12
|
||||
s1 s5 XCHG // B A min_A min_B expire_at signed_B? _12
|
||||
1 STI // B A min_A min_B expire_at _14
|
||||
s0 s3 XCHG2 // B A expire_at min_B _14 min_A
|
||||
STGRAMS // B A expire_at min_B _15
|
||||
SWAP // B A expire_at _15 min_B
|
||||
STGRAMS // B A expire_at _16
|
||||
32 STU // B A _18
|
||||
SWAP // B _18 A
|
||||
STGRAMS // B _19
|
||||
SWAP // _19 B
|
||||
STGRAMS // _20
|
||||
ENDC // _21
|
||||
}>
|
||||
unpack_state_close PROC:<{
|
||||
// state
|
||||
1 LDI // _1 state
|
||||
1 LDI // _1 _4 state
|
||||
LDGRAMS // _1 _4 _7 state
|
||||
LDGRAMS // _1 _4 _7 _9 state
|
||||
32 LDU // _1 _4 _7 _9 _11 state
|
||||
LDGRAMS // _1 _4 _7 _9 _11 _14 state
|
||||
LDGRAMS // _1 _4 _7 _9 _11 _14 _31 _30
|
||||
DROP // _1 _4 _7 _9 _11 _14 _16
|
||||
}>
|
||||
pack_state_close PROC:<{
|
||||
// signed_A? signed_B? promise_A promise_B expire_at A B
|
||||
1 PUSHINT // signed_A? signed_B? promise_A promise_B expire_at A B _7
|
||||
NEWC // signed_A? signed_B? promise_A promise_B expire_at A B _7 _8
|
||||
3 STI // signed_A? signed_B? promise_A promise_B expire_at A B _10
|
||||
s1 s7 XCHG // B signed_B? promise_A promise_B expire_at A signed_A? _10
|
||||
1 STI // B signed_B? promise_A promise_B expire_at A _12
|
||||
s1 s5 XCHG // B A promise_A promise_B expire_at signed_B? _12
|
||||
1 STI // B A promise_A promise_B expire_at _14
|
||||
s0 s3 XCHG2 // B A expire_at promise_B _14 promise_A
|
||||
STGRAMS // B A expire_at promise_B _15
|
||||
SWAP // B A expire_at _15 promise_B
|
||||
STGRAMS // B A expire_at _16
|
||||
32 STU // B A _18
|
||||
SWAP // B _18 A
|
||||
STGRAMS // B _19
|
||||
SWAP // _19 B
|
||||
STGRAMS // _20
|
||||
ENDC // _21
|
||||
}>
|
||||
send_payout PROC:<{
|
||||
// s_addr amount channel_id flags
|
||||
0x37fe7810 PUSHINT // s_addr amount channel_id flags _4
|
||||
0 PUSHINT // s_addr amount channel_id flags _4 _5=0
|
||||
16 PUSHINT // s_addr amount channel_id flags _4 _5=0 _6=16
|
||||
NEWC // s_addr amount channel_id flags _4 _5=0 _6=16 _7
|
||||
6 STU // s_addr amount channel_id flags _4 _5=0 _9
|
||||
s0 s6 XCHG2 // _5=0 amount channel_id flags _4 _9 s_addr
|
||||
STSLICER // _5=0 amount channel_id flags _4 _10
|
||||
s0 s4 XCHG2 // _5=0 _4 channel_id flags _10 amount
|
||||
STGRAMS // _5=0 _4 channel_id flags _11
|
||||
s1 s4 XCHG // flags _4 channel_id _5=0 _11
|
||||
107 STU // flags _4 channel_id _25
|
||||
s1 s2 XCHG // flags channel_id _4 _25
|
||||
32 STU // flags channel_id _27
|
||||
64 STU // flags _29
|
||||
ENDC // flags _30
|
||||
SWAP // _30 flags
|
||||
SENDRAWMSG
|
||||
}>
|
||||
do_payout PROC:<{
|
||||
// promise_A promise_B A B a_addr b_addr channel_id
|
||||
ACCEPT
|
||||
s5 s6 XCHG2 // channel_id b_addr A B a_addr promise_B promise_A
|
||||
SUB // channel_id b_addr A B a_addr diff
|
||||
s3 PUSH // channel_id b_addr A B a_addr diff A
|
||||
NEGATE // channel_id b_addr A B a_addr diff _10
|
||||
s1 s(-1) PUXC // channel_id b_addr A B a_addr diff diff _10
|
||||
LESS // channel_id b_addr A B a_addr diff _11
|
||||
IF:<{ // channel_id b_addr A B a_addr diff
|
||||
DROP // channel_id b_addr A B a_addr
|
||||
s2 PUSH // channel_id b_addr A B a_addr A
|
||||
NEGATE // channel_id b_addr A B a_addr diff
|
||||
}> // channel_id b_addr A B a_addr diff
|
||||
s0 s2 PUSH2 // channel_id b_addr A B a_addr diff diff B
|
||||
GREATER // channel_id b_addr A B a_addr diff _13
|
||||
IF:<{ // channel_id b_addr A B a_addr diff
|
||||
DROP // channel_id b_addr A B a_addr
|
||||
OVER // channel_id b_addr A B a_addr diff
|
||||
}> // channel_id b_addr A B a_addr diff
|
||||
s3 s3 XCPU // channel_id b_addr diff B a_addr A diff
|
||||
ADD // channel_id b_addr diff B a_addr A
|
||||
s2 s3 XCHG2 // channel_id b_addr A a_addr B diff
|
||||
SUB // channel_id b_addr A a_addr B
|
||||
s1 s2 s4 XCPU2
|
||||
3 PUSHINT // channel_id b_addr A B a_addr A channel_id _16=3
|
||||
send_payout CALLDICT
|
||||
s2 s0 s3 XCPUXC
|
||||
3 PUSHINT // B A b_addr B channel_id _18=3
|
||||
send_payout CALLDICT
|
||||
2 PUSHINT // B A _20
|
||||
NEWC // B A _20 _21
|
||||
3 STI // B A _23
|
||||
SWAP // B _23 A
|
||||
STGRAMS // B _24
|
||||
SWAP // _24 B
|
||||
STGRAMS // _25
|
||||
ENDC // _26
|
||||
}>
|
||||
with_init PROC:<{
|
||||
// state msg_value msg msg_signed_A? msg_signed_B? a_addr b_addr init_timeout channel_id
|
||||
s0 s8 XCHG // channel_id msg_value msg msg_signed_A? msg_signed_B? a_addr b_addr init_timeout state
|
||||
unpack_state_init CALLDICT // channel_id msg_value msg msg_signed_A? msg_signed_B? a_addr b_addr init_timeout signed_A? signed_B? min_A min_B expire_at A B
|
||||
s2 PUSH // channel_id msg_value msg msg_signed_A? msg_signed_B? a_addr b_addr init_timeout signed_A? signed_B? min_A min_B expire_at A B expire_at
|
||||
0 EQINT // channel_id msg_value msg msg_signed_A? msg_signed_B? a_addr b_addr init_timeout signed_A? signed_B? min_A min_B expire_at A B _18
|
||||
IF:<{ // channel_id msg_value msg msg_signed_A? msg_signed_B? a_addr b_addr init_timeout signed_A? signed_B? min_A min_B expire_at A B
|
||||
s2 POP // channel_id msg_value msg msg_signed_A? msg_signed_B? a_addr b_addr init_timeout signed_A? signed_B? min_A min_B B A
|
||||
NOW // channel_id msg_value msg msg_signed_A? msg_signed_B? a_addr b_addr init_timeout signed_A? signed_B? min_A min_B B A _19
|
||||
s0 s7 XCHG2 // channel_id msg_value msg msg_signed_A? msg_signed_B? a_addr b_addr A signed_A? signed_B? min_A min_B B _19 init_timeout
|
||||
ADD // channel_id msg_value msg msg_signed_A? msg_signed_B? a_addr b_addr A signed_A? signed_B? min_A min_B B expire_at
|
||||
s0 s6 XCHG2 // channel_id msg_value msg msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at A
|
||||
}>ELSE<{
|
||||
s7 POP // channel_id msg_value msg msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at A
|
||||
}>
|
||||
s0 s11 XCHG // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at msg
|
||||
32 LDU // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at op msg
|
||||
0x43278a28 PUSHINT // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at op msg _25
|
||||
s2 s(-1) PUXC // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at op msg op _25
|
||||
EQUAL // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at op msg _26
|
||||
IFJMP:<{ // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at op msg
|
||||
s2 s6 XCHG
|
||||
6 BLKDROP
|
||||
s4 POP
|
||||
s4 POP
|
||||
s5 POP // channel_id b_addr A B expire_at a_addr
|
||||
35 PUSHINT // channel_id b_addr A B expire_at a_addr _27
|
||||
s0 s2 XCHG
|
||||
NOW // channel_id b_addr A B _27 a_addr expire_at _28
|
||||
LESS // channel_id b_addr A B _27 a_addr _29
|
||||
s1 s2 XCHG // channel_id b_addr A B a_addr _27 _29
|
||||
THROWANYIFNOT
|
||||
0 PUSHINT // channel_id b_addr A B a_addr _31=0
|
||||
s4 s4 XCPU
|
||||
s0 s6 XCHG // _31=0 _32=0 A B a_addr b_addr channel_id
|
||||
do_payout CALLDICT // _33
|
||||
}> // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at op msg
|
||||
36 PUSHINT // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at op msg _34
|
||||
0x27317822 PUSHINT // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at op msg _34 _35
|
||||
s1 s3 XCHG // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at _34 msg op _35
|
||||
EQUAL // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at _34 msg _36
|
||||
s1 s2 XCHG // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at msg _34 _36
|
||||
THROWANYIFNOT
|
||||
LDGRAMS // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at _43 msg
|
||||
LDGRAMS // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at _43 _45 msg
|
||||
LDGRAMS // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at _43 _45 _47 msg
|
||||
LDGRAMS // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at _43 _45 _47 _49 msg
|
||||
64 LDU // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at _43 _45 _47 _49 _104 _103
|
||||
DROP // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A upd_min_B got_channel_id
|
||||
39 PUSHINT // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A upd_min_B got_channel_id _54
|
||||
SWAP
|
||||
18 s() PUSH // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A upd_min_B _54 got_channel_id channel_id
|
||||
EQUAL // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A upd_min_B _54 _55
|
||||
THROWANYIFNOT
|
||||
33 PUSHINT // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A upd_min_B _57
|
||||
s4 s3 PUSH2 // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A upd_min_B _57 inc_A inc_B
|
||||
ADD // channel_id msg_value A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A upd_min_B _57 _58
|
||||
s1 17 s() XCHG // channel_id _57 A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A upd_min_B msg_value _58
|
||||
LESS // channel_id _57 A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A upd_min_B _59
|
||||
s1 16 s() XCHG // channel_id upd_min_B A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A _57 _59
|
||||
THROWANYIF
|
||||
34 PUSHINT // channel_id upd_min_B A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A _61
|
||||
s13 s8 PUSH2 // channel_id upd_min_B A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A _61 msg_signed_A? signed_A?
|
||||
LESS // channel_id upd_min_B A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A _61 _62
|
||||
s13 s8 PUSH2 // channel_id upd_min_B A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A _61 _62 msg_signed_B? signed_B?
|
||||
LESS // channel_id upd_min_B A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A _61 _62 _63
|
||||
OR // channel_id upd_min_B A msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at inc_A inc_B upd_min_A _61 _64
|
||||
THROWANYIFNOT
|
||||
s13 s2 XCHG2 // channel_id upd_min_B inc_B msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at upd_min_A A inc_A
|
||||
ADD // channel_id upd_min_B inc_B msg_signed_A? msg_signed_B? a_addr b_addr B signed_A? signed_B? min_A min_B expire_at upd_min_A A
|
||||
s7 s12 XCHG2 // channel_id upd_min_B A msg_signed_A? msg_signed_B? a_addr b_addr upd_min_A signed_A? signed_B? min_A min_B expire_at B inc_B
|
||||
ADD // channel_id upd_min_B A msg_signed_A? msg_signed_B? a_addr b_addr upd_min_A signed_A? signed_B? min_A min_B expire_at B
|
||||
s5 s10 XCHG2 // channel_id upd_min_B A B msg_signed_B? a_addr b_addr upd_min_A expire_at signed_B? min_A min_B signed_A? msg_signed_A?
|
||||
OR // channel_id upd_min_B A B msg_signed_B? a_addr b_addr upd_min_A expire_at signed_B? min_A min_B signed_A?
|
||||
s2 s5 PUSH2 // channel_id upd_min_B A B msg_signed_B? a_addr b_addr upd_min_A expire_at signed_B? min_A min_B signed_A? min_A upd_min_A
|
||||
LESS // channel_id upd_min_B A B msg_signed_B? a_addr b_addr upd_min_A expire_at signed_B? min_A min_B signed_A? _69
|
||||
IF:<{ // channel_id upd_min_B A B msg_signed_B? a_addr b_addr upd_min_A expire_at signed_B? min_A min_B signed_A?
|
||||
s2 POP // channel_id upd_min_B A B msg_signed_B? a_addr b_addr min_A expire_at signed_B? signed_A? min_B
|
||||
s1 s4 XCHG // channel_id upd_min_B A B msg_signed_B? a_addr b_addr signed_A? expire_at signed_B? min_A min_B
|
||||
}>ELSE<{
|
||||
s5 POP // channel_id upd_min_B A B msg_signed_B? a_addr b_addr signed_A? expire_at signed_B? min_A min_B
|
||||
}>
|
||||
s2 s7 XCHG2 // channel_id upd_min_B A B min_B a_addr b_addr signed_A? expire_at min_A signed_B? msg_signed_B?
|
||||
OR // channel_id upd_min_B A B min_B a_addr b_addr signed_A? expire_at min_A signed_B?
|
||||
s6 s9 PUSH2 // channel_id upd_min_B A B min_B a_addr b_addr signed_A? expire_at min_A signed_B? min_B upd_min_B
|
||||
LESS // channel_id upd_min_B A B min_B a_addr b_addr signed_A? expire_at min_A signed_B? _71
|
||||
IF:<{ // channel_id upd_min_B A B min_B a_addr b_addr signed_A? expire_at min_A signed_B?
|
||||
s6 POP // channel_id min_B A B signed_B? a_addr b_addr signed_A? expire_at min_A
|
||||
s5 s8 XCHG // channel_id signed_B? A B min_B a_addr b_addr signed_A? expire_at min_A
|
||||
}>ELSE<{
|
||||
s9 POP // channel_id signed_B? A B min_B a_addr b_addr signed_A? expire_at min_A
|
||||
}>
|
||||
s2 s8 PUSH2 // channel_id signed_B? A B min_B a_addr b_addr signed_A? expire_at min_A signed_A? signed_B?
|
||||
AND // channel_id signed_B? A B min_B a_addr b_addr signed_A? expire_at min_A _72
|
||||
IFJMP:<{ // channel_id signed_B? A B min_B a_addr b_addr signed_A? expire_at min_A
|
||||
s8 POP
|
||||
2DROP // channel_id min_A A B min_B a_addr b_addr
|
||||
s5 s4 XCPU // channel_id b_addr A B min_B a_addr min_A A
|
||||
GREATER // channel_id b_addr A B min_B a_addr _73
|
||||
s2 s3 XCPU // channel_id b_addr A B _73 a_addr min_B B
|
||||
GREATER // channel_id b_addr A B _73 a_addr _74
|
||||
s1 s2 XCHG // channel_id b_addr A B a_addr _73 _74
|
||||
OR // channel_id b_addr A B a_addr _75
|
||||
IFJMP:<{ // channel_id b_addr A B a_addr
|
||||
0 PUSHINT // channel_id b_addr A B a_addr _76=0
|
||||
s4 s4 XCPU
|
||||
s0 s6 XCHG // _76=0 _77=0 A B a_addr b_addr channel_id
|
||||
do_payout CALLDICT // _78
|
||||
}> // channel_id b_addr A B a_addr
|
||||
DROP
|
||||
2 2 BLKDROP2 // A B
|
||||
0 PUSHINT // A B _79=0
|
||||
s0 s0 s0 PUSH3 // A B _79=0 _80=0 _81=0 _82=0
|
||||
DUP // A B _79=0 _80=0 _81=0 _82=0 _83=0
|
||||
2 5 BLKSWAP // _79=0 _80=0 _81=0 _82=0 _83=0 A B
|
||||
pack_state_close CALLDICT // _84
|
||||
}> // channel_id signed_B? A B min_B a_addr b_addr signed_A? expire_at min_A
|
||||
s3 POP
|
||||
s3 POP
|
||||
s7 POP // signed_A? signed_B? A B min_B expire_at min_A
|
||||
s1 s4 s4 XCHG3
|
||||
s0 s3 XCHG // signed_A? signed_B? min_A min_B expire_at A B
|
||||
pack_state_init CALLDICT // _85
|
||||
}>
|
||||
with_close PROC:<{
|
||||
// cs msg msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr expire_timeout channel_id
|
||||
s0 s9 XCHG // channel_id msg msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr expire_timeout cs
|
||||
unpack_state_close CALLDICT // channel_id msg msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr expire_timeout signed_A? signed_B? promise_A promise_B expire_at A B
|
||||
s2 PUSH // channel_id msg msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr expire_timeout signed_A? signed_B? promise_A promise_B expire_at A B expire_at
|
||||
0 EQINT // channel_id msg msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr expire_timeout signed_A? signed_B? promise_A promise_B expire_at A B _19
|
||||
IF:<{ // channel_id msg msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr expire_timeout signed_A? signed_B? promise_A promise_B expire_at A B
|
||||
s2 POP // channel_id msg msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr expire_timeout signed_A? signed_B? promise_A promise_B B A
|
||||
NOW // channel_id msg msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr expire_timeout signed_A? signed_B? promise_A promise_B B A _20
|
||||
s0 s7 XCHG2 // channel_id msg msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr A signed_A? signed_B? promise_A promise_B B _20 expire_timeout
|
||||
ADD // channel_id msg msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr A signed_A? signed_B? promise_A promise_B B expire_at
|
||||
s0 s6 XCHG2 // channel_id msg msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at A
|
||||
}>ELSE<{
|
||||
s7 POP // channel_id msg msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at A
|
||||
}>
|
||||
s0 s13 XCHG // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at msg
|
||||
32 LDU // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at op msg
|
||||
0x43278a28 PUSHINT // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at op msg _26
|
||||
s2 s(-1) PUXC // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at op msg op _26
|
||||
EQUAL // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at op msg _27
|
||||
IFJMP:<{ // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at op msg
|
||||
2DROP
|
||||
s3 POP
|
||||
s3 POP
|
||||
s6 POP
|
||||
s6 POP
|
||||
s6 POP
|
||||
s6 POP // channel_id A B promise_B expire_at promise_A a_addr b_addr
|
||||
35 PUSHINT // channel_id A B promise_B expire_at promise_A a_addr b_addr _28
|
||||
s0 s4 XCHG
|
||||
NOW // channel_id A B promise_B _28 promise_A a_addr b_addr expire_at _29
|
||||
LESS // channel_id A B promise_B _28 promise_A a_addr b_addr _30
|
||||
s1 s4 XCHG // channel_id A B promise_B b_addr promise_A a_addr _28 _30
|
||||
THROWANYIFNOT
|
||||
s1 s6 XCHG
|
||||
s3 s5 XCHG
|
||||
s3 s4 XCHG
|
||||
-ROT // promise_A promise_B A B a_addr b_addr channel_id
|
||||
do_payout CALLDICT // _32
|
||||
}> // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at op msg
|
||||
37 PUSHINT // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at op msg _33
|
||||
0xf28ae183 PUSHINT // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at op msg _33 _34
|
||||
s1 s3 XCHG // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at _33 msg op _34
|
||||
EQUAL // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at _33 msg _35
|
||||
s1 s2 XCHG // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at msg _33 _35
|
||||
THROWANYIFNOT
|
||||
34 PUSHINT // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at msg _37
|
||||
s13 s6 PUSH2 // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at msg _37 msg_signed_A? signed_A?
|
||||
LESS // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at msg _37 _38
|
||||
s13 s6 PUSH2 // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at msg _37 _38 msg_signed_B? signed_B?
|
||||
LESS // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at msg _37 _38 _39
|
||||
OR // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_A? signed_B? promise_A promise_B expire_at msg _37 _40
|
||||
THROWANYIFNOT
|
||||
s5 s12 XCPU // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B msg signed_B? promise_A promise_B expire_at signed_A? msg_signed_A?
|
||||
OR // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B msg signed_B? promise_A promise_B expire_at signed_A?
|
||||
s4 s11 XCPU // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B msg signed_A? promise_A promise_B expire_at signed_B? msg_signed_B?
|
||||
OR // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B msg signed_A? promise_A promise_B expire_at signed_B?
|
||||
s0 s5 XCHG // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at msg
|
||||
LDGRAMS // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at _46 msg
|
||||
LDGRAMS // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B msg
|
||||
1 LDI // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B has_sig msg
|
||||
SWAP // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B msg has_sig
|
||||
IF:<{ // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B msg
|
||||
LDREF // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B _55 msg
|
||||
SWAP // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B msg _55
|
||||
CTOS // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B msg _57
|
||||
9 PUSHPOW2 // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B msg _57 _58=512
|
||||
PLDSLICEX // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B msg sig
|
||||
OVER // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B msg sig msg
|
||||
HASHSU // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B msg sig hash
|
||||
s0 16 s() XCHG // channel_id A hash msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B msg sig msg_signed_A?
|
||||
IFNOT:<{ // channel_id A hash msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B msg sig
|
||||
s3 POP // channel_id A hash msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at sig extra_B msg
|
||||
31 PUSHINT // channel_id A hash msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at sig extra_B msg _62
|
||||
s15 s3 s13 PU2XC // channel_id A hash msg_signed_B? _62 b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at sig extra_B msg hash sig a_key
|
||||
CHKSIGNU // channel_id A hash msg_signed_B? _62 b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at sig extra_B msg _63
|
||||
s1 s13 XCHG // channel_id A hash msg_signed_B? msg b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at sig extra_B _62 _63
|
||||
THROWANYIFNOT
|
||||
s1 s11 XCHG
|
||||
0 PUSHINT
|
||||
s0 s2 XCHG // channel_id A hash msg_signed_B? sig b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A=0 extra_B msg
|
||||
}>ELSE<{
|
||||
s13 POP // channel_id A hash msg_signed_B? sig b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B msg
|
||||
}>
|
||||
s0 s13 XCHG // channel_id A hash msg sig b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B msg_signed_B?
|
||||
IFNOT:<{ // channel_id A hash msg sig b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B
|
||||
DROP // channel_id A hash msg sig b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A
|
||||
32 PUSHINT // channel_id A hash msg sig b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A _66
|
||||
s13 s11 s10 XCHG3 // channel_id A expire_at msg extra_A _66 a_addr b_addr B signed_B? signed_A? promise_A promise_B hash sig b_key
|
||||
CHKSIGNU // channel_id A expire_at msg extra_A _66 a_addr b_addr B signed_B? signed_A? promise_A promise_B _67
|
||||
s1 s8 XCHG // channel_id A expire_at msg extra_A promise_B a_addr b_addr B signed_B? signed_A? promise_A _66 _67
|
||||
THROWANYIFNOT
|
||||
0 PUSHINT // channel_id A expire_at msg extra_A promise_B a_addr b_addr B signed_B? signed_A? promise_A extra_B=0
|
||||
s0 s7 XCHG // channel_id A expire_at msg extra_A extra_B=0 a_addr b_addr B signed_B? signed_A? promise_A promise_B
|
||||
}>ELSE<{
|
||||
s2 s13 XCHG
|
||||
s10 POP
|
||||
s10 POP
|
||||
DROP // channel_id A expire_at msg extra_A extra_B a_addr b_addr B signed_B? signed_A? promise_A promise_B
|
||||
}>
|
||||
}>ELSE<{ // channel_id A msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr B signed_B? signed_A? promise_A promise_B expire_at extra_A extra_B msg
|
||||
s11 POP
|
||||
2DROP
|
||||
s9 POP // channel_id A msg_signed_A? msg_signed_B? expire_at msg a_addr b_addr B signed_B? signed_A? promise_A promise_B
|
||||
38 PUSHINT // channel_id A msg_signed_A? msg_signed_B? expire_at msg a_addr b_addr B signed_B? signed_A? promise_A promise_B _70
|
||||
s11 s10 XCHG2 // channel_id A promise_B _70 expire_at msg a_addr b_addr B signed_B? signed_A? promise_A msg_signed_A? msg_signed_B?
|
||||
AND // channel_id A promise_B _70 expire_at msg a_addr b_addr B signed_B? signed_A? promise_A _71
|
||||
s1 s9 XCHG // channel_id A promise_B promise_A expire_at msg a_addr b_addr B signed_B? signed_A? _70 _71
|
||||
THROWANYIFNOT
|
||||
0 PUSHINT // channel_id A promise_B promise_A expire_at msg a_addr b_addr B signed_B? signed_A? extra_A=0
|
||||
DUP // channel_id A promise_B promise_A expire_at msg a_addr b_addr B signed_B? signed_A? extra_A=0 extra_B=0
|
||||
s8 s10 XCHG
|
||||
s0 s7 XCHG
|
||||
s9 s9 XCHG2
|
||||
s0 s8 XCHG // channel_id A expire_at msg extra_A extra_B a_addr b_addr B signed_B? signed_A? promise_A promise_B
|
||||
}>
|
||||
s0 s9 XCHG // channel_id A expire_at promise_B extra_A extra_B a_addr b_addr B signed_B? signed_A? promise_A msg
|
||||
64 LDU // channel_id A expire_at promise_B extra_A extra_B a_addr b_addr B signed_B? signed_A? promise_A _78 msg
|
||||
LDGRAMS // channel_id A expire_at promise_B extra_A extra_B a_addr b_addr B signed_B? signed_A? promise_A _78 _81 msg
|
||||
LDGRAMS // channel_id A expire_at promise_B extra_A extra_B a_addr b_addr B signed_B? signed_A? promise_A _78 _81 _118 _117
|
||||
DROP // channel_id A expire_at promise_B extra_A extra_B a_addr b_addr B signed_B? signed_A? promise_A got_channel_id update_promise_A update_promise_B
|
||||
39 PUSHINT // channel_id A expire_at promise_B extra_A extra_B a_addr b_addr B signed_B? signed_A? promise_A got_channel_id update_promise_A update_promise_B _85
|
||||
s3 s15 XCPU // channel_id A expire_at promise_B extra_A extra_B a_addr b_addr B signed_B? signed_A? promise_A _85 update_promise_A update_promise_B got_channel_id channel_id
|
||||
EQUAL // channel_id A expire_at promise_B extra_A extra_B a_addr b_addr B signed_B? signed_A? promise_A _85 update_promise_A update_promise_B _86
|
||||
s1 s3 XCHG // channel_id A expire_at promise_B extra_A extra_B a_addr b_addr B signed_B? signed_A? promise_A update_promise_B update_promise_A _85 _86
|
||||
THROWANYIFNOT
|
||||
ACCEPT
|
||||
s0 s9 XCHG2 // channel_id A expire_at promise_B update_promise_B extra_B a_addr b_addr B signed_B? signed_A? promise_A update_promise_A extra_A
|
||||
ADD // channel_id A expire_at promise_B update_promise_B extra_B a_addr b_addr B signed_B? signed_A? promise_A update_promise_A
|
||||
2DUP // channel_id A expire_at promise_B update_promise_B extra_B a_addr b_addr B signed_B? signed_A? promise_A update_promise_A promise_A update_promise_A
|
||||
LESS // channel_id A expire_at promise_B update_promise_B extra_B a_addr b_addr B signed_B? signed_A? promise_A update_promise_A _90
|
||||
IF:<{ // channel_id A expire_at promise_B update_promise_B extra_B a_addr b_addr B signed_B? signed_A? promise_A update_promise_A
|
||||
NIP // channel_id A expire_at promise_B update_promise_B extra_B a_addr b_addr B signed_B? signed_A? promise_A
|
||||
}>ELSE<{
|
||||
DROP // channel_id A expire_at promise_B update_promise_B extra_B a_addr b_addr B signed_B? signed_A? promise_A
|
||||
}>
|
||||
s7 s6 XCHG2 // channel_id A expire_at promise_B signed_A? promise_A a_addr b_addr B signed_B? update_promise_B extra_B
|
||||
ADD // channel_id A expire_at promise_B signed_A? promise_A a_addr b_addr B signed_B? update_promise_B
|
||||
s7 s0 PUSH2 // channel_id A expire_at promise_B signed_A? promise_A a_addr b_addr B signed_B? update_promise_B promise_B update_promise_B
|
||||
LESS // channel_id A expire_at promise_B signed_A? promise_A a_addr b_addr B signed_B? update_promise_B _92
|
||||
IF:<{ // channel_id A expire_at promise_B signed_A? promise_A a_addr b_addr B signed_B? update_promise_B
|
||||
s7 POP // channel_id A expire_at promise_B signed_A? promise_A a_addr b_addr B signed_B?
|
||||
}>ELSE<{
|
||||
DROP // channel_id A expire_at promise_B signed_A? promise_A a_addr b_addr B signed_B?
|
||||
}>
|
||||
s5 s0 PUSH2 // channel_id A expire_at promise_B signed_A? promise_A a_addr b_addr B signed_B? signed_A? signed_B?
|
||||
AND // channel_id A expire_at promise_B signed_A? promise_A a_addr b_addr B signed_B? _93
|
||||
IFJMP:<{ // channel_id A expire_at promise_B signed_A? promise_A a_addr b_addr B signed_B?
|
||||
DROP
|
||||
s4 POP
|
||||
s5 POP // channel_id A b_addr promise_B B promise_A a_addr
|
||||
s1 s6 XCHG
|
||||
s3 s5 XCHG
|
||||
s3 s4 XCHG
|
||||
s0 s3 s3 XCHG3 // promise_A promise_B A B a_addr b_addr channel_id
|
||||
do_payout CALLDICT // _94
|
||||
}> // channel_id A expire_at promise_B signed_A? promise_A a_addr b_addr B signed_B?
|
||||
2 2 BLKDROP2
|
||||
s7 POP // signed_B? A expire_at promise_B signed_A? promise_A B
|
||||
s2 s6 XCHG
|
||||
s5 s4 s0 XCHG3
|
||||
s1 s2 XCHG // signed_A? signed_B? promise_A promise_B expire_at A B
|
||||
pack_state_close CALLDICT // _95
|
||||
}>
|
||||
recv_any PROC:<{
|
||||
// msg_value msg
|
||||
unpack_data INLINECALLDICT // msg_value msg config state
|
||||
OVER // msg_value msg config state config
|
||||
unpack_config CALLDICT // msg_value msg config state init_timeout close_timeout a_key b_key a_addr b_addr channel_id
|
||||
s9 s4 s3 XCPU2 // msg_value channel_id config state init_timeout close_timeout a_key b_key a_addr b_addr msg a_key b_key
|
||||
unwrap_signatures CALLDICT // msg_value channel_id config state init_timeout close_timeout a_key b_key a_addr b_addr msg msg_signed_A? msg_signed_B?
|
||||
s9 PUSH // msg_value channel_id config state init_timeout close_timeout a_key b_key a_addr b_addr msg msg_signed_A? msg_signed_B? state
|
||||
CTOS // msg_value channel_id config state init_timeout close_timeout a_key b_key a_addr b_addr msg msg_signed_A? msg_signed_B? cs
|
||||
3 LDU // msg_value channel_id config state init_timeout close_timeout a_key b_key a_addr b_addr msg msg_signed_A? msg_signed_B? state_type cs
|
||||
0 PUSHINT // msg_value channel_id config state init_timeout close_timeout a_key b_key a_addr b_addr msg msg_signed_A? msg_signed_B? state_type cs _23
|
||||
s2 s(-1) PUXC // msg_value channel_id config state init_timeout close_timeout a_key b_key a_addr b_addr msg msg_signed_A? msg_signed_B? state_type cs state_type _23
|
||||
EQUAL // msg_value channel_id config state init_timeout close_timeout a_key b_key a_addr b_addr msg msg_signed_A? msg_signed_B? state_type cs _24
|
||||
IF:<{ // msg_value channel_id config state init_timeout close_timeout a_key b_key a_addr b_addr msg msg_signed_A? msg_signed_B? state_type cs
|
||||
s11 POP // msg_value channel_id config cs init_timeout close_timeout a_key b_key a_addr b_addr msg msg_signed_A? msg_signed_B? state_type
|
||||
s10 s13 s(-1) PUXC2
|
||||
s4 s3 s(-2) PU2XC
|
||||
s8 s7 s0 PUSH3
|
||||
s0 s15 XCHG
|
||||
18 s() PUSH // state_type channel_id config cs msg_signed_B? close_timeout a_key b_key a_addr b_addr msg msg_signed_A? cs msg_value msg msg_signed_A? msg_signed_B? a_addr b_addr init_timeout channel_id
|
||||
with_init CALLDICT // state_type channel_id config cs msg_signed_B? close_timeout a_key b_key a_addr b_addr msg msg_signed_A? state
|
||||
s0 s9 XCHG
|
||||
s0 s8 XCHG // state_type channel_id config state cs close_timeout a_key b_key a_addr b_addr msg msg_signed_A? msg_signed_B?
|
||||
}>ELSE<{
|
||||
s10 POP
|
||||
s13 POP // state_type channel_id config state cs close_timeout a_key b_key a_addr b_addr msg msg_signed_A? msg_signed_B?
|
||||
}>
|
||||
1 PUSHINT // state_type channel_id config state cs close_timeout a_key b_key a_addr b_addr msg msg_signed_A? msg_signed_B? _26
|
||||
s1 s13 XCHG // msg_signed_B? channel_id config state cs close_timeout a_key b_key a_addr b_addr msg msg_signed_A? state_type _26
|
||||
EQUAL // msg_signed_B? channel_id config state cs close_timeout a_key b_key a_addr b_addr msg msg_signed_A? _27
|
||||
IF:<{ // msg_signed_B? channel_id config state cs close_timeout a_key b_key a_addr b_addr msg msg_signed_A?
|
||||
s8 POP // msg_signed_B? channel_id config msg_signed_A? cs close_timeout a_key b_key a_addr b_addr msg
|
||||
s6 s9 XCHG
|
||||
s0 s8 XCHG
|
||||
s6 s10 XCHG
|
||||
s4 s5 XCHG
|
||||
s3 s4 XCHG
|
||||
s1 s3 s10 XCHG3 // config cs msg msg_signed_A? msg_signed_B? a_key b_key a_addr b_addr close_timeout channel_id
|
||||
with_close CALLDICT // config state
|
||||
}>ELSE<{
|
||||
8 BLKDROP
|
||||
2 2 BLKDROP2 // config state
|
||||
}>
|
||||
pack_data INLINECALLDICT
|
||||
}>
|
||||
recv_internal PROC:<{
|
||||
// msg_value in_msg_cell in_msg
|
||||
NIP // msg_value in_msg
|
||||
recv_any CALLDICT
|
||||
}>
|
||||
recv_external PROC:<{
|
||||
// in_msg
|
||||
0 PUSHINT // in_msg _1=0
|
||||
SWAP // _1=0 in_msg
|
||||
recv_any CALLDICT
|
||||
}>
|
||||
}END>c
|
@ -1 +1 @@
|
||||
with_tvm_code("restricted-wallet2", "te6ccgECCwEAAQgAART/APSkE/S88sgLAQIBIAIDAgFIBAUB+PKDCNcYINMf0x8B+CO78mPtRNDTH9P/9ATRU0K68qEEjhIyMzP4AAGkyMsfEsv/9ADJ7VThBPkBVBBU+RDyovgAgPP4MyBukjB/nvgjAdDXCx+hggFRgKkE4iKAEPR7b6UxlvoAMHL7ApEw4pMg10qW0wfUAvsA6NECpMgKAATQMAIBIAYHAgEgCAkAe7y2B2omhAgJBrkPoCaMB5/BmQN0kYP898EYDoa4WP0MEAqMBUgnF8E7eIAUAIej230pjL/QAYULhbBMiYcUABe7Oc7UTQ0x8x1wv/gAEbjJftRNDXCx+AASyx/L//QAye1U");
|
||||
with_tvm_code("restricted-wallet2", "te6ccgECDgEAARoAART/APSkE/S88sgLAQIBIAIDAgFIBAUB8vKDCNcYINMf0x8B+CO78mPtRNDTH9P/0x/0BNFTU7ryoQWOFTM0NPgAA6TIyx8Sy/8Syx/0AMntVOEF+QFUEGb5EPKi+AAj+CPbPCOAIPR7b6UxlvoAMHL7ApEw4gGTINdKltMH1AL7AOjRpMjLHxPL/8sf9ADJ7VQNAATQMAIBIAYHAgEgCAkCAUgKCwAXuznO1E0NMfMdcL/4ABG4yX7UTQ1wsfgBDbbYHwR7Z5AMAQm1B1tnkAwBTu1E0IEBINch0x/0BNEC2zz4J28QAoAg9HtvpTGX+gAwoXC2CZEw4g0AOiGOETGA8/gzIG6SMHCU0NcLH+IB3yGSAaGSW3/i");
|
||||
|
@ -1,32 +1,42 @@
|
||||
// automatically generated from `smartcont/stdlib.fc` `smartcont/restricted-wallet2-code.fc`
|
||||
PROGRAM{
|
||||
DECLPROC recv_internal
|
||||
DECLPROC days_passed
|
||||
DECLPROC seconds_passed
|
||||
DECLPROC recv_external
|
||||
85143 DECLMETHOD seqno
|
||||
78748 DECLMETHOD get_public_key
|
||||
DECLPROC compute_balance_at
|
||||
108602 DECLMETHOD balance_at
|
||||
104128 DECLMETHOD balance
|
||||
recv_internal PROC:<{
|
||||
// in_msg
|
||||
DROP //
|
||||
}>
|
||||
days_passed PROC:<{
|
||||
//
|
||||
-13 PUSHINT // _1=-13
|
||||
CONFIGOPTPARAM // p
|
||||
DUP // p p
|
||||
ISNULL // p _3
|
||||
IF:<{ // p
|
||||
DROP //
|
||||
-1 PUSHINT // _4=-1
|
||||
}>ELSE<{ // p
|
||||
NOW // p _6
|
||||
SWAP // _6 p
|
||||
CTOS // _6 _7
|
||||
32 PLDU // _6 _9
|
||||
SUB // _10
|
||||
86400 PUSHINT // _10 _11=86400
|
||||
DIV // _4
|
||||
seconds_passed PROCREF:<{
|
||||
// start_at utime
|
||||
OVER // start_at utime start_at
|
||||
IFNOT:<{ // start_at utime
|
||||
NIP // utime
|
||||
-13 PUSHINT // utime _3=-13
|
||||
CONFIGOPTPARAM // utime p
|
||||
DUP // utime p p
|
||||
ISNULL // utime p _5
|
||||
IF:<{ // utime p
|
||||
DROP // utime
|
||||
0 PUSHINT // utime _6=0
|
||||
}>ELSE<{ // utime p
|
||||
CTOS // utime _8
|
||||
32 PLDU // utime _6
|
||||
}> // utime start_at
|
||||
SWAP // start_at utime
|
||||
}> // start_at utime
|
||||
OVER // start_at utime start_at
|
||||
IF:<{ // start_at utime
|
||||
SWAP // utime start_at
|
||||
SUB // _11
|
||||
}>ELSE<{ // start_at utime
|
||||
2DROP //
|
||||
-1 PUSHINT // _11=-1
|
||||
}>
|
||||
}>
|
||||
recv_external PROC:<{
|
||||
@ -42,66 +52,73 @@ PROGRAM{
|
||||
35 THROWIF
|
||||
c4 PUSH // signature in_msg msg_seqno cs _19
|
||||
CTOS // signature in_msg msg_seqno cs ds
|
||||
32 LDU // signature in_msg msg_seqno cs _24 ds
|
||||
256 LDU // signature in_msg msg_seqno cs _24 _27 ds
|
||||
LDDICT // signature in_msg msg_seqno cs stored_seqno public_key rdict ds
|
||||
32 LDU // signature in_msg msg_seqno cs _25 ds
|
||||
256 LDU // signature in_msg msg_seqno cs _25 _28 ds
|
||||
32 LDU // signature in_msg msg_seqno cs _25 _28 _31 ds
|
||||
LDDICT // signature in_msg msg_seqno cs stored_seqno public_key start_at rdict ds
|
||||
ENDS
|
||||
s4 s2 PUSH2 // signature in_msg msg_seqno cs stored_seqno public_key rdict msg_seqno stored_seqno
|
||||
EQUAL // signature in_msg msg_seqno cs stored_seqno public_key rdict _34
|
||||
s5 s3 PUSH2 // signature in_msg msg_seqno cs stored_seqno public_key start_at rdict msg_seqno stored_seqno
|
||||
EQUAL // signature in_msg msg_seqno cs stored_seqno public_key start_at rdict _38
|
||||
33 THROWIFNOT
|
||||
s0 s4 XCHG // signature in_msg rdict cs stored_seqno public_key msg_seqno
|
||||
IFNOTJMP:<{ // signature in_msg rdict cs stored_seqno public_key
|
||||
s2 POP
|
||||
s0 s5 XCHG // signature in_msg rdict cs stored_seqno public_key start_at msg_seqno
|
||||
IFNOTJMP:<{ // signature in_msg rdict cs stored_seqno public_key start_at
|
||||
s3 POP
|
||||
s3 POP // public_key stored_seqno rdict
|
||||
s4 POP
|
||||
s4 POP // stored_seqno public_key rdict start_at
|
||||
ACCEPT
|
||||
SWAP // public_key rdict stored_seqno
|
||||
INC // public_key rdict _38
|
||||
NEWC // public_key rdict _38 _39
|
||||
32 STU // public_key rdict _41
|
||||
s1 s2 XCHG // rdict public_key _41
|
||||
256 STU // rdict _43
|
||||
STDICT // _44
|
||||
ENDC // _45
|
||||
s0 s3 XCHG // start_at public_key rdict stored_seqno
|
||||
INC // start_at public_key rdict _42
|
||||
NEWC // start_at public_key rdict _42 _43
|
||||
32 STU // start_at public_key rdict _45
|
||||
s1 s2 XCHG // start_at rdict public_key _45
|
||||
256 STU // start_at rdict _47
|
||||
s1 s2 XCHG // rdict start_at _47
|
||||
32 STU // rdict _49
|
||||
STDICT // _50
|
||||
ENDC // _51
|
||||
c4 POP
|
||||
}> // signature in_msg rdict cs stored_seqno public_key
|
||||
s0 s4 XCHG // signature public_key rdict cs stored_seqno in_msg
|
||||
HASHSU // signature public_key rdict cs stored_seqno _48
|
||||
s0 s5 s4 XC2PU // stored_seqno public_key rdict cs _48 signature public_key
|
||||
CHKSIGNU // stored_seqno public_key rdict cs _49
|
||||
}> // signature in_msg rdict cs stored_seqno public_key start_at
|
||||
s0 s5 XCHG // signature start_at rdict cs stored_seqno public_key in_msg
|
||||
HASHSU // signature start_at rdict cs stored_seqno public_key _54
|
||||
s0 s6 s6 XC2PU // public_key start_at rdict cs stored_seqno _54 signature public_key
|
||||
CHKSIGNU // public_key start_at rdict cs stored_seqno _55
|
||||
34 THROWIFNOT
|
||||
ACCEPT
|
||||
days_passed INLINECALLDICT // stored_seqno public_key rdict cs ts
|
||||
s2 PUSH
|
||||
16 PUSHINT // stored_seqno public_key rdict cs ts rdict _57=16
|
||||
s3 PUSH
|
||||
NOW // public_key start_at rdict cs stored_seqno start_at _59
|
||||
seconds_passed INLINECALLDICT // public_key start_at rdict cs stored_seqno ts
|
||||
s3 PUSH
|
||||
32 PUSHINT // public_key start_at rdict cs stored_seqno ts rdict _64=32
|
||||
DICTIGETPREVEQ
|
||||
NULLSWAPIFNOT2 // stored_seqno public_key rdict cs _98 _97 _99
|
||||
NIP // stored_seqno public_key rdict cs value found
|
||||
IF:<{ // stored_seqno public_key rdict cs value
|
||||
LDGRAMS // stored_seqno public_key rdict cs _101 _100
|
||||
DROP // stored_seqno public_key rdict cs _59
|
||||
2 PUSHINT // stored_seqno public_key rdict cs _59 _61=2
|
||||
NULLSWAPIFNOT2 // public_key start_at rdict cs stored_seqno _109 _108 _110
|
||||
NIP // public_key start_at rdict cs stored_seqno value found
|
||||
IF:<{ // public_key start_at rdict cs stored_seqno value
|
||||
LDGRAMS // public_key start_at rdict cs stored_seqno _112 _111
|
||||
DROP // public_key start_at rdict cs stored_seqno _66
|
||||
2 PUSHINT // public_key start_at rdict cs stored_seqno _66 _68=2
|
||||
RAWRESERVE
|
||||
}>ELSE<{
|
||||
DROP // stored_seqno public_key rdict cs
|
||||
}> // stored_seqno public_key rdict cs
|
||||
DROP // public_key start_at rdict cs stored_seqno
|
||||
}>
|
||||
SWAP // public_key start_at rdict stored_seqno cs
|
||||
WHILE:<{
|
||||
DUP // stored_seqno public_key rdict cs cs
|
||||
SREFS // stored_seqno public_key rdict cs _65
|
||||
}>DO<{ // stored_seqno public_key rdict cs
|
||||
8 LDU // stored_seqno public_key rdict mode cs
|
||||
LDREF // stored_seqno public_key rdict mode msg cs
|
||||
s0 s2 XCHG // stored_seqno public_key rdict cs msg mode
|
||||
DUP // public_key start_at rdict stored_seqno cs cs
|
||||
SREFS // public_key start_at rdict stored_seqno cs _72
|
||||
}>DO<{ // public_key start_at rdict stored_seqno cs
|
||||
8 LDU // public_key start_at rdict stored_seqno mode cs
|
||||
LDREF // public_key start_at rdict stored_seqno mode msg cs
|
||||
s0 s2 XCHG // public_key start_at rdict stored_seqno cs msg mode
|
||||
SENDRAWMSG
|
||||
}> // stored_seqno public_key rdict cs
|
||||
}> // public_key start_at rdict stored_seqno cs
|
||||
ENDS
|
||||
s0 s2 XCHG // rdict public_key stored_seqno
|
||||
INC // rdict public_key _76
|
||||
NEWC // rdict public_key _76 _77
|
||||
32 STU // rdict public_key _79
|
||||
256 STU // rdict _81
|
||||
STDICT // _82
|
||||
ENDC // _83
|
||||
INC // public_key start_at rdict _83
|
||||
NEWC // public_key start_at rdict _83 _84
|
||||
32 STU // public_key start_at rdict _86
|
||||
s1 s3 XCHG // rdict start_at public_key _86
|
||||
256 STU // rdict start_at _88
|
||||
32 STU // rdict _90
|
||||
STDICT // _91
|
||||
ENDC // _92
|
||||
c4 POP
|
||||
}>
|
||||
seqno PROC:<{
|
||||
@ -118,30 +135,41 @@ PROGRAM{
|
||||
NIP // cs
|
||||
256 PLDU // _7
|
||||
}>
|
||||
balance PROC:<{
|
||||
//
|
||||
c4 PUSH // _1
|
||||
CTOS // _2
|
||||
288 PUSHINT // _2 _5
|
||||
SDSKIPFIRST // ds
|
||||
LDDICT // rdict ds
|
||||
compute_balance_at PROCREF:<{
|
||||
// utime
|
||||
c4 PUSH // utime _2
|
||||
CTOS // utime _3
|
||||
288 PUSHINT // utime _3 _6
|
||||
SDSKIPFIRST // utime ds
|
||||
32 LDU // utime _10 ds
|
||||
LDDICT // utime start_at rdict ds
|
||||
ENDS
|
||||
days_passed INLINECALLDICT // rdict ts
|
||||
BALANCE // rdict ts _14
|
||||
s0 s2 XCHG // rdict start_at utime
|
||||
seconds_passed INLINECALLDICT // rdict ts
|
||||
BALANCE // rdict ts _19
|
||||
FIRST // rdict ts balance
|
||||
s0 s2 XCHG
|
||||
16 PUSHINT // balance ts rdict _19=16
|
||||
32 PUSHINT // balance ts rdict _24=32
|
||||
DICTIGETPREVEQ
|
||||
NULLSWAPIFNOT2 // balance _29 _28 _30
|
||||
NULLSWAPIFNOT2 // balance _36 _35 _37
|
||||
NIP // balance value found
|
||||
IF:<{ // balance value
|
||||
LDGRAMS // balance _32 _31
|
||||
DROP // balance _21
|
||||
SUB // _23
|
||||
0 PUSHINT // _23 _24=0
|
||||
LDGRAMS // balance _39 _38
|
||||
DROP // balance _26
|
||||
SUB // _28
|
||||
0 PUSHINT // _28 _29=0
|
||||
MAX // balance
|
||||
}>ELSE<{
|
||||
DROP // balance
|
||||
}>
|
||||
}>
|
||||
balance_at PROC:<{
|
||||
// utime
|
||||
compute_balance_at INLINECALLDICT // _1
|
||||
}>
|
||||
balance PROC:<{
|
||||
//
|
||||
NOW // _0
|
||||
compute_balance_at INLINECALLDICT // _1
|
||||
}>
|
||||
}END>c
|
||||
|
@ -0,0 +1 @@
|
||||
with_tvm_code("restricted-wallet3", "te6ccgECEgEAAUsAART/APSkE/S88sgLAQIBIAIDAgFIBAUD+PKDCNcYINMf0x/THwL4I7vyY+1E0NMf0x/T/1NDuvKhUWK68qIG+QFUEHb5EPKkAY4fMwHT/9EB0x/0BNH4AAOkyMsfFMsfy/8Syx/0AMntVOEC0x/0BNH4ACH4I9s8IYAg9HtvpTGW+gAwcvsCkTDiApMg10qK6NECpMgPEBEABNAwAgEgBgcCASAICQIBSAwNAgFuCgsAEbjJftRNDXCx+AAXrc52omhpn5jrhf/AABesePaiaGmPmOuFj8ABDbbYHwR7Z5AOAQm1B1tnkA4BTu1E0IEBQNch0x/0BNEC2zz4J28QAoAg9HtvpTGX+gAwoXC2CZEw4g8AOiGOETGA8/gzIG6SMHCU0NcLH+IB3yGSAaGSW3/iAAzTB9QC+wAAHssfFMsfEsv/yx/0AMntVA==");
|
@ -0,0 +1,199 @@
|
||||
// automatically generated from `smartcont/stdlib.fc` `smartcont/restricted-wallet3-code.fc`
|
||||
PROGRAM{
|
||||
DECLPROC recv_internal
|
||||
DECLPROC seconds_passed
|
||||
DECLPROC recv_external
|
||||
85143 DECLMETHOD seqno
|
||||
80113 DECLMETHOD wallet_id
|
||||
78748 DECLMETHOD get_public_key
|
||||
DECLPROC compute_balance_at
|
||||
108602 DECLMETHOD balance_at
|
||||
104128 DECLMETHOD balance
|
||||
recv_internal PROC:<{
|
||||
// in_msg
|
||||
DROP //
|
||||
}>
|
||||
seconds_passed PROCREF:<{
|
||||
// start_at utime
|
||||
OVER // start_at utime start_at
|
||||
IFNOT:<{ // start_at utime
|
||||
NIP // utime
|
||||
-13 PUSHINT // utime _3=-13
|
||||
CONFIGOPTPARAM // utime p
|
||||
DUP // utime p p
|
||||
ISNULL // utime p _5
|
||||
IF:<{ // utime p
|
||||
DROP // utime
|
||||
0 PUSHINT // utime _6=0
|
||||
}>ELSE<{ // utime p
|
||||
CTOS // utime _8
|
||||
32 PLDU // utime _6
|
||||
}> // utime start_at
|
||||
SWAP // start_at utime
|
||||
}> // start_at utime
|
||||
OVER // start_at utime start_at
|
||||
IF:<{ // start_at utime
|
||||
SWAP // utime start_at
|
||||
SUB // _11
|
||||
}>ELSE<{ // start_at utime
|
||||
2DROP //
|
||||
-1 PUSHINT // _11=-1
|
||||
}>
|
||||
}>
|
||||
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
|
||||
s0 s2 XCHG
|
||||
NOW // 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
|
||||
s4 s3 PUSH2 // signature in_msg subwallet_id cs msg_seqno stored_seqno stored_subwallet public_key ds msg_seqno stored_seqno
|
||||
EQUAL // signature in_msg subwallet_id cs msg_seqno stored_seqno stored_subwallet public_key ds _38
|
||||
33 THROWIFNOT
|
||||
s6 s2 XCPU // signature in_msg ds cs msg_seqno stored_seqno stored_subwallet public_key subwallet_id stored_subwallet
|
||||
EQUAL // signature in_msg ds cs msg_seqno stored_seqno stored_subwallet public_key _41
|
||||
34 THROWIFNOT
|
||||
s0 s6 XCHG // signature public_key ds cs msg_seqno stored_seqno stored_subwallet in_msg
|
||||
HASHSU // signature public_key ds cs msg_seqno stored_seqno stored_subwallet _44
|
||||
s0 s7 s6 XC2PU // stored_subwallet public_key ds cs msg_seqno stored_seqno _44 signature public_key
|
||||
CHKSIGNU // stored_subwallet public_key ds cs msg_seqno stored_seqno _45
|
||||
36 THROWIFNOT
|
||||
SWAP // stored_subwallet public_key ds cs stored_seqno msg_seqno
|
||||
IFNOTJMP:<{ // stored_subwallet public_key ds cs stored_seqno
|
||||
s3 POP // stored_subwallet stored_seqno ds cs
|
||||
SWAP // stored_subwallet stored_seqno cs ds
|
||||
256 LDU // stored_subwallet stored_seqno cs public_key ds
|
||||
ENDS
|
||||
SWAP // stored_subwallet stored_seqno public_key cs
|
||||
32 LDU // stored_subwallet stored_seqno public_key _55 cs
|
||||
LDDICT // stored_subwallet stored_seqno public_key start_at rdict cs
|
||||
ENDS
|
||||
ACCEPT
|
||||
s0 s3 XCHG // stored_subwallet rdict public_key start_at stored_seqno
|
||||
INC // stored_subwallet rdict public_key start_at _63
|
||||
NEWC // stored_subwallet rdict public_key start_at _63 _64
|
||||
32 STU // stored_subwallet rdict public_key start_at _66
|
||||
s1 s4 XCHG // start_at rdict public_key stored_subwallet _66
|
||||
32 STU // start_at rdict public_key _68
|
||||
256 STU // start_at rdict _70
|
||||
s1 s2 XCHG // rdict start_at _70
|
||||
32 STU // rdict _72
|
||||
STDICT // _73
|
||||
ENDC // _74
|
||||
c4 POP
|
||||
}> // stored_subwallet public_key ds cs stored_seqno
|
||||
s0 s2 XCHG // stored_subwallet public_key stored_seqno cs ds
|
||||
32 LDU // stored_subwallet public_key stored_seqno cs _78 ds
|
||||
LDDICT // stored_subwallet public_key stored_seqno cs start_at rdict ds
|
||||
ENDS
|
||||
ACCEPT
|
||||
OVER
|
||||
NOW // stored_subwallet public_key stored_seqno cs start_at rdict start_at _86
|
||||
seconds_passed INLINECALLDICT // stored_subwallet public_key stored_seqno cs start_at rdict ts
|
||||
OVER
|
||||
32 PUSHINT // stored_subwallet public_key stored_seqno cs start_at rdict ts rdict _91=32
|
||||
DICTIGETPREVEQ
|
||||
NULLSWAPIFNOT2 // stored_subwallet public_key stored_seqno cs start_at rdict _148 _147 _149
|
||||
NIP // stored_subwallet public_key stored_seqno cs start_at rdict value found
|
||||
IF:<{ // stored_subwallet public_key stored_seqno cs start_at rdict value
|
||||
LDGRAMS // stored_subwallet public_key stored_seqno cs start_at rdict _151 _150
|
||||
DROP // stored_subwallet public_key stored_seqno cs start_at rdict _93
|
||||
2 PUSHINT // stored_subwallet public_key stored_seqno cs start_at rdict _93 _95=2
|
||||
RAWRESERVE
|
||||
}>ELSE<{
|
||||
DROP // stored_subwallet public_key stored_seqno cs start_at rdict
|
||||
}>
|
||||
s0 s2 XCHG // stored_subwallet public_key stored_seqno rdict start_at cs
|
||||
WHILE:<{
|
||||
DUP // stored_subwallet public_key stored_seqno rdict start_at cs cs
|
||||
SREFS // stored_subwallet public_key stored_seqno rdict start_at cs _99
|
||||
}>DO<{ // stored_subwallet public_key stored_seqno rdict start_at cs
|
||||
8 LDU // stored_subwallet public_key stored_seqno rdict start_at mode cs
|
||||
LDREF // stored_subwallet public_key stored_seqno rdict start_at mode msg cs
|
||||
s0 s2 XCHG // stored_subwallet public_key stored_seqno rdict start_at cs msg mode
|
||||
SENDRAWMSG
|
||||
}> // stored_subwallet public_key stored_seqno rdict start_at cs
|
||||
ENDS
|
||||
s0 s2 XCHG // stored_subwallet public_key start_at rdict stored_seqno
|
||||
INC // stored_subwallet public_key start_at rdict _110
|
||||
NEWC // stored_subwallet public_key start_at rdict _110 _111
|
||||
32 STU // stored_subwallet public_key start_at rdict _113
|
||||
s1 s4 XCHG // rdict public_key start_at stored_subwallet _113
|
||||
32 STU // rdict public_key start_at _115
|
||||
s1 s2 XCHG // rdict start_at public_key _115
|
||||
256 STU // rdict start_at _117
|
||||
32 STU // rdict _119
|
||||
STDICT // _120
|
||||
ENDC // _121
|
||||
c4 POP
|
||||
}>
|
||||
seqno PROC:<{
|
||||
//
|
||||
c4 PUSH // _0
|
||||
CTOS // _1
|
||||
32 PLDU // _3
|
||||
}>
|
||||
wallet_id PROC:<{
|
||||
//
|
||||
c4 PUSH // _1
|
||||
CTOS // ds
|
||||
32 LDU // _9 _8
|
||||
NIP // ds
|
||||
32 PLDU // _7
|
||||
}>
|
||||
get_public_key PROC:<{
|
||||
//
|
||||
c4 PUSH // _1
|
||||
CTOS // ds
|
||||
64 LDU // _11 _10
|
||||
NIP // ds
|
||||
256 PLDU // _9
|
||||
}>
|
||||
compute_balance_at PROCREF:<{
|
||||
// utime
|
||||
c4 PUSH // utime _2
|
||||
CTOS // utime _3
|
||||
320 PUSHINT // utime _3 _8
|
||||
SDSKIPFIRST // utime ds
|
||||
32 LDU // utime _12 ds
|
||||
LDDICT // utime start_at rdict ds
|
||||
ENDS
|
||||
s0 s2 XCHG // rdict start_at utime
|
||||
seconds_passed INLINECALLDICT // rdict ts
|
||||
BALANCE // rdict ts _21
|
||||
FIRST // rdict ts balance
|
||||
s0 s2 XCHG
|
||||
32 PUSHINT // balance ts rdict _26=32
|
||||
DICTIGETPREVEQ
|
||||
NULLSWAPIFNOT2 // balance _38 _37 _39
|
||||
NIP // balance value found
|
||||
IF:<{ // balance value
|
||||
LDGRAMS // balance _41 _40
|
||||
DROP // balance _28
|
||||
SUB // _30
|
||||
0 PUSHINT // _30 _31=0
|
||||
MAX // balance
|
||||
}>ELSE<{
|
||||
DROP // balance
|
||||
}>
|
||||
}>
|
||||
balance_at PROC:<{
|
||||
// utime
|
||||
compute_balance_at INLINECALLDICT // _1
|
||||
}>
|
||||
balance PROC:<{
|
||||
//
|
||||
NOW // _0
|
||||
compute_balance_at INLINECALLDICT // _1
|
||||
}>
|
||||
}END>c
|
323
submodules/ton/tonlib-src/crypto/smartcont/config-code.fif
Normal file
323
submodules/ton/tonlib-src/crypto/smartcont/config-code.fif
Normal file
@ -0,0 +1,323 @@
|
||||
// automatically generated from `smartcont/stdlib.fc` `smartcont/config-code.fc`
|
||||
PROGRAM{
|
||||
DECLPROC set_conf_param
|
||||
DECLPROC check_validator_set
|
||||
DECLPROC send_answer
|
||||
DECLPROC send_confirmation
|
||||
DECLPROC send_error
|
||||
DECLPROC recv_internal
|
||||
DECLPROC change_elector_code
|
||||
DECLPROC recv_external
|
||||
DECLPROC run_ticktock
|
||||
set_conf_param PROC:<{
|
||||
// index value
|
||||
c4 PUSH // index value _3
|
||||
CTOS // index value cs
|
||||
LDREF // index value cfg_dict cs
|
||||
s3 s3 XCHG2
|
||||
32 PUSHINT // cs value index cfg_dict _9=32
|
||||
DICTISETREF // cs cfg_dict
|
||||
NEWC // cs cfg_dict _11
|
||||
STREF // cs _12
|
||||
SWAP // _12 cs
|
||||
STSLICER // _13
|
||||
ENDC // _14
|
||||
c4 POP
|
||||
}>
|
||||
check_validator_set PROC:<{
|
||||
// vset
|
||||
CTOS // cs
|
||||
8 LDU // _4 cs
|
||||
SWAP // cs _4
|
||||
17 EQINT // cs _8
|
||||
9 THROWIFNOT
|
||||
32 LDU // utime_since cs
|
||||
32 LDU // utime_since utime_until cs
|
||||
16 LDU // utime_since utime_until total cs
|
||||
16 LDU // utime_since utime_until total _42 _41
|
||||
DROP // utime_since utime_until total main
|
||||
DUP // utime_since utime_until total main main
|
||||
0 GTINT // utime_since utime_until total main _28
|
||||
9 THROWIFNOT
|
||||
GEQ // utime_since utime_until _31
|
||||
9 THROWIFNOT
|
||||
}>
|
||||
send_answer PROC:<{
|
||||
// addr query_id ans_tag mode
|
||||
0 PUSHINT // addr query_id ans_tag mode _4=0
|
||||
24 PUSHINT // addr query_id ans_tag mode _4=0 _5=24
|
||||
NEWC // addr query_id ans_tag mode _4=0 _5=24 _6
|
||||
6 STU // addr query_id ans_tag mode _4=0 _8
|
||||
s0 s5 XCHG2 // _4=0 query_id ans_tag mode _8 addr
|
||||
STSLICER // _4=0 query_id ans_tag mode _9
|
||||
s1 s4 XCHG // mode query_id ans_tag _4=0 _9
|
||||
111 STU // mode query_id ans_tag _23
|
||||
32 STU // mode query_id _25
|
||||
64 STU // mode _27
|
||||
ENDC // mode _28
|
||||
SWAP // _28 mode
|
||||
SENDRAWMSG
|
||||
}>
|
||||
send_confirmation PROC:<{
|
||||
// addr query_id ans_tag
|
||||
64 PUSHINT // addr query_id ans_tag _3=64
|
||||
send_answer CALLDICT
|
||||
}>
|
||||
send_error PROC:<{
|
||||
// addr query_id ans_tag
|
||||
64 PUSHINT // addr query_id ans_tag _3=64
|
||||
send_answer CALLDICT
|
||||
}>
|
||||
recv_internal PROC:<{
|
||||
// in_msg_cell in_msg
|
||||
SWAP // in_msg in_msg_cell
|
||||
CTOS // in_msg cs
|
||||
4 LDU // in_msg flags cs
|
||||
LDMSGADDR // in_msg flags _74 _73
|
||||
DROP // in_msg flags s_addr
|
||||
DUP // in_msg flags s_addr s_addr
|
||||
REWRITESTDADDR // in_msg flags s_addr src_wc src_addr
|
||||
SWAP // in_msg flags s_addr src_addr src_wc
|
||||
INC // in_msg flags s_addr src_addr _15
|
||||
s0 s3 XCHG
|
||||
1 PUSHINT // in_msg _15 s_addr src_addr flags _16=1
|
||||
AND // in_msg _15 s_addr src_addr _17
|
||||
s1 s3 XCHG // in_msg src_addr s_addr _15 _17
|
||||
OR // in_msg src_addr s_addr _18
|
||||
s3 PUSH // in_msg src_addr s_addr _18 in_msg
|
||||
SEMPTY // in_msg src_addr s_addr _18 _19
|
||||
OR // in_msg src_addr s_addr _20
|
||||
IFJMP:<{ // in_msg src_addr s_addr
|
||||
3 BLKDROP //
|
||||
}> // in_msg src_addr s_addr
|
||||
s0 s2 XCHG // s_addr src_addr in_msg
|
||||
32 LDU // s_addr src_addr tag in_msg
|
||||
64 LDU // s_addr src_addr tag query_id in_msg
|
||||
s2 PUSH
|
||||
1314280276 PUSHINT // s_addr src_addr tag query_id in_msg tag _29=1314280276
|
||||
EQUAL // s_addr src_addr tag query_id in_msg _30
|
||||
IFJMP:<{ // s_addr src_addr tag query_id in_msg
|
||||
s2 POP // s_addr src_addr in_msg query_id
|
||||
SWAP // s_addr src_addr query_id in_msg
|
||||
LDREF // s_addr src_addr query_id vset in_msg
|
||||
ENDS
|
||||
1 PUSHINT // s_addr src_addr query_id vset _36=1
|
||||
CONFIGOPTPARAM // s_addr src_addr query_id vset elector_param
|
||||
DUP // s_addr src_addr query_id vset elector_param elector_param
|
||||
ISNULL // s_addr src_addr query_id vset elector_param _39
|
||||
IF:<{ // s_addr src_addr query_id vset elector_param
|
||||
DROP // s_addr src_addr query_id vset
|
||||
-1 PUSHINT // s_addr src_addr query_id vset _40=-1
|
||||
}>ELSE<{ // s_addr src_addr query_id vset elector_param
|
||||
CTOS // s_addr src_addr query_id vset _42
|
||||
256 PLDU // s_addr src_addr query_id vset _40
|
||||
}> // s_addr src_addr query_id vset elector_addr
|
||||
s0 s3 XCHG
|
||||
FALSE
|
||||
s0 s4 XCHG // s_addr ok query_id vset src_addr elector_addr
|
||||
EQUAL // s_addr ok query_id vset _47
|
||||
IF:<{ // s_addr ok query_id vset
|
||||
s2 POP // s_addr vset query_id
|
||||
OVER // s_addr vset query_id vset
|
||||
check_validator_set CALLDICT // s_addr vset query_id t_since t_until
|
||||
OVER
|
||||
NOW // s_addr vset query_id t_since t_until t_since t
|
||||
GREATER // s_addr vset query_id t_since t_until _53
|
||||
s0 s2 XCHG // s_addr vset query_id _53 t_until t_since
|
||||
GREATER // s_addr vset query_id _53 _54
|
||||
AND // s_addr vset query_id ok
|
||||
}>ELSE<{
|
||||
s0 s2 XCHG // s_addr vset query_id ok
|
||||
}>
|
||||
IFJMP:<{ // s_addr vset query_id
|
||||
36 PUSHINT // s_addr vset query_id _56=36
|
||||
ROT // s_addr query_id _56=36 vset
|
||||
set_conf_param CALLDICT
|
||||
4000730955 PUSHINT // s_addr query_id _58=4000730955
|
||||
send_confirmation CALLDICT
|
||||
}> // s_addr vset query_id
|
||||
NIP // s_addr query_id
|
||||
4000730991 PUSHINT // s_addr query_id _60=4000730991
|
||||
send_error CALLDICT
|
||||
}> // s_addr src_addr tag query_id in_msg
|
||||
s2 s4 XCHG
|
||||
4 BLKDROP // tag
|
||||
DUP // tag tag
|
||||
0 EQINT // tag _64
|
||||
SWAP
|
||||
31 PUSHPOW2 // _64 tag _67
|
||||
AND // _64 _68
|
||||
OR // _69
|
||||
37 THROWIFNOT
|
||||
}>
|
||||
change_elector_code PROC:<{
|
||||
// cs
|
||||
1 PUSHINT // cs _2=1
|
||||
CONFIGOPTPARAM // cs _3
|
||||
CTOS // cs _4
|
||||
256 PLDU // cs dest_addr
|
||||
NOW // cs dest_addr query_id
|
||||
1313042276 PUSHINT // cs dest_addr query_id _9=1313042276
|
||||
0 PUSHINT // cs dest_addr query_id _9=1313042276 _10=0
|
||||
50431 PUSHINT // cs dest_addr query_id _9=1313042276 _10=0 _11=50431
|
||||
NEWC // cs dest_addr query_id _9=1313042276 _10=0 _11=50431 _12
|
||||
17 STU // cs dest_addr query_id _9=1313042276 _10=0 _14
|
||||
s1 s4 XCHG // cs _10=0 query_id _9=1313042276 dest_addr _14
|
||||
256 STU // cs _10=0 query_id _9=1313042276 _16
|
||||
30 PUSHPOW2 // cs _10=0 query_id _9=1313042276 _16 _19
|
||||
STGRAMS // cs _10=0 query_id _9=1313042276 _20
|
||||
s1 s3 XCHG // cs _9=1313042276 query_id _10=0 _20
|
||||
107 STU // cs _9=1313042276 query_id _34
|
||||
s1 s2 XCHG // cs query_id _9=1313042276 _34
|
||||
32 STU // cs query_id _36
|
||||
64 STU // cs _38
|
||||
SWAP // _38 cs
|
||||
STSLICER // _39
|
||||
ENDC // _40
|
||||
0 PUSHINT // _40 _41=0
|
||||
SENDRAWMSG
|
||||
}>
|
||||
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 action cs
|
||||
32 LDU // signature in_msg action msg_seqno cs
|
||||
32 LDU // signature in_msg action msg_seqno valid_until cs
|
||||
NOW // signature in_msg action msg_seqno valid_until cs _19
|
||||
s1 s2 XCHG // signature in_msg action msg_seqno cs valid_until _19
|
||||
LESS // signature in_msg action msg_seqno cs _20
|
||||
35 THROWIF
|
||||
c4 PUSH // signature in_msg action msg_seqno cs _23
|
||||
CTOS // signature in_msg action msg_seqno cs cs2
|
||||
LDREF // signature in_msg action msg_seqno cs cfg_dict cs2
|
||||
32 LDU // signature in_msg action msg_seqno cs cfg_dict stored_seqno cs2
|
||||
256 LDU // signature in_msg action msg_seqno cs cfg_dict stored_seqno public_key cs2
|
||||
ENDS
|
||||
s4 s1 XCPU // signature in_msg action public_key cs cfg_dict stored_seqno msg_seqno stored_seqno
|
||||
EQUAL // signature in_msg action public_key cs cfg_dict stored_seqno _38
|
||||
33 THROWIFNOT
|
||||
s0 s5 XCHG // signature stored_seqno action public_key cs cfg_dict in_msg
|
||||
HASHSU // signature stored_seqno action public_key cs cfg_dict _41
|
||||
s0 s6 s3 XC2PU // cfg_dict stored_seqno action public_key cs _41 signature public_key
|
||||
CHKSIGNU // cfg_dict stored_seqno action public_key cs _42
|
||||
34 THROWIFNOT
|
||||
ACCEPT
|
||||
s2 PUSH
|
||||
1130778657 PUSHINT // cfg_dict stored_seqno action public_key cs action _45=1130778657
|
||||
EQUAL // cfg_dict stored_seqno action public_key cs _46
|
||||
IF:<{ // cfg_dict stored_seqno action public_key cs
|
||||
s2 POP // cfg_dict stored_seqno cs public_key
|
||||
SWAP // cfg_dict stored_seqno public_key cs
|
||||
32 LDU // cfg_dict stored_seqno public_key param_index cs
|
||||
LDREF // cfg_dict stored_seqno public_key param_index param_value cs
|
||||
ENDS
|
||||
s0 s1 s4 XCHG3
|
||||
32 PUSHINT // public_key stored_seqno param_value param_index cfg_dict _56=32
|
||||
DICTISETREF // public_key stored_seqno cfg_dict
|
||||
}>ELSE<{ // cfg_dict stored_seqno action public_key cs
|
||||
s2 PUSH
|
||||
1313042276 PUSHINT // cfg_dict stored_seqno action public_key cs action _58=1313042276
|
||||
EQUAL // cfg_dict stored_seqno action public_key cs _59
|
||||
IF:<{ // cfg_dict stored_seqno action public_key cs
|
||||
s2 POP // cfg_dict stored_seqno cs public_key
|
||||
SWAP // cfg_dict stored_seqno public_key cs
|
||||
LDREF // cfg_dict stored_seqno public_key new_code cs
|
||||
ENDS
|
||||
SETCODE
|
||||
}>ELSE<{ // cfg_dict stored_seqno action public_key cs
|
||||
s2 PUSH
|
||||
1348619041 PUSHINT // cfg_dict stored_seqno action public_key cs action _65=1348619041
|
||||
EQUAL // cfg_dict stored_seqno action public_key cs _66
|
||||
IF:<{ // cfg_dict stored_seqno action public_key cs
|
||||
NIP
|
||||
NIP // cfg_dict stored_seqno cs
|
||||
256 LDU // cfg_dict stored_seqno public_key cs
|
||||
ENDS
|
||||
}>ELSE<{ // cfg_dict stored_seqno action public_key cs
|
||||
s2 PUSH
|
||||
1313074949 PUSHINT // cfg_dict stored_seqno action public_key cs action _71=1313074949
|
||||
EQUAL // cfg_dict stored_seqno action public_key cs _72
|
||||
IF:<{ // cfg_dict stored_seqno action public_key cs
|
||||
s2 POP // cfg_dict stored_seqno cs public_key
|
||||
SWAP // cfg_dict stored_seqno public_key cs
|
||||
change_elector_code CALLDICT
|
||||
}>ELSE<{ // cfg_dict stored_seqno action public_key cs
|
||||
DROP // cfg_dict stored_seqno action public_key
|
||||
SWAP // cfg_dict stored_seqno public_key action
|
||||
32 THROWIF
|
||||
}>
|
||||
}>
|
||||
}>
|
||||
s0 s2 XCHG // public_key stored_seqno cfg_dict
|
||||
}>
|
||||
SWAP // public_key cfg_dict stored_seqno
|
||||
INC // public_key cfg_dict _77
|
||||
NEWC // public_key cfg_dict _77 _78
|
||||
s1 s2 XCHG // public_key _77 cfg_dict _78
|
||||
STREF // public_key _77 _79
|
||||
32 STU // public_key _81
|
||||
256 STU // _83
|
||||
ENDC // _84
|
||||
c4 POP
|
||||
}>
|
||||
run_ticktock PROC:<{
|
||||
// is_tock
|
||||
DROP //
|
||||
c4 PUSH // _2
|
||||
CTOS // cs
|
||||
LDREF // cfg_dict cs
|
||||
32 PUSHINT // cfg_dict cs kl=32
|
||||
36 PUSHINT // cfg_dict cs kl=32 _10=36
|
||||
s3 s1 PUSH2 // cfg_dict cs kl=32 _10=36 cfg_dict kl=32
|
||||
DICTIGETOPTREF // cfg_dict cs kl=32 next_vset
|
||||
DUP // cfg_dict cs kl=32 next_vset next_vset
|
||||
ISNULL // cfg_dict cs kl=32 next_vset _12
|
||||
IFNOT:<{ // cfg_dict cs kl=32 next_vset
|
||||
DUP // cfg_dict cs kl=32 next_vset next_vset
|
||||
CTOS // cfg_dict cs kl=32 next_vset ds
|
||||
DUP // cfg_dict cs kl=32 next_vset ds ds
|
||||
SBITS // cfg_dict cs kl=32 next_vset ds _15
|
||||
39 GTINT // cfg_dict cs kl=32 next_vset ds _17
|
||||
IF:<{ // cfg_dict cs kl=32 next_vset ds
|
||||
8 LDU // cfg_dict cs kl=32 next_vset tag ds
|
||||
32 PLDU // cfg_dict cs kl=32 next_vset tag since
|
||||
SWAP // cfg_dict cs kl=32 next_vset since tag
|
||||
17 EQINT // cfg_dict cs kl=32 next_vset since _26
|
||||
NOW // cfg_dict cs kl=32 next_vset since _26 _27
|
||||
s1 s2 XCHG // cfg_dict cs kl=32 next_vset _26 since _27
|
||||
GEQ // cfg_dict cs kl=32 next_vset _26 _28
|
||||
AND // cfg_dict cs kl=32 next_vset _29
|
||||
IF:<{ // cfg_dict cs kl=32 next_vset
|
||||
SWAP
|
||||
34 PUSHINT
|
||||
s0 s4 s4 XC2PU // kl=32 cs next_vset _32=34 cfg_dict kl=32
|
||||
DICTISETGETOPTREF // kl=32 cs cfg_dict cur_vset
|
||||
s3 s1 s0 PUXCPU // kl=32 cs cur_vset _35=32 cfg_dict kl=32
|
||||
DICTISETGETOPTREF // kl=32 cs _51 _52
|
||||
DROP // kl=32 cs cfg_dict
|
||||
36 PUSHINT // kl=32 cs cfg_dict _38=36
|
||||
s0 s1 s3 XCHG3 // cs _38=36 cfg_dict kl=32
|
||||
DICTIDEL // cs _53 _54
|
||||
DROP // cs cfg_dict
|
||||
}>ELSE<{
|
||||
s2 s3 XCHG
|
||||
2DROP // cs cfg_dict
|
||||
}>
|
||||
}>ELSE<{
|
||||
s3 s4 XCHG
|
||||
3 BLKDROP // cs cfg_dict
|
||||
}>
|
||||
}>ELSE<{
|
||||
s2 s3 XCHG
|
||||
2DROP // cs cfg_dict
|
||||
}>
|
||||
NEWC // cs cfg_dict _40
|
||||
STREF // cs _41
|
||||
SWAP // _41 cs
|
||||
STSLICER // _42
|
||||
ENDC // _43
|
||||
c4 POP
|
||||
}>
|
||||
}END>c
|
@ -1097,8 +1097,21 @@ tuple past_elections() method_id {
|
||||
do {
|
||||
(id, var fs, var found) = past_elections.udict_get_prev?(32, id);
|
||||
if (found) {
|
||||
var info = [unpack_past_election(fs)];
|
||||
list = cons(pair(id, info), list);
|
||||
list = cons([id, unpack_past_election(fs)], list);
|
||||
}
|
||||
} until (~ found);
|
||||
return list;
|
||||
}
|
||||
|
||||
tuple past_elections_list() method_id {
|
||||
var (elect, credits, past_elections, grams, active_id, active_hash) = load_data();
|
||||
var id = (1 << 32);
|
||||
var list = null();
|
||||
do {
|
||||
(id, var fs, var found) = past_elections.udict_get_prev?(32, id);
|
||||
if (found) {
|
||||
var (unfreeze_at, stake_held, vset_hash, frozen_dict, total_stake, bonuses, complaints) = unpack_past_election(fs);
|
||||
list = cons([id, unfreeze_at, vset_hash, stake_held], list);
|
||||
}
|
||||
} until (~ found);
|
||||
return list;
|
||||
|
1712
submodules/ton/tonlib-src/crypto/smartcont/elector-code.fif
Normal file
1712
submodules/ton/tonlib-src/crypto/smartcont/elector-code.fif
Normal file
File diff suppressed because it is too large
Load Diff
@ -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,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
|
@ -29,8 +29,8 @@ def? $3 { @' $3 } { "rwallet" } cond constant file-base
|
||||
} : make-rdict
|
||||
|
||||
// Create new restricted wallet; code taken from `auto/restricted-wallet2-code.fif`
|
||||
"auto/restricted-wallet-code.fif" include // code
|
||||
<b 0 32 u, PubKey 256 u, amount make-rdict dict, b> // data
|
||||
"auto/restricted-wallet2-code.fif" include // code
|
||||
<b 0 32 u, PubKey 256 u, 0 32 u, amount make-rdict dict, b> // data
|
||||
null // no libraries
|
||||
<b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit
|
||||
dup ."StateInit: " <s csr. cr
|
||||
|
@ -0,0 +1,315 @@
|
||||
;; WARINIG: NOT READY FOR A PRODUCTION!
|
||||
|
||||
int err:wrong_a_signature() asm "31 PUSHINT";
|
||||
int err:wrong_b_signature() asm "32 PUSHINT";
|
||||
int err:msg_value_too_small() asm "33 PUSHINT";
|
||||
int err:replay_protection() asm "34 PUSHINT";
|
||||
int err:no_timeout() asm "35 PUSHINT";
|
||||
int err:expected_init() asm "36 PUSHINT";
|
||||
int err:expected_close() asm "37 PUSHINT";
|
||||
int err:no_promise_signature() asm "38 PUSHINT";
|
||||
int err:wrong_channel_id() asm "39 PUSHINT";
|
||||
|
||||
int msg:init() asm "0x27317822 PUSHINT";
|
||||
int msg:close() asm "0xf28ae183 PUSHINT";
|
||||
int msg:timeout() asm "0x43278a28 PUSHINT";
|
||||
int msg:payout() asm "0x37fe7810 PUSHINT";
|
||||
|
||||
int state:init() asm "0 PUSHINT";
|
||||
int state:close() asm "1 PUSHINT";
|
||||
int state:payout() asm "2 PUSHINT";
|
||||
|
||||
|
||||
;; A - initial balance of Alice,
|
||||
;; B - initial balance of B
|
||||
;;
|
||||
;; To determine balance we track nondecreasing list of promises
|
||||
;; promise_A ;; promised by Alice to Bob
|
||||
;; promise_B ;; promised by Bob to Alice
|
||||
;;
|
||||
;; diff - balance between Alice and Bob. 0 in the beginning
|
||||
;; diff = promise_B - promise_A;
|
||||
;; diff = clamp(diff, -A, +B);
|
||||
;;
|
||||
;; final_A = A + diff;
|
||||
;; final_B = B + diff;
|
||||
|
||||
;; Data pack/unpack
|
||||
;;
|
||||
_ unpack_data() inline_ref {
|
||||
var cs = get_data().begin_parse();
|
||||
var res = (cs~load_ref(), cs~load_ref());
|
||||
cs.end_parse();
|
||||
return res;
|
||||
}
|
||||
|
||||
_ pack_data(cell config, cell state) impure inline_ref {
|
||||
set_data(begin_cell().store_ref(config).store_ref(state).end_cell());
|
||||
}
|
||||
|
||||
;; Config pack/unpack
|
||||
;;
|
||||
;; config$_ initTimeout:int exitTimeout:int a_key:int256 b_key:int256 a_addr b_addr channel_id:uint64 = Config;
|
||||
;;
|
||||
_ unpack_config(cell config) {
|
||||
var cs = config.begin_parse();
|
||||
var res = (
|
||||
cs~load_uint(32),
|
||||
cs~load_uint(32),
|
||||
cs~load_uint(256),
|
||||
cs~load_uint(256),
|
||||
cs~load_ref().begin_parse(),
|
||||
cs~load_ref().begin_parse(),
|
||||
cs~load_uint(64));
|
||||
cs.end_parse();
|
||||
return res;
|
||||
}
|
||||
|
||||
;; takes
|
||||
;; signedMesage$_ a_sig:Maybe<int256> b_sig:Maybe<int256> msg:Message = SignedMessage;
|
||||
;; checks signatures and unwap message.
|
||||
(slice, (int, int)) unwrap_signatures(slice cs, int a_key, int b_key) {
|
||||
int a? = cs~load_int(1);
|
||||
slice a_sig = cs;
|
||||
if (a?) {
|
||||
a_sig = cs~load_ref().begin_parse().preload_bits(512);
|
||||
}
|
||||
var b? = cs~load_int(1);
|
||||
slice b_sig = cs;
|
||||
if (b?) {
|
||||
b_sig = cs~load_ref().begin_parse().preload_bits(512);
|
||||
}
|
||||
int hash = cs.slice_hash();
|
||||
if (a?) {
|
||||
throw_unless(err:wrong_a_signature(), check_signature(hash, a_sig, a_key));
|
||||
}
|
||||
if (b?) {
|
||||
throw_unless(err:wrong_b_signature(), check_signature(hash, b_sig, b_key));
|
||||
}
|
||||
return (cs, (a?, b?));
|
||||
}
|
||||
|
||||
;; process message, give state is stateInit
|
||||
;;
|
||||
;; stateInit signed_A?:Bool signed_B?:Bool min_A:Grams min_B:Grams expire_at:uint32 A:Grams B:Grams = State;
|
||||
_ unpack_state_init(slice state) {
|
||||
return (
|
||||
state~load_int(1),
|
||||
state~load_int(1),
|
||||
state~load_grams(),
|
||||
state~load_grams(),
|
||||
state~load_uint(32),
|
||||
state~load_grams(),
|
||||
state~load_grams());
|
||||
|
||||
}
|
||||
_ pack_state_init(int signed_A?, int signed_B?, int min_A, int min_B, int expire_at, int A, int B) {
|
||||
return begin_cell()
|
||||
.store_int(state:init(), 3)
|
||||
.store_int(signed_A?, 1)
|
||||
.store_int(signed_B?, 1)
|
||||
.store_grams(min_A)
|
||||
.store_grams(min_B)
|
||||
.store_uint(expire_at, 32)
|
||||
.store_grams(A)
|
||||
.store_grams(B).end_cell();
|
||||
}
|
||||
|
||||
;; stateClosing$10 signed_A?:bool signed_B?:Bool promise_A:Grams promise_B:Grams exipire_at:uint32 A:Grams B:Grams = State;
|
||||
_ unpack_state_close(slice state) {
|
||||
return (
|
||||
state~load_int(1),
|
||||
state~load_int(1),
|
||||
state~load_grams(),
|
||||
state~load_grams(),
|
||||
state~load_uint(32),
|
||||
state~load_grams(),
|
||||
state~load_grams());
|
||||
}
|
||||
|
||||
_ pack_state_close(int signed_A?, int signed_B?, int promise_A, int promise_B, int expire_at, int A, int B) {
|
||||
return begin_cell()
|
||||
.store_int(state:close(), 3)
|
||||
.store_int(signed_A?, 1)
|
||||
.store_int(signed_B?, 1)
|
||||
.store_grams(promise_A)
|
||||
.store_grams(promise_B)
|
||||
.store_uint(expire_at, 32)
|
||||
.store_grams(A)
|
||||
.store_grams(B).end_cell();
|
||||
}
|
||||
|
||||
_ send_payout(slice s_addr, int amount, int channel_id, int flags) impure {
|
||||
send_raw_message(begin_cell()
|
||||
.store_uint(0x10, 6)
|
||||
.store_slice(s_addr)
|
||||
.store_grams(amount)
|
||||
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
|
||||
.store_uint(msg:payout(), 32)
|
||||
.store_uint(channel_id, 64)
|
||||
.end_cell(), flags);
|
||||
}
|
||||
|
||||
|
||||
cell do_payout(int promise_A, int promise_B, int A, int B, slice a_addr, slice b_addr, int channel_id) impure {
|
||||
accept_message();
|
||||
|
||||
int diff = promise_B - promise_A;
|
||||
if (diff < - A) {
|
||||
diff = - A;
|
||||
}
|
||||
if (diff > B) {
|
||||
diff = B;
|
||||
}
|
||||
A += diff;
|
||||
B -= diff;
|
||||
|
||||
send_payout(a_addr, A, channel_id, 3);
|
||||
send_payout(b_addr, B, channel_id, 3);
|
||||
|
||||
return begin_cell()
|
||||
.store_int(state:payout(), 3)
|
||||
.store_grams(A)
|
||||
.store_grams(B)
|
||||
.end_cell();
|
||||
}
|
||||
|
||||
|
||||
;;
|
||||
;; init$000 inc_A:Grams inc_B:Grams min_A:Grams min_B:Grams = Message;
|
||||
;;
|
||||
cell with_init(slice state, int msg_value, slice msg, int msg_signed_A?, int msg_signed_B?,
|
||||
slice a_addr, slice b_addr, int init_timeout, int channel_id) {
|
||||
;; parse state
|
||||
(int signed_A?, int signed_B?, int min_A, int min_B, int expire_at, int A, int B) = unpack_state_init(state);
|
||||
|
||||
if (expire_at == 0) {
|
||||
expire_at = now() + init_timeout;
|
||||
}
|
||||
|
||||
int op = msg~load_uint(32);
|
||||
if (op == msg:timeout()) {
|
||||
throw_unless(err:no_timeout(), expire_at < now());
|
||||
return do_payout(0, 0, A, B, a_addr, b_addr, channel_id);
|
||||
}
|
||||
throw_unless(err:expected_init(), op == msg:init());
|
||||
|
||||
;; unpack init message
|
||||
(int inc_A, int inc_B, int upd_min_A, int upd_min_B, int got_channel_id) =
|
||||
(msg~load_grams(), msg~load_grams(), msg~load_grams(), msg~load_grams(), msg~load_uint(64));
|
||||
throw_unless(err:wrong_channel_id(), got_channel_id == channel_id);
|
||||
|
||||
;; TODO: we should reserve some part of the value for comission
|
||||
throw_if(err:msg_value_too_small(), msg_value < inc_A + inc_B);
|
||||
throw_unless(err:replay_protection(), (msg_signed_A? < signed_A?) | (msg_signed_B? < signed_B?));
|
||||
|
||||
A += inc_A;
|
||||
B += inc_B;
|
||||
|
||||
signed_A? |= msg_signed_A?;
|
||||
if (min_A < upd_min_A) {
|
||||
min_A = upd_min_A;
|
||||
}
|
||||
|
||||
signed_B? |= msg_signed_B?;
|
||||
if (min_B < upd_min_B) {
|
||||
min_B = upd_min_B;
|
||||
}
|
||||
|
||||
if (signed_A? & signed_B?) {
|
||||
if ((min_A > A) | (min_B > B)) {
|
||||
return do_payout(0, 0, A, B, a_addr, b_addr, channel_id);
|
||||
}
|
||||
|
||||
return pack_state_close(0, 0, 0, 0, 0, A, B);
|
||||
}
|
||||
|
||||
return pack_state_init(signed_A?, signed_B?, min_A, min_B, expire_at, A, B);
|
||||
}
|
||||
|
||||
;; close$001 extra_A:Grams extra_B:Grams sig:Maybe<int256> promise_A:Grams promise_B:Grams = Message;
|
||||
|
||||
cell with_close(slice cs, slice msg, int msg_signed_A?, int msg_signed_B?, int a_key, int b_key,
|
||||
slice a_addr, slice b_addr, int expire_timeout, int channel_id) {
|
||||
;; parse state
|
||||
(int signed_A?, int signed_B?, int promise_A, int promise_B, int expire_at, int A, int B) = unpack_state_close(cs);
|
||||
|
||||
if (expire_at == 0) {
|
||||
expire_at = now() + expire_timeout;
|
||||
}
|
||||
|
||||
int op = msg~load_uint(32);
|
||||
if (op == msg:timeout()) {
|
||||
throw_unless(err:no_timeout(), expire_at < now());
|
||||
return do_payout(promise_A, promise_B, A, B, a_addr, b_addr, channel_id);
|
||||
}
|
||||
throw_unless(err:expected_close(), op == msg:close());
|
||||
|
||||
;; also ensures that (msg_signed_A? | msg_signed_B?) is true
|
||||
throw_unless(err:replay_protection(), (msg_signed_A? < signed_A?) | (msg_signed_B? < signed_B?));
|
||||
signed_A? |= msg_signed_A?;
|
||||
signed_B? |= msg_signed_B?;
|
||||
|
||||
;; unpack close message
|
||||
(int extra_A, int extra_B) = (msg~load_grams(), msg~load_grams());
|
||||
int has_sig = msg~load_int(1);
|
||||
if (has_sig) {
|
||||
slice sig = msg~load_ref().begin_parse().preload_bits(512);
|
||||
int hash = msg.slice_hash();
|
||||
ifnot (msg_signed_A?) {
|
||||
throw_unless(err:wrong_a_signature(), check_signature(hash, sig, a_key));
|
||||
extra_A = 0;
|
||||
}
|
||||
ifnot (msg_signed_B?) {
|
||||
throw_unless(err:wrong_b_signature(), check_signature(hash, sig, b_key));
|
||||
extra_B = 0;
|
||||
}
|
||||
} else {
|
||||
throw_unless(err:no_promise_signature(), msg_signed_A? & msg_signed_B?);
|
||||
extra_A = 0;
|
||||
extra_B = 0;
|
||||
}
|
||||
(int got_channel_id, int update_promise_A, int update_promise_B) = (msg~load_uint(64), msg~load_grams(), msg~load_grams());
|
||||
throw_unless(err:wrong_channel_id(), got_channel_id == channel_id);
|
||||
|
||||
|
||||
accept_message();
|
||||
update_promise_A += extra_A;
|
||||
if (promise_A < update_promise_A) {
|
||||
promise_A = update_promise_A;
|
||||
}
|
||||
update_promise_B += extra_B;
|
||||
if (promise_B < update_promise_B) {
|
||||
promise_B = update_promise_B;
|
||||
}
|
||||
|
||||
if (signed_A? & signed_B?) {
|
||||
return do_payout(promise_A, promise_B, A, B, a_addr, b_addr, channel_id);
|
||||
}
|
||||
return pack_state_close(signed_A?, signed_B?, promise_A, promise_B, expire_at, A, B);
|
||||
}
|
||||
|
||||
() recv_any(int msg_value, slice msg) impure {
|
||||
(cell config, cell state) = unpack_data();
|
||||
(int init_timeout, int close_timeout, int a_key, int b_key, slice a_addr, slice b_addr, int channel_id) = config.unpack_config();
|
||||
(int msg_signed_A?, int msg_signed_B?) = msg~unwrap_signatures(a_key, b_key);
|
||||
|
||||
slice cs = state.begin_parse();
|
||||
int state_type = cs~load_uint(3);
|
||||
|
||||
if (state_type == state:init()) { ;; init
|
||||
state = with_init(cs, msg_value, msg, msg_signed_A?, msg_signed_B?, a_addr, b_addr, init_timeout, channel_id);
|
||||
} if (state_type == state:close()) {
|
||||
state = with_close(cs, msg, msg_signed_A?, msg_signed_B?, a_key, b_key, a_addr, b_addr, close_timeout, channel_id);
|
||||
}
|
||||
|
||||
pack_data(config, state);
|
||||
}
|
||||
|
||||
() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure {
|
||||
recv_any(msg_value, in_msg);
|
||||
}
|
||||
|
||||
() recv_external(slice in_msg) impure {
|
||||
recv_any(0, in_msg);
|
||||
}
|
@ -1,13 +1,16 @@
|
||||
;; Restricted wallet (a variant of wallet-code.fc)
|
||||
;; until configuration parameter -13 is set, accepts messages only to elector smc
|
||||
;; restricts access to parts of balance until certain dates
|
||||
|
||||
() recv_internal(slice in_msg) impure {
|
||||
;; do nothing for internal messages
|
||||
}
|
||||
|
||||
_ days_passed() inline {
|
||||
_ seconds_passed(int start_at, int utime) inline_ref {
|
||||
ifnot (start_at) {
|
||||
var p = config_param(-13);
|
||||
return null?(p) ? -1 : (now() - begin_parse(p).preload_uint(32)) / 86400;
|
||||
start_at = null?(p) ? 0 : begin_parse(p).preload_uint(32);
|
||||
}
|
||||
return start_at ? utime - start_at : -1;
|
||||
}
|
||||
|
||||
() recv_external(slice in_msg) impure {
|
||||
@ -16,7 +19,7 @@ _ days_passed() inline {
|
||||
var (msg_seqno, valid_until) = (cs~load_uint(32), cs~load_uint(32));
|
||||
throw_if(35, valid_until <= now());
|
||||
var ds = get_data().begin_parse();
|
||||
var (stored_seqno, public_key, rdict) = (ds~load_uint(32), ds~load_uint(256), ds~load_dict());
|
||||
var (stored_seqno, public_key, start_at, rdict) = (ds~load_uint(32), ds~load_uint(256), ds~load_uint(32), ds~load_dict());
|
||||
ds.end_parse();
|
||||
throw_unless(33, msg_seqno == stored_seqno);
|
||||
ifnot (msg_seqno) {
|
||||
@ -24,14 +27,15 @@ _ days_passed() inline {
|
||||
set_data(begin_cell()
|
||||
.store_uint(stored_seqno + 1, 32)
|
||||
.store_uint(public_key, 256)
|
||||
.store_uint(start_at, 32)
|
||||
.store_dict(rdict)
|
||||
.end_cell());
|
||||
return ();
|
||||
}
|
||||
throw_unless(34, check_signature(slice_hash(in_msg), signature, public_key));
|
||||
accept_message();
|
||||
var ts = days_passed();
|
||||
var (_, value, found) = rdict.idict_get_preveq?(16, ts);
|
||||
var ts = seconds_passed(start_at, now());
|
||||
var (_, value, found) = rdict.idict_get_preveq?(32, ts);
|
||||
if (found) {
|
||||
raw_reserve(value~load_grams(), 2);
|
||||
}
|
||||
@ -45,6 +49,7 @@ _ days_passed() inline {
|
||||
set_data(begin_cell()
|
||||
.store_uint(stored_seqno + 1, 32)
|
||||
.store_uint(public_key, 256)
|
||||
.store_uint(start_at, 32)
|
||||
.store_dict(rdict)
|
||||
.end_cell());
|
||||
}
|
||||
@ -61,15 +66,23 @@ int get_public_key() method_id {
|
||||
return cs.preload_uint(256);
|
||||
}
|
||||
|
||||
int balance() method_id {
|
||||
int compute_balance_at(int utime) inline_ref {
|
||||
var ds = get_data().begin_parse().skip_bits(32 + 256);
|
||||
var rdict = ds~load_dict();
|
||||
var (start_at, rdict) = (ds~load_uint(32), ds~load_dict());
|
||||
ds.end_parse();
|
||||
var ts = days_passed();
|
||||
var ts = seconds_passed(start_at, utime);
|
||||
var balance = get_balance().pair_first();
|
||||
var (_, value, found) = rdict.idict_get_preveq?(16, ts);
|
||||
var (_, value, found) = rdict.idict_get_preveq?(32, ts);
|
||||
if (found) {
|
||||
balance = max(balance - value~load_grams(), 0);
|
||||
}
|
||||
return balance;
|
||||
}
|
||||
|
||||
int balance_at(int utime) method_id {
|
||||
return compute_balance_at(utime);
|
||||
}
|
||||
|
||||
int balance() method_id {
|
||||
return compute_balance_at(now());
|
||||
}
|
||||
|
@ -0,0 +1,103 @@
|
||||
;; Restricted wallet initialized by a third party (a variant of restricted-wallet2-code.fc)
|
||||
;; restricts access to parts of balance until certain dates
|
||||
|
||||
() recv_internal(slice in_msg) impure {
|
||||
;; do nothing for internal messages
|
||||
}
|
||||
|
||||
_ seconds_passed(int start_at, int utime) inline_ref {
|
||||
ifnot (start_at) {
|
||||
var p = config_param(-13);
|
||||
start_at = null?(p) ? 0 : begin_parse(p).preload_uint(32);
|
||||
}
|
||||
return start_at ? utime - start_at : -1;
|
||||
}
|
||||
|
||||
() 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));
|
||||
throw_unless(33, msg_seqno == stored_seqno);
|
||||
throw_unless(34, subwallet_id == stored_subwallet);
|
||||
throw_unless(36, check_signature(slice_hash(in_msg), signature, public_key));
|
||||
ifnot (msg_seqno) {
|
||||
public_key = ds~load_uint(256); ;; load "final" public key
|
||||
ds.end_parse();
|
||||
cs~touch();
|
||||
var (start_at, rdict) = (cs~load_uint(32), cs~load_dict());
|
||||
cs.end_parse();
|
||||
accept_message();
|
||||
set_data(begin_cell()
|
||||
.store_uint(stored_seqno + 1, 32)
|
||||
.store_uint(stored_subwallet, 32)
|
||||
.store_uint(public_key, 256)
|
||||
.store_uint(start_at, 32)
|
||||
.store_dict(rdict)
|
||||
.end_cell());
|
||||
return ();
|
||||
}
|
||||
var (start_at, rdict) = (ds~load_uint(32), ds~load_dict());
|
||||
ds.end_parse();
|
||||
accept_message();
|
||||
var ts = seconds_passed(start_at, now());
|
||||
var (_, value, found) = rdict.idict_get_preveq?(32, ts);
|
||||
if (found) {
|
||||
raw_reserve(value~load_grams(), 2);
|
||||
}
|
||||
cs~touch();
|
||||
while (cs.slice_refs()) {
|
||||
var mode = cs~load_uint(8);
|
||||
var msg = cs~load_ref();
|
||||
send_raw_message(msg, mode);
|
||||
}
|
||||
cs.end_parse();
|
||||
set_data(begin_cell()
|
||||
.store_uint(stored_seqno + 1, 32)
|
||||
.store_uint(stored_subwallet, 32)
|
||||
.store_uint(public_key, 256)
|
||||
.store_uint(start_at, 32)
|
||||
.store_dict(rdict)
|
||||
.end_cell());
|
||||
}
|
||||
|
||||
;; Get methods
|
||||
|
||||
int seqno() method_id {
|
||||
return get_data().begin_parse().preload_uint(32);
|
||||
}
|
||||
|
||||
int wallet_id() method_id {
|
||||
var ds = get_data().begin_parse();
|
||||
ds~load_uint(32);
|
||||
return ds.preload_uint(32);
|
||||
}
|
||||
|
||||
int get_public_key() method_id {
|
||||
var ds = get_data().begin_parse();
|
||||
ds~load_uint(32 + 32);
|
||||
return ds.preload_uint(256);
|
||||
}
|
||||
|
||||
int compute_balance_at(int utime) inline_ref {
|
||||
var ds = get_data().begin_parse().skip_bits(32 + 32 + 256);
|
||||
var (start_at, rdict) = (ds~load_uint(32), ds~load_dict());
|
||||
ds.end_parse();
|
||||
var ts = seconds_passed(start_at, utime);
|
||||
var balance = get_balance().pair_first();
|
||||
var (_, value, found) = rdict.idict_get_preveq?(32, ts);
|
||||
if (found) {
|
||||
balance = max(balance - value~load_grams(), 0);
|
||||
}
|
||||
return balance;
|
||||
}
|
||||
|
||||
int balance_at(int utime) method_id {
|
||||
return compute_balance_at(utime);
|
||||
}
|
||||
|
||||
int balance() method_id {
|
||||
return compute_balance_at(now());
|
||||
}
|
@ -18,5 +18,7 @@ dup Blen { 32 B>i@ } { drop Basechain } cond constant wallet_wc
|
||||
|
||||
file-base +".pk" dup file-exists? {
|
||||
dup file>B dup Blen 32 <> abort"Private key must be exactly 32 bytes long"
|
||||
=: wallet_pk ."Private key available in file " type cr
|
||||
tuck =: wallet_pk ."Private key available in file " type cr
|
||||
priv>pub 256 B>u@
|
||||
dup ."Corresponding public key is " .pubkey ." = " 64X. cr
|
||||
} { ."Private key file " type ." not found" cr } cond
|
||||
|
@ -0,0 +1,45 @@
|
||||
// automatically generated from `smartcont/stdlib.fc` `smartcont/simple-wallet-code.fc`
|
||||
PROGRAM{
|
||||
DECLPROC recv_internal
|
||||
DECLPROC recv_external
|
||||
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 msg_seqno cs
|
||||
c4 PUSH // signature in_msg msg_seqno cs _11
|
||||
CTOS // signature in_msg msg_seqno cs cs2
|
||||
32 LDU // signature in_msg msg_seqno cs stored_seqno cs2
|
||||
256 LDU // signature in_msg msg_seqno cs stored_seqno public_key cs2
|
||||
ENDS
|
||||
s3 s1 XCPU // signature in_msg public_key cs stored_seqno msg_seqno stored_seqno
|
||||
EQUAL // signature in_msg public_key cs stored_seqno _23
|
||||
33 THROWIFNOT
|
||||
s0 s3 XCHG // signature stored_seqno public_key cs in_msg
|
||||
HASHSU // signature stored_seqno public_key cs _26
|
||||
s0 s4 s2 XC2PU // cs stored_seqno public_key _26 signature public_key
|
||||
CHKSIGNU // cs stored_seqno public_key _27
|
||||
34 THROWIFNOT
|
||||
ACCEPT
|
||||
s2 s0 XCPU // public_key stored_seqno cs cs
|
||||
SREFS // public_key stored_seqno cs _32
|
||||
IF:<{ // public_key stored_seqno cs
|
||||
8 LDU // public_key stored_seqno mode cs
|
||||
LDREF // public_key stored_seqno mode _37 cs
|
||||
s0 s2 XCHG // public_key stored_seqno cs _37 mode
|
||||
SENDRAWMSG
|
||||
}> // public_key stored_seqno cs
|
||||
ENDS
|
||||
INC // public_key _42
|
||||
NEWC // public_key _42 _43
|
||||
32 STU // public_key _45
|
||||
256 STU // _47
|
||||
ENDC // _48
|
||||
c4 POP
|
||||
}>
|
||||
}END>c
|
59
submodules/ton/tonlib-src/crypto/smartcont/wallet-code.fif
Normal file
59
submodules/ton/tonlib-src/crypto/smartcont/wallet-code.fif
Normal file
@ -0,0 +1,59 @@
|
||||
// automatically generated from `smartcont/stdlib.fc` `smartcont/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 _8 cs
|
||||
32 LDU // signature in_msg msg_seqno valid_until cs
|
||||
NOW // signature in_msg msg_seqno valid_until cs _15
|
||||
s1 s2 XCHG // signature in_msg msg_seqno cs valid_until _15
|
||||
LEQ // signature in_msg msg_seqno cs _16
|
||||
35 THROWIF
|
||||
c4 PUSH // signature in_msg msg_seqno cs _19
|
||||
CTOS // signature in_msg msg_seqno cs ds
|
||||
32 LDU // signature in_msg msg_seqno cs _23 ds
|
||||
256 LDU // signature in_msg msg_seqno cs stored_seqno public_key ds
|
||||
ENDS
|
||||
s3 s1 XCPU // signature in_msg public_key cs stored_seqno msg_seqno stored_seqno
|
||||
EQUAL // signature in_msg public_key cs stored_seqno _31
|
||||
33 THROWIFNOT
|
||||
s0 s3 XCHG // signature stored_seqno public_key cs in_msg
|
||||
HASHSU // signature stored_seqno public_key cs _34
|
||||
s0 s4 s2 XC2PU // cs stored_seqno public_key _34 signature public_key
|
||||
CHKSIGNU // cs stored_seqno public_key _35
|
||||
34 THROWIFNOT
|
||||
ACCEPT
|
||||
s0 s2 XCHG // public_key stored_seqno cs
|
||||
WHILE:<{
|
||||
DUP // public_key stored_seqno cs cs
|
||||
SREFS // public_key stored_seqno cs _40
|
||||
}>DO<{ // public_key stored_seqno cs
|
||||
8 LDU // public_key stored_seqno mode cs
|
||||
LDREF // public_key stored_seqno mode _45 cs
|
||||
s0 s2 XCHG // public_key stored_seqno cs _45 mode
|
||||
SENDRAWMSG
|
||||
}> // public_key stored_seqno cs
|
||||
ENDS
|
||||
INC // public_key _50
|
||||
NEWC // public_key _50 _51
|
||||
32 STU // public_key _53
|
||||
256 STU // _55
|
||||
ENDC // _56
|
||||
c4 POP
|
||||
}>
|
||||
seqno PROC:<{
|
||||
//
|
||||
c4 PUSH // _0
|
||||
CTOS // _1
|
||||
32 PLDU // _3
|
||||
}>
|
||||
}END>c
|
@ -21,6 +21,31 @@
|
||||
#include "block/block-auto.h"
|
||||
#include "block/block-parse.h"
|
||||
namespace ton {
|
||||
|
||||
namespace smc {
|
||||
td::Ref<vm::CellSlice> pack_grams(td::uint64 amount) {
|
||||
vm::CellBuilder cb;
|
||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(amount));
|
||||
return vm::load_cell_slice_ref(cb.finalize());
|
||||
}
|
||||
|
||||
bool unpack_grams(td::Ref<vm::CellSlice> cs, td::uint64& amount) {
|
||||
td::RefInt256 got;
|
||||
if (!block::tlb::t_Grams.as_integer_to(cs, got)) {
|
||||
return false;
|
||||
}
|
||||
if (!got->unsigned_fits_bits(63)) {
|
||||
return false;
|
||||
}
|
||||
auto x = got->to_long();
|
||||
if (x < 0) {
|
||||
return false;
|
||||
}
|
||||
amount = x;
|
||||
return true;
|
||||
}
|
||||
} // namespace smc
|
||||
|
||||
td::Ref<vm::Cell> GenericAccount::get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data) noexcept {
|
||||
return vm::CellBuilder()
|
||||
.store_zeroes(2)
|
||||
@ -47,7 +72,7 @@ void GenericAccount::store_int_message(vm::CellBuilder& cb, const block::StdAddr
|
||||
.store_long(dest_address.workchain, 8)
|
||||
.store_int256(dest_addr, 256);
|
||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
|
||||
cb.store_zeroes(9 + 64 + 32 + 1 + 1);
|
||||
cb.store_zeroes(9 + 64 + 32);
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> GenericAccount::create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
||||
|
@ -23,6 +23,10 @@
|
||||
#include "SmartContract.h"
|
||||
|
||||
namespace ton {
|
||||
namespace smc {
|
||||
td::Ref<vm::CellSlice> pack_grams(td::uint64 amount);
|
||||
bool unpack_grams(td::Ref<vm::CellSlice> cs, td::uint64& amount);
|
||||
} // namespace smc
|
||||
class GenericAccount {
|
||||
public:
|
||||
static td::Ref<vm::Cell> get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data) noexcept;
|
||||
|
@ -73,17 +73,11 @@ td::Ref<vm::Cell> HighloadWallet::make_a_gift_message(const td::Ed25519::Private
|
||||
for (size_t i = 0; i < gifts.size(); i++) {
|
||||
auto& gift = gifts[i];
|
||||
td::int32 send_mode = 3;
|
||||
auto gramms = gift.gramms;
|
||||
if (gramms == -1) {
|
||||
gramms = 0;
|
||||
if (gift.gramms == -1) {
|
||||
send_mode += 128;
|
||||
}
|
||||
auto message_inner = create_int_message(gift);
|
||||
vm::CellBuilder cb;
|
||||
GenericAccount::store_int_message(cb, gift.destination, gramms);
|
||||
cb.store_bytes("\0\0\0\0", 4);
|
||||
vm::CellString::store(cb, gift.message, 35 * 8).ensure();
|
||||
auto message_inner = cb.finalize();
|
||||
cb = {};
|
||||
cb.store_long(send_mode, 8).store_ref(message_inner);
|
||||
auto key = messages.integer_key(td::make_refint(i), 16, false);
|
||||
messages.set_builder(key.bits(), 16, cb);
|
||||
|
@ -73,18 +73,11 @@ td::Ref<vm::Cell> HighloadWalletV2::make_a_gift_message(const td::Ed25519::Priva
|
||||
for (size_t i = 0; i < gifts.size(); i++) {
|
||||
auto& gift = gifts[i];
|
||||
td::int32 send_mode = 3;
|
||||
auto gramms = gift.gramms;
|
||||
if (gramms == -1) {
|
||||
gramms = 0;
|
||||
if (gift.gramms == -1) {
|
||||
send_mode += 128;
|
||||
}
|
||||
vm::CellBuilder cb;
|
||||
GenericAccount::store_int_message(cb, gift.destination, gramms);
|
||||
cb.store_bytes("\0\0\0\0", 4);
|
||||
vm::CellString::store(cb, gift.message, 35 * 8).ensure();
|
||||
auto message_inner = cb.finalize();
|
||||
cb = {};
|
||||
cb.store_long(send_mode, 8).store_ref(message_inner);
|
||||
cb.store_long(send_mode, 8).store_ref(create_int_message(gift));
|
||||
auto key = messages.integer_key(td::make_refint(i), 16, false);
|
||||
messages.set_builder(key.bits(), 16, cb);
|
||||
}
|
||||
|
264
submodules/ton/tonlib-src/crypto/smc-envelope/PaymentChannel.cpp
Normal file
264
submodules/ton/tonlib-src/crypto/smc-envelope/PaymentChannel.cpp
Normal file
@ -0,0 +1,264 @@
|
||||
#include "PaymentChannel.h"
|
||||
#include "GenericAccount.h"
|
||||
#include "vm/cells.h"
|
||||
#include "vm/cellslice.h"
|
||||
#include "Ed25519.h"
|
||||
#include "block/block-auto.h"
|
||||
#include "block/block-parse.h"
|
||||
|
||||
#include "SmartContract.h"
|
||||
#include "SmartContractCode.h"
|
||||
|
||||
namespace ton {
|
||||
using smc::pack_grams;
|
||||
using smc::unpack_grams;
|
||||
namespace pchan {
|
||||
|
||||
td::Ref<vm::Cell> Config::serialize() const {
|
||||
block::gen::ChanConfig::Record rec;
|
||||
|
||||
vm::CellBuilder a_addr_cb;
|
||||
block::tlb::t_MsgAddressInt.store_std_address(a_addr_cb, a_addr);
|
||||
rec.a_addr = a_addr_cb.finalize_novm();
|
||||
|
||||
vm::CellBuilder b_addr_cb;
|
||||
block::tlb::t_MsgAddressInt.store_std_address(b_addr_cb, b_addr);
|
||||
rec.b_addr = b_addr_cb.finalize_novm();
|
||||
|
||||
rec.a_key.as_slice().copy_from(a_key);
|
||||
rec.b_key.as_slice().copy_from(b_key);
|
||||
rec.init_timeout = init_timeout;
|
||||
rec.close_timeout = close_timeout;
|
||||
rec.channel_id = channel_id;
|
||||
|
||||
td::Ref<vm::Cell> res;
|
||||
CHECK(tlb::pack_cell(res, rec));
|
||||
return res;
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> MsgInit::serialize() const {
|
||||
block::gen::ChanMsg::Record_chan_msg_init rec;
|
||||
rec.min_A = pack_grams(min_A);
|
||||
rec.min_B = pack_grams(min_B);
|
||||
rec.inc_A = pack_grams(inc_A);
|
||||
rec.inc_B = pack_grams(inc_B);
|
||||
rec.channel_id = channel_id;
|
||||
|
||||
td::Ref<vm::Cell> res;
|
||||
CHECK(tlb::pack_cell(res, rec));
|
||||
return res;
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Promise::serialize() const {
|
||||
block::gen::ChanPromise::Record rec;
|
||||
rec.channel_id = channel_id;
|
||||
rec.promise_A = pack_grams(promise_A);
|
||||
rec.promise_B = pack_grams(promise_B);
|
||||
td::Ref<vm::Cell> res;
|
||||
CHECK(tlb::pack_cell(res, rec));
|
||||
return res;
|
||||
}
|
||||
|
||||
td::SecureString sign(const td::Ref<vm::Cell>& msg, const td::Ed25519::PrivateKey* key) {
|
||||
return key->sign(msg->get_hash().as_slice()).move_as_ok();
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> maybe_sign(const td::Ref<vm::Cell>& msg, const td::Ed25519::PrivateKey* key) {
|
||||
if (!key) {
|
||||
return {};
|
||||
}
|
||||
return vm::CellBuilder().store_bytes(sign(msg, key).as_slice()).finalize();
|
||||
}
|
||||
|
||||
td::Ref<vm::CellSlice> maybe_ref(td::Ref<vm::Cell> msg) {
|
||||
vm::CellBuilder cb;
|
||||
CHECK(cb.store_maybe_ref(msg));
|
||||
return vm::load_cell_slice_ref(cb.finalize());
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> MsgClose::serialize() const {
|
||||
block::gen::ChanMsg::Record_chan_msg_close rec;
|
||||
rec.extra_A = pack_grams(extra_A);
|
||||
rec.extra_B = pack_grams(extra_B);
|
||||
rec.promise = signed_promise;
|
||||
|
||||
td::Ref<vm::Cell> res;
|
||||
CHECK(tlb::pack_cell(res, rec));
|
||||
return res;
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> MsgTimeout::serialize() const {
|
||||
block::gen::ChanMsg::Record_chan_msg_timeout rec;
|
||||
td::Ref<vm::Cell> res;
|
||||
CHECK(tlb::pack_cell(res, rec));
|
||||
return res;
|
||||
}
|
||||
|
||||
td::SecureString SignedPromise::signature(const td::Ed25519::PrivateKey* key, const td::Ref<vm::Cell>& promise) {
|
||||
return sign(promise, key);
|
||||
}
|
||||
td::Ref<vm::Cell> SignedPromise::create_and_serialize(td::Slice signature, const td::Ref<vm::Cell>& promise) {
|
||||
block::gen::ChanSignedPromise::Record rec;
|
||||
rec.promise = vm::load_cell_slice_ref(promise);
|
||||
LOG(ERROR) << "signature.size() = " << signature.size();
|
||||
rec.sig = maybe_ref(vm::CellBuilder().store_bytes(signature).finalize());
|
||||
td::Ref<vm::Cell> res;
|
||||
CHECK(tlb::pack_cell(res, rec));
|
||||
return res;
|
||||
}
|
||||
td::Ref<vm::Cell> SignedPromise::create_and_serialize(const td::Ed25519::PrivateKey* key,
|
||||
const td::Ref<vm::Cell>& promise) {
|
||||
block::gen::ChanSignedPromise::Record rec;
|
||||
rec.promise = vm::load_cell_slice_ref(promise);
|
||||
rec.sig = maybe_ref(maybe_sign(promise, key));
|
||||
td::Ref<vm::Cell> res;
|
||||
CHECK(tlb::pack_cell(res, rec));
|
||||
return res;
|
||||
}
|
||||
|
||||
bool SignedPromise::unpack(td::Ref<vm::Cell> cell) {
|
||||
block::gen::ChanSignedPromise::Record rec;
|
||||
if (!tlb::unpack_cell(cell, rec)) {
|
||||
return false;
|
||||
}
|
||||
block::gen::ChanPromise::Record rec_promise;
|
||||
if (!tlb::csr_unpack(rec.promise, rec_promise)) {
|
||||
return false;
|
||||
}
|
||||
promise.channel_id = rec_promise.channel_id;
|
||||
if (!unpack_grams(rec_promise.promise_A, promise.promise_A)) {
|
||||
return false;
|
||||
}
|
||||
if (!unpack_grams(rec_promise.promise_B, promise.promise_B)) {
|
||||
return false;
|
||||
}
|
||||
td::Ref<vm::Cell> sig_cell;
|
||||
if (!rec.sig->prefetch_maybe_ref(sig_cell)) {
|
||||
return false;
|
||||
}
|
||||
td::SecureString signature(64);
|
||||
vm::CellSlice cs = vm::load_cell_slice(sig_cell);
|
||||
if (!cs.prefetch_bytes(signature.as_mutable_slice())) {
|
||||
return false;
|
||||
}
|
||||
o_signature = std::move(signature);
|
||||
return true;
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> StateInit::serialize() const {
|
||||
block::gen::ChanState::Record_chan_state_init rec;
|
||||
rec.expire_at = expire_at;
|
||||
rec.min_A = pack_grams(min_A);
|
||||
rec.min_B = pack_grams(min_B);
|
||||
rec.A = pack_grams(A);
|
||||
rec.B = pack_grams(B);
|
||||
rec.signed_A = signed_A;
|
||||
rec.signed_B = signed_B;
|
||||
td::Ref<vm::Cell> res;
|
||||
CHECK(tlb::pack_cell(res, rec));
|
||||
return res;
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Data::serialize() const {
|
||||
block::gen::ChanData::Record rec;
|
||||
rec.config = config;
|
||||
rec.state = state;
|
||||
td::Ref<vm::Cell> res;
|
||||
CHECK(block::gen::t_ChanData.cell_pack(res, rec));
|
||||
return res;
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> Data::init_state() {
|
||||
return StateInit().serialize();
|
||||
}
|
||||
} // namespace pchan
|
||||
|
||||
td::Result<PaymentChannel::Info> PaymentChannel::get_info() const {
|
||||
block::gen::ChanData::Record data_rec;
|
||||
if (!tlb::unpack_cell(get_state().data, data_rec)) {
|
||||
return td::Status::Error("Can't unpack data");
|
||||
}
|
||||
block::gen::ChanConfig::Record config_rec;
|
||||
if (!tlb::unpack_cell(data_rec.config, config_rec)) {
|
||||
return td::Status::Error("Can't unpack config");
|
||||
}
|
||||
pchan::Config config;
|
||||
config.a_key = td::SecureString(config_rec.a_key.as_slice());
|
||||
config.b_key = td::SecureString(config_rec.b_key.as_slice());
|
||||
block::tlb::t_MsgAddressInt.extract_std_address(vm::load_cell_slice_ref(config_rec.a_addr), config.a_addr);
|
||||
block::tlb::t_MsgAddressInt.extract_std_address(vm::load_cell_slice_ref(config_rec.b_addr), config.b_addr);
|
||||
config.init_timeout = static_cast<td::int32>(config_rec.init_timeout);
|
||||
config.close_timeout = static_cast<td::int32>(config_rec.close_timeout);
|
||||
config.channel_id = static_cast<td::int64>(config_rec.channel_id);
|
||||
|
||||
auto state_cs = vm::load_cell_slice(data_rec.state);
|
||||
Info res;
|
||||
switch (block::gen::t_ChanState.check_tag(state_cs)) {
|
||||
case block::gen::ChanState::chan_state_init: {
|
||||
pchan::StateInit state;
|
||||
block::gen::ChanState::Record_chan_state_init state_rec;
|
||||
if (!tlb::unpack_cell(data_rec.state, state_rec)) {
|
||||
return td::Status::Error("Can't unpack state");
|
||||
}
|
||||
bool ok = unpack_grams(state_rec.A, state.A) && unpack_grams(state_rec.B, state.B) &&
|
||||
unpack_grams(state_rec.min_A, state.min_A) && unpack_grams(state_rec.min_B, state.min_B);
|
||||
state.expire_at = state_rec.expire_at;
|
||||
state.signed_A = state_rec.signed_A;
|
||||
state.signed_B = state_rec.signed_B;
|
||||
if (!ok) {
|
||||
return td::Status::Error("Can't unpack state");
|
||||
}
|
||||
res.state = std::move(state);
|
||||
break;
|
||||
}
|
||||
case block::gen::ChanState::chan_state_close: {
|
||||
pchan::StateClose state;
|
||||
block::gen::ChanState::Record_chan_state_close state_rec;
|
||||
if (!tlb::unpack_cell(data_rec.state, state_rec)) {
|
||||
return td::Status::Error("Can't unpack state");
|
||||
}
|
||||
bool ok = unpack_grams(state_rec.A, state.A) && unpack_grams(state_rec.B, state.B) &&
|
||||
unpack_grams(state_rec.promise_A, state.promise_A) &&
|
||||
unpack_grams(state_rec.promise_B, state.promise_B);
|
||||
state.expire_at = state_rec.expire_at;
|
||||
state.signed_A = state_rec.signed_A;
|
||||
state.signed_B = state_rec.signed_B;
|
||||
if (!ok) {
|
||||
return td::Status::Error("Can't unpack state");
|
||||
}
|
||||
res.state = std::move(state);
|
||||
break;
|
||||
}
|
||||
case block::gen::ChanState::chan_state_payout: {
|
||||
pchan::StatePayout state;
|
||||
block::gen::ChanState::Record_chan_state_payout state_rec;
|
||||
if (!tlb::unpack_cell(data_rec.state, state_rec)) {
|
||||
return td::Status::Error("Can't unpack state");
|
||||
}
|
||||
bool ok = unpack_grams(state_rec.A, state.A) && unpack_grams(state_rec.B, state.B);
|
||||
if (!ok) {
|
||||
return td::Status::Error("Can't unpack state");
|
||||
}
|
||||
res.state = std::move(state);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return td::Status::Error("Can't unpack state");
|
||||
}
|
||||
|
||||
res.config = std::move(config);
|
||||
res.description = block::gen::t_ChanState.as_string_ref(data_rec.state);
|
||||
|
||||
return std::move(res);
|
||||
} // namespace ton
|
||||
|
||||
td::optional<td::int32> PaymentChannel::guess_revision(const vm::Cell::Hash& code_hash) {
|
||||
for (auto i : ton::SmartContractCode::get_revisions(ton::SmartContractCode::PaymentChannel)) {
|
||||
auto code = SmartContractCode::get_code(SmartContractCode::PaymentChannel, i);
|
||||
if (code->get_hash() == code_hash) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
} // namespace ton
|
251
submodules/ton/tonlib-src/crypto/smc-envelope/PaymentChannel.h
Normal file
251
submodules/ton/tonlib-src/crypto/smc-envelope/PaymentChannel.h
Normal file
@ -0,0 +1,251 @@
|
||||
#pragma once
|
||||
#include "vm/cells.h"
|
||||
#include "vm/cellslice.h"
|
||||
#include "Ed25519.h"
|
||||
#include "block/block-auto.h"
|
||||
#include "block/block-parse.h"
|
||||
|
||||
#include "td/utils/Variant.h"
|
||||
|
||||
#include "SmartContract.h"
|
||||
#include "SmartContractCode.h"
|
||||
|
||||
namespace ton {
|
||||
namespace pchan {
|
||||
|
||||
//
|
||||
// Payment channels
|
||||
//
|
||||
struct Config {
|
||||
td::uint32 init_timeout{0};
|
||||
td::uint32 close_timeout{0};
|
||||
td::SecureString a_key;
|
||||
td::SecureString b_key;
|
||||
block::StdAddress a_addr;
|
||||
block::StdAddress b_addr;
|
||||
td::uint64 channel_id{0};
|
||||
|
||||
td::Ref<vm::Cell> serialize() const;
|
||||
};
|
||||
|
||||
struct MsgInit {
|
||||
td::uint64 inc_A{0};
|
||||
td::uint64 inc_B{0};
|
||||
td::uint64 min_A{0};
|
||||
td::uint64 min_B{0};
|
||||
td::uint64 channel_id{0};
|
||||
|
||||
td::Ref<vm::Cell> serialize() const;
|
||||
};
|
||||
|
||||
struct Promise {
|
||||
td::uint64 channel_id;
|
||||
td::uint64 promise_A{0};
|
||||
td::uint64 promise_B{0};
|
||||
td::Ref<vm::Cell> serialize() const;
|
||||
};
|
||||
|
||||
td::Ref<vm::Cell> maybe_sign(const td::Ref<vm::Cell>& msg, const td::Ed25519::PrivateKey* key);
|
||||
td::Ref<vm::CellSlice> maybe_ref(td::Ref<vm::Cell> msg);
|
||||
|
||||
struct MsgClose {
|
||||
td::uint64 extra_A{0};
|
||||
td::uint64 extra_B{0};
|
||||
td::Ref<vm::CellSlice> signed_promise;
|
||||
td::Ref<vm::Cell> serialize() const;
|
||||
};
|
||||
|
||||
struct MsgTimeout {
|
||||
td::Ref<vm::Cell> serialize() const;
|
||||
};
|
||||
|
||||
struct SignedPromise {
|
||||
Promise promise;
|
||||
td::optional<td::SecureString> o_signature;
|
||||
|
||||
bool unpack(td::Ref<vm::Cell> cell);
|
||||
static td::SecureString signature(const td::Ed25519::PrivateKey* key, const td::Ref<vm::Cell>& promise);
|
||||
static td::Ref<vm::Cell> create_and_serialize(td::Slice signature, const td::Ref<vm::Cell>& promise);
|
||||
static td::Ref<vm::Cell> create_and_serialize(const td::Ed25519::PrivateKey* key, const td::Ref<vm::Cell>& promise);
|
||||
};
|
||||
|
||||
struct StateInit {
|
||||
bool signed_A{false};
|
||||
bool signed_B{false};
|
||||
td::uint64 min_A{0};
|
||||
td::uint64 min_B{0};
|
||||
td::uint64 A{0};
|
||||
td::uint64 B{0};
|
||||
td::uint32 expire_at{0};
|
||||
|
||||
td::Ref<vm::Cell> serialize() const;
|
||||
};
|
||||
|
||||
struct StateClose {
|
||||
bool signed_A{false};
|
||||
bool signed_B{false};
|
||||
td::uint64 promise_A{0};
|
||||
td::uint64 promise_B{0};
|
||||
td::uint64 A{0};
|
||||
td::uint64 B{0};
|
||||
td::uint32 expire_at{0};
|
||||
};
|
||||
|
||||
struct StatePayout {
|
||||
td::uint64 A{0};
|
||||
td::uint64 B{0};
|
||||
};
|
||||
|
||||
struct Data {
|
||||
td::Ref<vm::Cell> config;
|
||||
td::Ref<vm::Cell> state;
|
||||
|
||||
static td::Ref<vm::Cell> init_state();
|
||||
|
||||
td::Ref<vm::Cell> serialize() const;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct MsgBuilder {
|
||||
td::Ed25519::PrivateKey* a_key{nullptr};
|
||||
td::Ed25519::PrivateKey* b_key{nullptr};
|
||||
|
||||
T&& with_a_key(td::Ed25519::PrivateKey* key) && {
|
||||
a_key = key;
|
||||
return static_cast<T&&>(*this);
|
||||
}
|
||||
T&& with_b_key(td::Ed25519::PrivateKey* key) && {
|
||||
b_key = key;
|
||||
return static_cast<T&&>(*this);
|
||||
}
|
||||
|
||||
td::Ref<vm::Cell> finalize() && {
|
||||
block::gen::ChanSignedMsg::Record rec;
|
||||
auto msg = static_cast<T&&>(*this).msg.serialize();
|
||||
rec.msg = vm::load_cell_slice_ref(msg);
|
||||
rec.sig_A = maybe_ref(maybe_sign(msg, a_key));
|
||||
rec.sig_B = maybe_ref(maybe_sign(msg, b_key));
|
||||
td::Ref<vm::Cell> res;
|
||||
CHECK(tlb::pack_cell(res, rec));
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
struct MsgInitBuilder : public MsgBuilder<MsgInitBuilder> {
|
||||
MsgInit msg;
|
||||
|
||||
MsgInitBuilder&& min_A(td::uint64 value) && {
|
||||
msg.min_A = value;
|
||||
return std::move(*this);
|
||||
}
|
||||
MsgInitBuilder&& min_B(td::uint64 value) && {
|
||||
msg.min_B = value;
|
||||
return std::move(*this);
|
||||
}
|
||||
MsgInitBuilder&& inc_A(td::uint64 value) && {
|
||||
msg.inc_A = value;
|
||||
return std::move(*this);
|
||||
}
|
||||
MsgInitBuilder&& inc_B(td::uint64 value) && {
|
||||
msg.inc_B = value;
|
||||
return std::move(*this);
|
||||
}
|
||||
MsgInitBuilder&& channel_id(td::uint64 value) && {
|
||||
msg.channel_id = value;
|
||||
return std::move(*this);
|
||||
}
|
||||
};
|
||||
|
||||
struct MsgTimeoutBuilder : public MsgBuilder<MsgTimeoutBuilder> {
|
||||
MsgTimeout msg;
|
||||
};
|
||||
|
||||
struct MsgCloseBuilder : public MsgBuilder<MsgCloseBuilder> {
|
||||
MsgClose msg;
|
||||
|
||||
MsgCloseBuilder&& extra_A(td::uint64 value) && {
|
||||
msg.extra_A = value;
|
||||
return std::move(*this);
|
||||
}
|
||||
MsgCloseBuilder&& extra_B(td::uint64 value) && {
|
||||
msg.extra_B = value;
|
||||
return std::move(*this);
|
||||
}
|
||||
MsgCloseBuilder&& signed_promise(td::Ref<vm::Cell> signed_promise) && {
|
||||
msg.signed_promise = vm::load_cell_slice_ref(signed_promise);
|
||||
return std::move(*this);
|
||||
}
|
||||
};
|
||||
|
||||
struct SignedPromiseBuilder {
|
||||
Promise promise;
|
||||
td::optional<td::SecureString> o_signature;
|
||||
td::Ed25519::PrivateKey* key{nullptr};
|
||||
|
||||
SignedPromiseBuilder& with_key(td::Ed25519::PrivateKey* key) {
|
||||
this->key = key;
|
||||
return *this;
|
||||
}
|
||||
SignedPromiseBuilder& promise_A(td::uint64 value) {
|
||||
promise.promise_A = value;
|
||||
return *this;
|
||||
}
|
||||
SignedPromiseBuilder& promise_B(td::uint64 value) {
|
||||
promise.promise_B = value;
|
||||
return *this;
|
||||
}
|
||||
SignedPromiseBuilder& channel_id(td::uint64 value) {
|
||||
promise.channel_id = value;
|
||||
return *this;
|
||||
}
|
||||
SignedPromiseBuilder& signature(td::SecureString signature) {
|
||||
o_signature = std::move(signature);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool check_signature(td::Slice signature, const td::Ed25519::PublicKey& pk) {
|
||||
return pk.verify_signature(promise.serialize()->get_hash().as_slice(), signature).is_ok();
|
||||
}
|
||||
td::SecureString calc_signature() {
|
||||
CHECK(key);
|
||||
return SignedPromise::signature(key, promise.serialize());
|
||||
}
|
||||
td::Ref<vm::Cell> finalize() {
|
||||
if (o_signature) {
|
||||
return SignedPromise::create_and_serialize(o_signature.value().copy(), promise.serialize());
|
||||
} else {
|
||||
return SignedPromise::create_and_serialize(key, promise.serialize());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pchan
|
||||
|
||||
class PaymentChannel : public SmartContract {
|
||||
public:
|
||||
PaymentChannel(State state) : SmartContract(std::move(state)) {
|
||||
}
|
||||
|
||||
struct Info {
|
||||
pchan::Config config;
|
||||
td::Variant<pchan::StateInit, pchan::StateClose, pchan::StatePayout> state;
|
||||
std::string description;
|
||||
};
|
||||
td::Result<Info> get_info() const;
|
||||
|
||||
static td::Ref<PaymentChannel> create(State state) {
|
||||
return td::Ref<PaymentChannel>(true, std::move(state));
|
||||
}
|
||||
static td::optional<td::int32> guess_revision(const vm::Cell::Hash& code_hash);
|
||||
static td::Ref<PaymentChannel> create(const pchan::Config& config, td::int32 revision) {
|
||||
State state;
|
||||
state.code = SmartContractCode::get_code(SmartContractCode::PaymentChannel, revision);
|
||||
pchan::Data data;
|
||||
data.config = config.serialize();
|
||||
pchan::StateInit init;
|
||||
data.state = init.serialize();
|
||||
state.data = data.serialize();
|
||||
return create(std::move(state));
|
||||
}
|
||||
};
|
||||
} // namespace ton
|
@ -32,19 +32,19 @@
|
||||
namespace ton {
|
||||
namespace {
|
||||
|
||||
td::Ref<vm::Stack> prepare_vm_stack(td::Ref<vm::CellSlice> body) {
|
||||
td::Ref<vm::Stack> prepare_vm_stack(td::RefInt256 amount, td::Ref<vm::CellSlice> body) {
|
||||
td::Ref<vm::Stack> stack_ref{true};
|
||||
td::RefInt256 acc_addr{true};
|
||||
//CHECK(acc_addr.write().import_bits(account.addr.cbits(), 256));
|
||||
vm::Stack& stack = stack_ref.write();
|
||||
stack.push_int(td::make_refint(10000000000));
|
||||
stack.push_int(td::make_refint(10000000000));
|
||||
stack.push_int(std::move(amount));
|
||||
stack.push_cell(vm::CellBuilder().finalize());
|
||||
stack.push_cellslice(std::move(body));
|
||||
return stack_ref;
|
||||
}
|
||||
|
||||
td::Ref<vm::Tuple> prepare_vm_c7(td::uint32 now) {
|
||||
td::Ref<vm::Tuple> prepare_vm_c7(td::uint32 now, td::uint64 balance) {
|
||||
// TODO: fix initialization of c7
|
||||
td::BitArray<256> rand_seed;
|
||||
rand_seed.as_slice().fill(0);
|
||||
@ -58,7 +58,7 @@ td::Ref<vm::Tuple> prepare_vm_c7(td::uint32 now) {
|
||||
td::make_refint(0), // block_lt:Integer
|
||||
td::make_refint(0), // trans_lt:Integer
|
||||
std::move(rand_seed_int), // rand_seed:Integer
|
||||
block::CurrencyCollection(1000000000).as_vm_tuple(), // balance_remaining:[Integer (Maybe Cell)]
|
||||
block::CurrencyCollection(balance).as_vm_tuple(), // balance_remaining:[Integer (Maybe Cell)]
|
||||
vm::load_cell_slice_ref(vm::CellBuilder().finalize()) // myself:MsgAddressInt
|
||||
//vm::StackEntry::maybe(td::Ref<vm::Cell>())
|
||||
); // global_config:(Maybe Cell) ] = SmartContractInfo;
|
||||
@ -66,6 +66,15 @@ td::Ref<vm::Tuple> prepare_vm_c7(td::uint32 now) {
|
||||
return vm::make_tuple_ref(std::move(tuple));
|
||||
}
|
||||
|
||||
static int output_actions_count(td::Ref<vm::Cell> list) {
|
||||
int i = -1;
|
||||
do {
|
||||
++i;
|
||||
list = load_cell_slice(std::move(list)).prefetch_ref();
|
||||
} while (list.not_null());
|
||||
return i;
|
||||
}
|
||||
|
||||
SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stack> stack, td::Ref<vm::Tuple> c7,
|
||||
vm::GasLimits gas, bool ignore_chksig) {
|
||||
auto gas_credit = gas.gas_credit;
|
||||
@ -123,6 +132,8 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
|
||||
if (res.success) {
|
||||
res.new_state.data = vm.get_c4();
|
||||
res.actions = vm.get_d(5);
|
||||
LOG(DEBUG) << "output actions:\n"
|
||||
<< block::gen::OutList{output_actions_count(res.actions)}.as_string_ref(res.actions);
|
||||
}
|
||||
LOG_IF(ERROR, gas_credit != 0 && (res.accepted && !res.success))
|
||||
<< "Accepted but failed with code " << res.code << "\n"
|
||||
@ -171,10 +182,13 @@ SmartContract::Answer SmartContract::run_method(Args args) {
|
||||
now = args.now.unwrap();
|
||||
}
|
||||
if (!args.c7) {
|
||||
args.c7 = prepare_vm_c7(now);
|
||||
args.c7 = prepare_vm_c7(now, args.balance);
|
||||
}
|
||||
if (!args.limits) {
|
||||
args.limits = vm::GasLimits{(long long)0, (long long)1000000, (long long)10000};
|
||||
bool is_internal = args.get_method_id().ok() == 0;
|
||||
|
||||
args.limits = vm::GasLimits{is_internal ? (long long)args.amount * 1000 : (long long)0, (long long)1000000,
|
||||
is_internal ? 0 : (long long)10000};
|
||||
}
|
||||
CHECK(args.stack);
|
||||
CHECK(args.method_id);
|
||||
@ -191,7 +205,7 @@ SmartContract::Answer SmartContract::run_get_method(Args args) const {
|
||||
now = args.now.unwrap();
|
||||
}
|
||||
if (!args.c7) {
|
||||
args.c7 = prepare_vm_c7(now);
|
||||
args.c7 = prepare_vm_c7(now, args.balance);
|
||||
}
|
||||
if (!args.limits) {
|
||||
args.limits = vm::GasLimits{1000000};
|
||||
@ -209,6 +223,11 @@ SmartContract::Answer SmartContract::run_get_method(td::Slice method, Args args)
|
||||
}
|
||||
|
||||
SmartContract::Answer SmartContract::send_external_message(td::Ref<vm::Cell> cell, Args args) {
|
||||
return run_method(args.set_stack(prepare_vm_stack(vm::load_cell_slice_ref(cell))).set_method_id(-1));
|
||||
return run_method(
|
||||
args.set_stack(prepare_vm_stack(td::make_refint(0), vm::load_cell_slice_ref(cell))).set_method_id(-1));
|
||||
}
|
||||
SmartContract::Answer SmartContract::send_internal_message(td::Ref<vm::Cell> cell, Args args) {
|
||||
return run_method(
|
||||
args.set_stack(prepare_vm_stack(td::make_refint(args.amount), vm::load_cell_slice_ref(cell))).set_method_id(0));
|
||||
}
|
||||
} // namespace ton
|
||||
|
@ -57,6 +57,8 @@ class SmartContract : public td::CntObject {
|
||||
td::optional<td::Ref<vm::Stack>> stack;
|
||||
td::optional<td::int32> now;
|
||||
bool ignore_chksig{false};
|
||||
td::uint64 amount{0};
|
||||
td::uint64 balance{0};
|
||||
|
||||
Args() {
|
||||
}
|
||||
@ -95,6 +97,14 @@ class SmartContract : public td::CntObject {
|
||||
this->ignore_chksig = ignore_chksig;
|
||||
return std::move(*this);
|
||||
}
|
||||
Args&& set_amount(td::uint64 amount) {
|
||||
this->amount = amount;
|
||||
return std::move(*this);
|
||||
}
|
||||
Args&& set_balance(td::uint64 balance) {
|
||||
this->balance = balance;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
td::Result<td::int32> get_method_id() const {
|
||||
if (!method_id) {
|
||||
@ -109,6 +119,7 @@ class SmartContract : public td::CntObject {
|
||||
Answer run_get_method(Args args = {}) const;
|
||||
Answer run_get_method(td::Slice method, Args args = {}) const;
|
||||
Answer send_external_message(td::Ref<vm::Cell> cell, Args args = {});
|
||||
Answer send_internal_message(td::Ref<vm::Cell> cell, Args args = {});
|
||||
|
||||
size_t code_size() const;
|
||||
size_t data_size() const;
|
||||
@ -122,6 +133,9 @@ class SmartContract : public td::CntObject {
|
||||
const State& get_state() const {
|
||||
return state_;
|
||||
}
|
||||
CntObject* make_copy() const override {
|
||||
return new SmartContract(state_);
|
||||
}
|
||||
|
||||
protected:
|
||||
State state_;
|
||||
|
@ -44,6 +44,8 @@ const auto& get_map() {
|
||||
#include "smartcont/auto/highload-wallet-code.cpp"
|
||||
#include "smartcont/auto/highload-wallet-v2-code.cpp"
|
||||
#include "smartcont/auto/dns-manual-code.cpp"
|
||||
#include "smartcont/auto/payment-channel-code.cpp"
|
||||
#include "smartcont/auto/restricted-wallet3-code.cpp"
|
||||
|
||||
with_tvm_code("highload-wallet-r1",
|
||||
"te6ccgEBBgEAhgABFP8A9KQT9KDyyAsBAgEgAgMCAUgEBQC88oMI1xgg0x/TH9Mf+CMTu/Jj7UTQ0x/TH9P/"
|
||||
@ -96,6 +98,13 @@ const auto& get_map() {
|
||||
"FwCEMQLTAAHAAZPUAdCY0wUBqgLXGAHiINdJwg/"
|
||||
"ypiB41yLXCwfyaHBTEddJqTYCmNMHAcAAEqEB5DDIywYBzxbJ0FADACBZ9KhvpSCUAvQEMJIybeICACg0A4AQ9FqZECOECUBE8AEBkjAx4gBmM"
|
||||
"SLAFZwy9AQQI4QJUELwAQHgIsAWmDIChAn0czAB4DAyIMAfkzD0BODAIJJtAeDyLG0B");
|
||||
with_tvm_code(
|
||||
"restricted-wallet3-r1",
|
||||
"te6ccgECEgEAAUwAART/APSkE/S88sgLAQIBIAIDAgFIBAUD+PKDCNcYINMf0x/THwL4I7vyY+1E0NMf0x/T/"
|
||||
"1NDuvKhUWK68qIG+QFUEHb5EPKkAY4fMwHT/9EB0x/0BNH4AAOkyMsfFMsfy/8Syx/0AMntVOEC0x/"
|
||||
"0BNH4ACH4I9s8IYAg9HtvpTGW+gAwcvsCkTDiApMg10qK6NECpMgPEBEABNAwAgEgBgcCASAICQIBSAwNAgFuCgsAEbjJftRNDXCx+"
|
||||
"AAXrc52omhpn5jrhf/AABmsePaiaEAQa5DrhY/AAQ222B8Ee2eQDgEJtQdbZ5AOAU7tRNCBAUDXIdMf9ATRAts8+CdvEAKAIPR7b6Uxl/"
|
||||
"oAMKFwtgmRMOIPADohjhExgPP4MyBukjBwlNDXCx/iAd8hkgGhklt/4gAM0wfUAvsAAB7LHxTLHxLL/8sf9ADJ7VQ=");
|
||||
return map;
|
||||
}();
|
||||
return map;
|
||||
@ -103,7 +112,6 @@ const auto& get_map() {
|
||||
} // namespace
|
||||
|
||||
td::Result<td::Ref<vm::Cell>> SmartContractCode::load(td::Slice name) {
|
||||
LOG(ERROR) << "LOAD " << name;
|
||||
auto& map = get_map();
|
||||
auto it = map.find(name);
|
||||
if (it == map.end()) {
|
||||
@ -146,6 +154,14 @@ td::Span<int> SmartContractCode::get_revisions(Type type) {
|
||||
static int res[] = {-1, 1};
|
||||
return res;
|
||||
}
|
||||
case Type::PaymentChannel: {
|
||||
static int res[] = {-1};
|
||||
return res;
|
||||
}
|
||||
case Type::RestrictedWallet: {
|
||||
static int res[] = {-1, 1};
|
||||
return res;
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
@ -190,6 +206,10 @@ td::Ref<vm::Cell> SmartContractCode::get_code(Type type, int ext_revision) {
|
||||
return "multisig";
|
||||
case Type::ManualDns:
|
||||
return "dns-manual";
|
||||
case Type::PaymentChannel:
|
||||
return "payment-channel";
|
||||
case Type::RestrictedWallet:
|
||||
return "restricted-wallet3";
|
||||
}
|
||||
UNREACHABLE();
|
||||
return "";
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "vm/cells.h"
|
||||
|
||||
#include "td/utils/Span.h"
|
||||
@ -25,7 +26,18 @@ class SmartContractCode {
|
||||
public:
|
||||
static td::Result<td::Ref<vm::Cell>> load(td::Slice name);
|
||||
|
||||
enum Type { WalletV1 = 1, WalletV1Ext, WalletV2, WalletV3, HighloadWalletV1, HighloadWalletV2, ManualDns, Multisig };
|
||||
enum Type {
|
||||
WalletV1 = 1,
|
||||
WalletV1Ext,
|
||||
WalletV2,
|
||||
WalletV3,
|
||||
HighloadWalletV1,
|
||||
HighloadWalletV2,
|
||||
ManualDns,
|
||||
Multisig,
|
||||
PaymentChannel,
|
||||
RestrictedWallet
|
||||
};
|
||||
static td::Span<int> get_revisions(Type type);
|
||||
static td::Result<int> validate_revision(Type type, int revision);
|
||||
static td::Ref<vm::Cell> get_code(Type type, int revision = 0);
|
||||
|
@ -43,12 +43,7 @@ td::Ref<vm::Cell> TestGiver::make_a_gift_message_static(td::uint32 seqno, td::Sp
|
||||
|
||||
for (auto& gift : gifts) {
|
||||
td::int32 send_mode = 1;
|
||||
auto gramms = gift.gramms;
|
||||
vm::CellBuilder cbi;
|
||||
GenericAccount::store_int_message(cbi, gift.destination, gramms);
|
||||
store_gift_message(cbi, gift);
|
||||
auto message_inner = cbi.finalize();
|
||||
cb.store_long(send_mode, 8).store_ref(std::move(message_inner));
|
||||
cb.store_long(send_mode, 8).store_ref(create_int_message(gift));
|
||||
}
|
||||
|
||||
return cb.finalize();
|
||||
|
@ -46,18 +46,11 @@ td::Ref<vm::Cell> TestWallet::make_a_gift_message_static(const td::Ed25519::Priv
|
||||
|
||||
for (auto& gift : gifts) {
|
||||
td::int32 send_mode = 3;
|
||||
auto gramms = gift.gramms;
|
||||
if (gramms == -1) {
|
||||
gramms = 0;
|
||||
if (gift.gramms == -1) {
|
||||
send_mode += 128;
|
||||
}
|
||||
vm::CellBuilder cbi;
|
||||
GenericAccount::store_int_message(cbi, gift.destination, gramms);
|
||||
store_gift_message(cbi, gift);
|
||||
auto message_inner = cbi.finalize();
|
||||
cb.store_long(send_mode, 8).store_ref(std::move(message_inner));
|
||||
cb.store_long(send_mode, 8).store_ref(create_int_message(gift));
|
||||
}
|
||||
|
||||
auto message_outer = cb.finalize();
|
||||
auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
|
||||
|
@ -52,16 +52,10 @@ td::Ref<vm::Cell> Wallet::make_a_gift_message(const td::Ed25519::PrivateKey& pri
|
||||
|
||||
for (auto& gift : gifts) {
|
||||
td::int32 send_mode = 3;
|
||||
auto gramms = gift.gramms;
|
||||
if (gramms == -1) {
|
||||
gramms = 0;
|
||||
if (gift.gramms == -1) {
|
||||
send_mode += 128;
|
||||
}
|
||||
vm::CellBuilder cbi;
|
||||
GenericAccount::store_int_message(cbi, gift.destination, gramms);
|
||||
store_gift_message(cbi, gift);
|
||||
auto message_inner = cbi.finalize();
|
||||
cb.store_long(send_mode, 8).store_ref(std::move(message_inner));
|
||||
cb.store_long(send_mode, 8).store_ref(create_int_message(gift));
|
||||
}
|
||||
|
||||
auto message_outer = cb.finalize();
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "WalletInterface.h"
|
||||
|
||||
#include "GenericAccount.h"
|
||||
|
||||
namespace ton {
|
||||
td::Ref<vm::Cell> WalletInterfaceRaw::create_int_message(const Gift &gift) {
|
||||
vm::CellBuilder cbi;
|
||||
GenericAccount::store_int_message(cbi, gift.destination, gift.gramms < 0 ? 0 : gift.gramms);
|
||||
if (gift.init_state.not_null()) {
|
||||
cbi.store_ones(2);
|
||||
cbi.store_ref(gift.init_state);
|
||||
}
|
||||
cbi.store_zeroes(0);
|
||||
store_gift_message(cbi, gift);
|
||||
return cbi.finalize();
|
||||
}
|
||||
|
||||
td::Result<td::Ed25519::PublicKey> WalletInterfaceRaw::get_public_key() const {
|
||||
auto sc = as_smart_constract();
|
||||
auto answer = sc.run_get_method("get_public_key");
|
||||
if (!answer.success) {
|
||||
return td::Status::Error("get_public_key failed");
|
||||
}
|
||||
auto do_get_public_key = [&]() -> td::Result<td::Ed25519::PublicKey> {
|
||||
auto key = answer.stack.write().pop_int_finite();
|
||||
td::SecureString bytes(32);
|
||||
if (!key->export_bytes(bytes.as_mutable_slice().ubegin(), bytes.size())) {
|
||||
return td::Status::Error("get_public_key failed");
|
||||
}
|
||||
return td::Ed25519::PublicKey(std::move(bytes));
|
||||
};
|
||||
return TRY_VM(do_get_public_key());
|
||||
}
|
||||
} // namespace ton
|
@ -24,6 +24,7 @@
|
||||
#include "vm/cells/CellString.h"
|
||||
|
||||
#include "SmartContract.h"
|
||||
#include "GenericAccount.h"
|
||||
|
||||
namespace ton {
|
||||
class WalletInterface {
|
||||
@ -36,6 +37,7 @@ class WalletInterface {
|
||||
std::string message;
|
||||
|
||||
td::Ref<vm::Cell> body;
|
||||
td::Ref<vm::Cell> init_state;
|
||||
};
|
||||
|
||||
virtual ~WalletInterface() {
|
||||
@ -48,15 +50,29 @@ class WalletInterface {
|
||||
return td::Status::Error("Unsupported");
|
||||
}
|
||||
|
||||
td::Result<td::Ref<vm::Cell>> get_init_message(const td::Ed25519::PrivateKey &private_key,
|
||||
td::uint32 valid_until = std::numeric_limits<td::uint32>::max()) {
|
||||
td::Result<td::Ref<vm::Cell>> get_init_message(
|
||||
const td::Ed25519::PrivateKey &private_key,
|
||||
td::uint32 valid_until = std::numeric_limits<td::uint32>::max()) const {
|
||||
return make_a_gift_message(private_key, valid_until, {});
|
||||
}
|
||||
static td::Ref<vm::Cell> create_int_message(const Gift &gift) {
|
||||
vm::CellBuilder cbi;
|
||||
GenericAccount::store_int_message(cbi, gift.destination, gift.gramms < 0 ? 0 : gift.gramms);
|
||||
if (gift.init_state.not_null()) {
|
||||
cbi.store_ones(2);
|
||||
cbi.store_ref(gift.init_state);
|
||||
} else {
|
||||
cbi.store_zeroes(1);
|
||||
}
|
||||
cbi.store_zeroes(1);
|
||||
store_gift_message(cbi, gift);
|
||||
return cbi.finalize();
|
||||
}
|
||||
static void store_gift_message(vm::CellBuilder &cb, const Gift &gift) {
|
||||
if (gift.body.not_null()) {
|
||||
auto body = vm::load_cell_slice(gift.body);
|
||||
//TODO: handle error
|
||||
cb.append_cellslice_bool(body);
|
||||
CHECK(cb.append_cellslice_bool(body));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -62,16 +62,10 @@ td::Ref<vm::Cell> WalletV3::make_a_gift_message(const td::Ed25519::PrivateKey& p
|
||||
|
||||
for (auto& gift : gifts) {
|
||||
td::int32 send_mode = 3;
|
||||
auto gramms = gift.gramms;
|
||||
if (gramms == -1) {
|
||||
gramms = 0;
|
||||
if (gift.gramms == -1) {
|
||||
send_mode += 128;
|
||||
}
|
||||
vm::CellBuilder cbi;
|
||||
GenericAccount::store_int_message(cbi, gift.destination, gramms);
|
||||
store_gift_message(cbi, gift);
|
||||
auto message_inner = cbi.finalize();
|
||||
cb.store_long(send_mode, 8).store_ref(std::move(message_inner));
|
||||
cb.store_long(send_mode, 8).store_ref(create_int_message(gift));
|
||||
}
|
||||
|
||||
auto message_outer = cb.finalize();
|
||||
|
@ -70,3 +70,209 @@ class WalletV3 : public ton::SmartContract, public WalletInterface {
|
||||
td::Result<td::Ed25519::PublicKey> get_public_key_or_throw() const;
|
||||
};
|
||||
} // namespace ton
|
||||
|
||||
#include "smc-envelope/SmartContractCode.h"
|
||||
#include "smc-envelope/GenericAccount.h"
|
||||
#include "block/block-parse.h"
|
||||
#include <algorithm>
|
||||
namespace ton {
|
||||
template <class WalletT, class TraitsT>
|
||||
class WalletBase : public SmartContract, public WalletInterface {
|
||||
public:
|
||||
using Traits = TraitsT;
|
||||
using InitData = typename Traits::InitData;
|
||||
|
||||
explicit WalletBase(State state) : SmartContract(std::move(state)) {
|
||||
}
|
||||
static td::Ref<WalletT> create(State state) {
|
||||
return td::Ref<WalletT>(true, std::move(state));
|
||||
}
|
||||
static td::Ref<vm::Cell> get_init_code(int revision) {
|
||||
return SmartContractCode::get_code(get_code_type(), revision);
|
||||
};
|
||||
size_t get_max_gifts_size() const override {
|
||||
return Traits::max_gifts_size;
|
||||
}
|
||||
static SmartContractCode::Type get_code_type() {
|
||||
return Traits::code_type;
|
||||
}
|
||||
static td::optional<td::int32> guess_revision(const vm::Cell::Hash& code_hash) {
|
||||
for (auto i : ton::SmartContractCode::get_revisions(get_code_type())) {
|
||||
auto code = SmartContractCode::get_code(get_code_type(), i);
|
||||
if (code->get_hash() == code_hash) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static td::Ref<WalletT> create(const InitData& init_data, int revision) {
|
||||
return td::Ref<WalletT>(true, State{get_init_code(revision), WalletT::get_init_data(init_data)});
|
||||
}
|
||||
|
||||
td::Result<td::uint32> get_seqno() const {
|
||||
return TRY_VM([&]() -> td::Result<td::uint32> {
|
||||
Answer answer = this->run_get_method("seqno");
|
||||
if (!answer.success) {
|
||||
return td::Status::Error("seqno get method failed");
|
||||
}
|
||||
return static_cast<td::uint32>(answer.stack.write().pop_long_range(std::numeric_limits<td::uint32>::max()));
|
||||
}());
|
||||
}
|
||||
td::Result<td::uint32> get_wallet_id() const {
|
||||
return TRY_VM([&]() -> td::Result<td::uint32> {
|
||||
Answer answer = this->run_get_method("wallet_id");
|
||||
if (!answer.success) {
|
||||
return td::Status::Error("seqno get method failed");
|
||||
}
|
||||
return static_cast<td::uint32>(answer.stack.write().pop_long_range(std::numeric_limits<td::uint32>::max()));
|
||||
}());
|
||||
}
|
||||
|
||||
td::Result<td::uint64> get_balance(td::uint64 account_balance, td::uint32 now) const {
|
||||
return TRY_VM([&]() -> td::Result<td::uint64> {
|
||||
Answer answer = this->run_get_method(Args().set_method_id("balance").set_balance(account_balance).set_now(now));
|
||||
if (!answer.success) {
|
||||
return td::Status::Error("balance get method failed");
|
||||
}
|
||||
return static_cast<td::uint64>(answer.stack.write().pop_long());
|
||||
}());
|
||||
}
|
||||
|
||||
td::Result<td::Ed25519::PublicKey> get_public_key() const override {
|
||||
return TRY_VM([&]() -> td::Result<td::Ed25519::PublicKey> {
|
||||
Answer answer = this->run_get_method("get_public_key");
|
||||
if (!answer.success) {
|
||||
return td::Status::Error("get_public_key get method failed");
|
||||
}
|
||||
auto key_int = answer.stack.write().pop_int();
|
||||
LOG(ERROR) << key_int->bit_size(false);
|
||||
td::SecureString bytes(32);
|
||||
if (!key_int->export_bytes(bytes.as_mutable_slice().ubegin(), bytes.size(), false)) {
|
||||
return td::Status::Error("not a public key");
|
||||
}
|
||||
return td::Ed25519::PublicKey(std::move(bytes));
|
||||
}());
|
||||
};
|
||||
};
|
||||
|
||||
struct RestrictedWalletTraits {
|
||||
struct InitData {
|
||||
td::SecureString init_key;
|
||||
td::SecureString main_key;
|
||||
td::uint32 wallet_id{0};
|
||||
};
|
||||
|
||||
static constexpr unsigned max_message_size = vm::CellString::max_bytes;
|
||||
static constexpr unsigned max_gifts_size = 4;
|
||||
static constexpr auto code_type = SmartContractCode::RestrictedWallet;
|
||||
};
|
||||
|
||||
class RestrictedWallet : public WalletBase<RestrictedWallet, RestrictedWalletTraits> {
|
||||
public:
|
||||
struct Config {
|
||||
td::uint32 start_at{0};
|
||||
std::vector<std::pair<td::int32, td::uint64>> limits;
|
||||
};
|
||||
|
||||
explicit RestrictedWallet(State state) : WalletBase(std::move(state)) {
|
||||
}
|
||||
|
||||
td::Result<Config> get_config() const {
|
||||
return TRY_VM([this]() -> td::Result<Config> {
|
||||
auto cs = vm::load_cell_slice(get_state().data);
|
||||
Config config;
|
||||
td::Ref<vm::Cell> dict_root;
|
||||
auto ok = cs.advance(32 + 32 + 256) && cs.fetch_uint_to(32, config.start_at) && cs.fetch_maybe_ref(dict_root);
|
||||
vm::Dictionary dict(std::move(dict_root), 32);
|
||||
dict.check_for_each([&](auto cs, auto ptr, auto ptr_bits) {
|
||||
auto r_seconds = td::narrow_cast_safe<td::int32>(dict.key_as_integer(ptr, true)->to_long());
|
||||
if (r_seconds.is_error()) {
|
||||
ok = false;
|
||||
return ok;
|
||||
}
|
||||
td::uint64 value;
|
||||
ok &= smc::unpack_grams(cs, value);
|
||||
config.limits.emplace_back(r_seconds.ok(), value);
|
||||
return ok;
|
||||
});
|
||||
if (!ok) {
|
||||
return td::Status::Error("Can't parse config");
|
||||
}
|
||||
std::sort(config.limits.begin(), config.limits.end());
|
||||
return config;
|
||||
}());
|
||||
}
|
||||
|
||||
static td::Ref<vm::Cell> get_init_data(const InitData& init_data) {
|
||||
vm::CellBuilder cb;
|
||||
cb.store_long(0, 32);
|
||||
cb.store_long(init_data.wallet_id, 32);
|
||||
CHECK(init_data.init_key.size() == 32);
|
||||
CHECK(init_data.main_key.size() == 32);
|
||||
cb.store_bytes(init_data.init_key.as_slice());
|
||||
cb.store_bytes(init_data.main_key.as_slice());
|
||||
return cb.finalize();
|
||||
}
|
||||
|
||||
td::Result<td::Ref<vm::Cell>> get_init_message(const td::Ed25519::PrivateKey& init_private_key,
|
||||
td::uint32 valid_until, const Config& config) const {
|
||||
vm::CellBuilder cb;
|
||||
TRY_RESULT(seqno, get_seqno());
|
||||
TRY_RESULT(wallet_id, get_wallet_id());
|
||||
LOG(ERROR) << "seqno: " << seqno << " wallet_id: " << wallet_id;
|
||||
if (seqno != 0) {
|
||||
return td::Status::Error("Wallet is already inited");
|
||||
}
|
||||
|
||||
cb.store_long(wallet_id, 32);
|
||||
cb.store_long(valid_until, 32);
|
||||
cb.store_long(seqno, 32);
|
||||
|
||||
cb.store_long(config.start_at, 32);
|
||||
vm::Dictionary dict(32);
|
||||
|
||||
auto add = [&](td::int32 till, td::uint64 value) {
|
||||
auto key = dict.integer_key(td::make_refint(till), 32, true);
|
||||
vm::CellBuilder gcb;
|
||||
block::tlb::t_Grams.store_integer_value(gcb, td::BigInt256(value));
|
||||
dict.set_builder(key.bits(), 32, gcb);
|
||||
};
|
||||
for (auto limit : config.limits) {
|
||||
add(limit.first, limit.second);
|
||||
}
|
||||
cb.store_maybe_ref(dict.get_root_cell());
|
||||
|
||||
auto message_outer = cb.finalize();
|
||||
auto signature = init_private_key.sign(message_outer->get_hash().as_slice()).move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
|
||||
}
|
||||
|
||||
td::Result<td::Ref<vm::Cell>> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 valid_until,
|
||||
td::Span<Gift> gifts) const override {
|
||||
CHECK(gifts.size() <= Traits::max_gifts_size);
|
||||
|
||||
vm::CellBuilder cb;
|
||||
TRY_RESULT(seqno, get_seqno());
|
||||
TRY_RESULT(wallet_id, get_wallet_id());
|
||||
if (seqno == 0) {
|
||||
return td::Status::Error("Wallet is not inited yet");
|
||||
}
|
||||
cb.store_long(wallet_id, 32);
|
||||
cb.store_long(valid_until, 32);
|
||||
cb.store_long(seqno, 32);
|
||||
|
||||
for (auto& gift : gifts) {
|
||||
td::int32 send_mode = 3;
|
||||
if (gift.gramms == -1) {
|
||||
send_mode += 128;
|
||||
}
|
||||
cb.store_long(send_mode, 8).store_ref(create_int_message(gift));
|
||||
}
|
||||
|
||||
auto message_outer = cb.finalize();
|
||||
auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok();
|
||||
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
|
||||
}
|
||||
};
|
||||
} // namespace ton
|
||||
|
@ -1542,6 +1542,7 @@ template <class DeserializerT>
|
||||
class BenchBocDeserializer : public td::Benchmark {
|
||||
public:
|
||||
BenchBocDeserializer(std::string name, BenchBocDeserializerConfig config) : name_(std::move(name)), config_(config) {
|
||||
td::PerfWarningTimer perf("A", 1);
|
||||
fast_array_ = vm::FastCompactArray(array_size);
|
||||
td::Random::Xorshift128plus rnd{123};
|
||||
for (td::uint32 i = 0; i < array_size; i++) {
|
||||
|
@ -21,7 +21,9 @@
|
||||
|
||||
#include "Ed25519.h"
|
||||
|
||||
#include "block/block-auto.h"
|
||||
#include "block/block.h"
|
||||
#include "block/block-parse.h"
|
||||
|
||||
#include "fift/Fift.h"
|
||||
#include "fift/words.h"
|
||||
@ -38,6 +40,7 @@
|
||||
#include "smc-envelope/WalletV3.h"
|
||||
#include "smc-envelope/HighloadWallet.h"
|
||||
#include "smc-envelope/HighloadWalletV2.h"
|
||||
#include "smc-envelope/PaymentChannel.h"
|
||||
|
||||
#include "td/utils/base64.h"
|
||||
#include "td/utils/crypto.h"
|
||||
@ -489,6 +492,99 @@ TEST(Tonlib, TestGiver) {
|
||||
CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == res->get_hash());
|
||||
}
|
||||
|
||||
TEST(Tonlib, RestrictedWallet) {
|
||||
//auto source_lookup = fift::create_mem_source_lookup(load_source("smartcont/new-restricted-wallet2.fif")).move_as_ok();
|
||||
//source_lookup
|
||||
//.write_file("/auto/restricted-wallet2-code.fif", load_source("smartcont/auto/restricted-wallet2-code.fif"))
|
||||
//.ensure();
|
||||
//class ZeroOsTime : public fift::OsTime {
|
||||
//public:
|
||||
//td::uint32 now() override {
|
||||
//return 0;
|
||||
//}
|
||||
//};
|
||||
//source_lookup.set_os_time(std::make_unique<ZeroOsTime>());
|
||||
//auto priv_key = td::Ed25519::generate_private_key().move_as_ok();
|
||||
//auto pub_key = priv_key.get_public_key().move_as_ok();
|
||||
//auto pub_key_serialized = block::PublicKey::from_bytes(pub_key.as_octet_string()).move_as_ok().serialize(true);
|
||||
|
||||
//std::vector<std::string> args = {"path", pub_key_serialized, std::string("100")};
|
||||
//auto fift_output = fift::mem_run_fift(std::move(source_lookup), args).move_as_ok();
|
||||
|
||||
//ton::RestrictedWallet::InitData init_data;
|
||||
//td::uint64 x = 100 * 1000000000ull;
|
||||
//init_data.key = &pub_key;
|
||||
//init_data.start_at = 0;
|
||||
//init_data.limits = {{-32768, x}, {92, x * 3 / 4}, {183, x * 1 / 2}, {366, x * 1 / 4}, {548, 0}};
|
||||
//auto wallet = ton::RestrictedWallet::create(init_data, -1);
|
||||
|
||||
//ASSERT_EQ(0u, wallet->get_seqno().move_as_ok());
|
||||
//CHECK(pub_key.as_octet_string() == wallet->get_public_key().move_as_ok().as_octet_string());
|
||||
////LOG(ERROR) << wallet->get_balance(x, 60 * 60 * 24 * 400).move_as_ok();
|
||||
|
||||
//auto new_wallet_query = fift_output.source_lookup.read_file("rwallet-query.boc").move_as_ok().data;
|
||||
//auto new_wallet_addr = fift_output.source_lookup.read_file("rwallet.addr").move_as_ok().data;
|
||||
|
||||
//auto address = wallet->get_address(-1);
|
||||
////CHECK(address.addr.as_slice() == td::Slice(new_wallet_addr).substr(0, 32));
|
||||
//address.bounceable = false;
|
||||
//auto res = ton::GenericAccount::create_ext_message(address, wallet->get_init_state(),
|
||||
//wallet->get_init_message(priv_key).move_as_ok());
|
||||
//LOG(ERROR) << "-------";
|
||||
//vm::load_cell_slice(res).print_rec(std::cerr);
|
||||
//LOG(ERROR) << "-------";
|
||||
//vm::load_cell_slice(vm::std_boc_deserialize(new_wallet_query).move_as_ok()).print_rec(std::cerr);
|
||||
//CHECK(vm::std_boc_deserialize(new_wallet_query).move_as_ok()->get_hash() == res->get_hash());
|
||||
|
||||
//auto dest = block::StdAddress::parse("Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX").move_as_ok();
|
||||
//fift_output.source_lookup.write_file("/main.fif", load_source("smartcont/wallet-v2.fif")).ensure();
|
||||
//fift_output.source_lookup.write_file("rwallet.pk", priv_key.as_octet_string().as_slice()).ensure();
|
||||
//fift_output = fift::mem_run_fift(
|
||||
//std::move(fift_output.source_lookup),
|
||||
//{"aba", "rwallet", "-C", "TESTv2", "Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX", "0", "321"})
|
||||
//.move_as_ok();
|
||||
//auto wallet_query = fift_output.source_lookup.read_file("wallet-query.boc").move_as_ok().data;
|
||||
//ton::TestWallet::Gift gift;
|
||||
//gift.destination = dest;
|
||||
//gift.message = "TESTv2";
|
||||
//gift.gramms = 321000000000ll;
|
||||
////CHECK(priv_key.get_public_key().ok().as_octet_string() == wallet->get_public_key().ok().as_octet_string());
|
||||
//auto gift_message = ton::GenericAccount::create_ext_message(
|
||||
//address, {}, wallet->make_a_gift_message(priv_key, 60, {gift}).move_as_ok());
|
||||
//LOG(ERROR) << "-------";
|
||||
//vm::load_cell_slice(gift_message).print_rec(std::cerr);
|
||||
//LOG(ERROR) << "-------";
|
||||
//vm::load_cell_slice(vm::std_boc_deserialize(wallet_query).move_as_ok()).print_rec(std::cerr);
|
||||
//CHECK(vm::std_boc_deserialize(wallet_query).move_as_ok()->get_hash() == gift_message->get_hash());
|
||||
}
|
||||
TEST(Tonlib, RestrictedWallet3) {
|
||||
auto init_priv_key = td::Ed25519::generate_private_key().move_as_ok();
|
||||
auto init_pub_key = init_priv_key.get_public_key().move_as_ok();
|
||||
auto priv_key = td::Ed25519::generate_private_key().move_as_ok();
|
||||
auto pub_key = priv_key.get_public_key().move_as_ok();
|
||||
|
||||
ton::RestrictedWallet::InitData init_data;
|
||||
init_data.init_key = init_pub_key.as_octet_string();
|
||||
init_data.main_key = pub_key.as_octet_string();
|
||||
init_data.wallet_id = 123;
|
||||
auto wallet = ton::RestrictedWallet::create(init_data, -1);
|
||||
|
||||
auto address = wallet->get_address();
|
||||
|
||||
td::uint64 x = 100 * 1000000000ull;
|
||||
ton::RestrictedWallet::Config config;
|
||||
config.start_at = 1;
|
||||
config.limits = {{-32768, x}, {92, x * 3 / 4}, {183, x * 1 / 2}, {366, x * 1 / 4}, {548, 0}};
|
||||
CHECK(wallet.write().send_external_message(wallet->get_init_message(init_priv_key, 10, config).move_as_ok()).success);
|
||||
CHECK(wallet->get_seqno().move_as_ok() == 1);
|
||||
|
||||
ton::WalletInterface::Gift gift;
|
||||
gift.destination = address;
|
||||
gift.message = "hello";
|
||||
CHECK(wallet.write().send_external_message(wallet->make_a_gift_message(priv_key, 10, {gift}).move_as_ok()).success);
|
||||
CHECK(wallet->get_seqno().move_as_ok() == 2);
|
||||
}
|
||||
|
||||
class SimpleWallet : public ton::SmartContract {
|
||||
public:
|
||||
SimpleWallet(State state) : SmartContract(std::move(state)) {
|
||||
@ -1286,3 +1382,397 @@ TEST(Smartcont, DnsManual) {
|
||||
// TODO: rethink semantic of creating an empty dictionary
|
||||
do_dns_test(CheckedDns(true, true));
|
||||
}
|
||||
|
||||
using namespace ton::pchan;
|
||||
|
||||
template <class T>
|
||||
struct ValidateState {
|
||||
T& self() {
|
||||
return static_cast<T&>(*this);
|
||||
}
|
||||
|
||||
void init(td::Ref<vm::Cell> state) {
|
||||
state_ = state;
|
||||
block::gen::ChanData::Record data_rec;
|
||||
if (!tlb::unpack_cell(state, data_rec)) {
|
||||
on_fatal_error(td::Status::Error("Expected Data"));
|
||||
return;
|
||||
}
|
||||
if (!tlb::unpack_cell(data_rec.state, self().rec)) {
|
||||
on_fatal_error(td::Status::Error("Expected StatePayout"));
|
||||
return;
|
||||
}
|
||||
CHECK(self().rec.A.not_null());
|
||||
}
|
||||
|
||||
T& expect_grams(td::Ref<vm::CellSlice> cs, td::uint64 expected, td::Slice name) {
|
||||
if (has_fatal_error_) {
|
||||
return self();
|
||||
}
|
||||
td::RefInt256 got;
|
||||
CHECK(cs.not_null());
|
||||
CHECK(block::tlb::t_Grams.as_integer_to(cs, got));
|
||||
if (got->cmp(expected) != 0) {
|
||||
on_error(td::Status::Error(PSLICE() << name << ": expected " << expected << ", got " << got->to_dec_string()));
|
||||
}
|
||||
return self();
|
||||
}
|
||||
template <class S>
|
||||
T& expect_eq(S a, S expected, td::Slice name) {
|
||||
if (has_fatal_error_) {
|
||||
return self();
|
||||
}
|
||||
if (!(a == expected)) {
|
||||
on_error(td::Status::Error(PSLICE() << name << ": expected " << expected << ", got " << a));
|
||||
}
|
||||
return self();
|
||||
}
|
||||
|
||||
td::Status finish() {
|
||||
if (errors_.empty()) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
std::stringstream ss;
|
||||
block::gen::t_ChanData.print_ref(ss, state_);
|
||||
td::StringBuilder sb;
|
||||
for (auto& error : errors_) {
|
||||
sb << error << "\n";
|
||||
}
|
||||
sb << ss.str();
|
||||
return td::Status::Error(sb.as_cslice());
|
||||
}
|
||||
|
||||
void on_fatal_error(td::Status error) {
|
||||
CHECK(!has_fatal_error_);
|
||||
has_fatal_error_ = true;
|
||||
on_error(std::move(error));
|
||||
}
|
||||
void on_error(td::Status error) {
|
||||
CHECK(error.is_error());
|
||||
errors_.push_back(std::move(error));
|
||||
}
|
||||
|
||||
public:
|
||||
td::Ref<vm::Cell> state_;
|
||||
bool has_fatal_error_{false};
|
||||
std::vector<td::Status> errors_;
|
||||
};
|
||||
|
||||
struct ValidateStatePayout : public ValidateState<ValidateStatePayout> {
|
||||
ValidateStatePayout& expect_A(td::uint64 a) {
|
||||
expect_grams(rec.A, a, "A");
|
||||
return *this;
|
||||
}
|
||||
ValidateStatePayout& expect_B(td::uint64 b) {
|
||||
expect_grams(rec.B, b, "B");
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValidateStatePayout(td::Ref<vm::Cell> state) {
|
||||
init(std::move(state));
|
||||
}
|
||||
|
||||
block::gen::ChanState::Record_chan_state_payout rec;
|
||||
};
|
||||
|
||||
struct ValidateStateInit : public ValidateState<ValidateStateInit> {
|
||||
ValidateStateInit& expect_A(td::uint64 a) {
|
||||
expect_grams(rec.A, a, "A");
|
||||
return *this;
|
||||
}
|
||||
ValidateStateInit& expect_B(td::uint64 b) {
|
||||
expect_grams(rec.B, b, "B");
|
||||
return *this;
|
||||
}
|
||||
ValidateStateInit& expect_min_A(td::uint64 a) {
|
||||
expect_grams(rec.min_A, a, "min_A");
|
||||
return *this;
|
||||
}
|
||||
ValidateStateInit& expect_min_B(td::uint64 b) {
|
||||
expect_grams(rec.min_B, b, "min_B");
|
||||
return *this;
|
||||
}
|
||||
ValidateStateInit& expect_expire_at(td::uint32 b) {
|
||||
expect_eq(rec.expire_at, b, "expire_at");
|
||||
return *this;
|
||||
}
|
||||
ValidateStateInit& expect_signed_A(bool x) {
|
||||
expect_eq(rec.signed_A, x, "signed_A");
|
||||
return *this;
|
||||
}
|
||||
ValidateStateInit& expect_signed_B(bool x) {
|
||||
expect_eq(rec.signed_B, x, "signed_B");
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValidateStateInit(td::Ref<vm::Cell> state) {
|
||||
init(std::move(state));
|
||||
}
|
||||
|
||||
block::gen::ChanState::Record_chan_state_init rec;
|
||||
};
|
||||
|
||||
struct ValidateStateClose : public ValidateState<ValidateStateClose> {
|
||||
ValidateStateClose& expect_A(td::uint64 a) {
|
||||
expect_grams(rec.A, a, "A");
|
||||
return *this;
|
||||
}
|
||||
ValidateStateClose& expect_B(td::uint64 b) {
|
||||
expect_grams(rec.B, b, "B");
|
||||
return *this;
|
||||
}
|
||||
ValidateStateClose& expect_promise_A(td::uint64 a) {
|
||||
expect_grams(rec.promise_A, a, "promise_A");
|
||||
return *this;
|
||||
}
|
||||
ValidateStateClose& expect_promise_B(td::uint64 b) {
|
||||
expect_grams(rec.promise_B, b, "promise_B");
|
||||
return *this;
|
||||
}
|
||||
ValidateStateClose& expect_expire_at(td::uint32 b) {
|
||||
expect_eq(rec.expire_at, b, "expire_at");
|
||||
return *this;
|
||||
}
|
||||
ValidateStateClose& expect_signed_A(bool x) {
|
||||
expect_eq(rec.signed_A, x, "signed_A");
|
||||
return *this;
|
||||
}
|
||||
ValidateStateClose& expect_signed_B(bool x) {
|
||||
expect_eq(rec.signed_B, x, "signed_B");
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValidateStateClose(td::Ref<vm::Cell> state) {
|
||||
init(std::move(state));
|
||||
}
|
||||
|
||||
block::gen::ChanState::Record_chan_state_close rec;
|
||||
};
|
||||
|
||||
// config$_ initTimeout:int exitTimeout:int a_key:int256 b_key:int256 a_addr b_addr channel_id:int256 = Config;
|
||||
TEST(Smarcont, Channel) {
|
||||
auto code = ton::SmartContractCode::get_code(ton::SmartContractCode::PaymentChannel);
|
||||
Config config;
|
||||
auto a_pkey = td::Ed25519::generate_private_key().move_as_ok();
|
||||
auto b_pkey = td::Ed25519::generate_private_key().move_as_ok();
|
||||
config.init_timeout = 20;
|
||||
config.close_timeout = 40;
|
||||
auto dest = block::StdAddress::parse("Ef9Tj6fMJP+OqhAdhKXxq36DL+HYSzCc3+9O6UNzqsgPfYFX").move_as_ok();
|
||||
config.a_addr = dest;
|
||||
config.b_addr = dest;
|
||||
config.a_key = a_pkey.get_public_key().ok().as_octet_string();
|
||||
config.b_key = b_pkey.get_public_key().ok().as_octet_string();
|
||||
config.channel_id = 123;
|
||||
|
||||
Data data;
|
||||
data.config = config.serialize();
|
||||
data.state = data.init_state();
|
||||
auto data_cell = data.serialize();
|
||||
|
||||
auto channel = ton::SmartContract::create(ton::SmartContract::State{code, data_cell});
|
||||
ValidateStateInit(channel->get_state().data)
|
||||
.expect_A(0)
|
||||
.expect_B(0)
|
||||
.expect_min_A(0)
|
||||
.expect_min_B(0)
|
||||
.expect_signed_A(false)
|
||||
.expect_signed_B(false)
|
||||
.expect_expire_at(0)
|
||||
.finish()
|
||||
.ensure();
|
||||
|
||||
enum err {
|
||||
ok = 0,
|
||||
wrong_a_signature = 31,
|
||||
wrong_b_signature,
|
||||
msg_value_too_small,
|
||||
replay_protection,
|
||||
no_timeout,
|
||||
expected_init,
|
||||
expected_close,
|
||||
no_promise_signature,
|
||||
wrong_channel_id
|
||||
};
|
||||
|
||||
#define expect_code(description, expected_code, e) \
|
||||
{ \
|
||||
auto res = e; \
|
||||
LOG_IF(FATAL, expected_code != res.code) << " res.code=" << res.code << " " << description << "\n" << #e; \
|
||||
}
|
||||
#define expect_ok(description, e) expect_code(description, 0, e)
|
||||
|
||||
expect_code("Trying to invoke a timeout while channel is empty", no_timeout,
|
||||
channel.write().send_external_message(MsgTimeoutBuilder().finalize(),
|
||||
ton::SmartContract::Args().set_now(1000000)));
|
||||
|
||||
expect_code("External init message with no signatures", replay_protection,
|
||||
channel.write().send_external_message(MsgInitBuilder().channel_id(config.channel_id).finalize()));
|
||||
expect_code("Internal init message with not enough value", msg_value_too_small,
|
||||
channel.write().send_internal_message(
|
||||
MsgInitBuilder().channel_id(config.channel_id).inc_A(1000).min_B(2000).with_a_key(&a_pkey).finalize(),
|
||||
ton::SmartContract::Args().set_amount(100)));
|
||||
expect_code(
|
||||
"Internal init message with wrong channel_id", wrong_channel_id,
|
||||
channel.write().send_internal_message(MsgInitBuilder().inc_A(1000).min_B(2000).with_a_key(&a_pkey).finalize(),
|
||||
ton::SmartContract::Args().set_amount(1000)));
|
||||
expect_ok("A init with (inc_A = 1000, min_A = 1, min_B = 2000)",
|
||||
channel.write().send_internal_message(MsgInitBuilder()
|
||||
.channel_id(config.channel_id)
|
||||
.inc_A(1000)
|
||||
.min_A(1)
|
||||
.min_B(2000)
|
||||
.with_a_key(&a_pkey)
|
||||
.finalize(),
|
||||
ton::SmartContract::Args().set_amount(1000)));
|
||||
ValidateStateInit(channel->get_state().data)
|
||||
.expect_A(1000)
|
||||
.expect_B(0)
|
||||
.expect_min_A(1)
|
||||
.expect_min_B(2000)
|
||||
.expect_signed_A(true)
|
||||
.expect_signed_B(false)
|
||||
.expect_expire_at(config.init_timeout)
|
||||
.finish()
|
||||
.ensure();
|
||||
|
||||
expect_code("Repeated init of A init with (inc_A = 100, min_B = 5000). Must be ignored", replay_protection,
|
||||
channel.write().send_internal_message(
|
||||
MsgInitBuilder().channel_id(config.channel_id).inc_A(100).min_B(5000).with_a_key(&a_pkey).finalize(),
|
||||
ton::SmartContract::Args().set_amount(1000)));
|
||||
expect_code(
|
||||
"Trying to invoke a timeout too early", no_timeout,
|
||||
channel.write().send_external_message(MsgTimeoutBuilder().finalize(), ton::SmartContract::Args().set_now(0)));
|
||||
|
||||
{
|
||||
auto channel_copy = channel;
|
||||
expect_ok("Invoke a timeout", channel_copy.write().send_external_message(MsgTimeoutBuilder().finalize(),
|
||||
ton::SmartContract::Args().set_now(21)));
|
||||
ValidateStatePayout(channel_copy->get_state().data).expect_A(1000).expect_B(0).finish().ensure();
|
||||
}
|
||||
{
|
||||
auto channel_copy = channel;
|
||||
expect_ok("B init with inc_B < min_B. Leads to immediate payout",
|
||||
channel_copy.write().send_internal_message(
|
||||
MsgInitBuilder().channel_id(config.channel_id).inc_B(1500).with_b_key(&b_pkey).finalize(),
|
||||
ton::SmartContract::Args().set_amount(1500)));
|
||||
ValidateStatePayout(channel_copy->get_state().data).expect_A(1000).expect_B(1500).finish().ensure();
|
||||
}
|
||||
|
||||
expect_ok("B init with (inc_B = 2000, min_A = 1, min_A = 1000)",
|
||||
channel.write().send_internal_message(
|
||||
MsgInitBuilder().channel_id(config.channel_id).inc_B(2000).min_A(1000).with_b_key(&b_pkey).finalize(),
|
||||
ton::SmartContract::Args().set_amount(2000)));
|
||||
ValidateStateClose(channel->get_state().data)
|
||||
.expect_A(1000)
|
||||
.expect_B(2000)
|
||||
.expect_promise_A(0)
|
||||
.expect_promise_B(0)
|
||||
.expect_signed_A(false)
|
||||
.expect_signed_B(false)
|
||||
.expect_expire_at(0)
|
||||
.finish()
|
||||
.ensure();
|
||||
|
||||
{
|
||||
auto channel_copy = channel;
|
||||
expect_ok("A&B send Promise(1000000, 1000000 + 10) signed by nobody",
|
||||
channel_copy.write().send_external_message(MsgCloseBuilder()
|
||||
.signed_promise(SignedPromiseBuilder()
|
||||
.promise_A(1000000)
|
||||
.promise_B(1000000 + 10)
|
||||
.channel_id(config.channel_id)
|
||||
.finalize())
|
||||
.with_a_key(&a_pkey)
|
||||
.with_b_key(&b_pkey)
|
||||
.finalize(),
|
||||
ton::SmartContract::Args().set_now(21)));
|
||||
ValidateStatePayout(channel_copy->get_state().data).expect_A(1000 + 10).expect_B(2000 - 10).finish().ensure();
|
||||
}
|
||||
{
|
||||
auto channel_copy = channel;
|
||||
expect_ok("A&B send Promise(1000000, 1000000 + 10) signed by A",
|
||||
channel_copy.write().send_external_message(MsgCloseBuilder()
|
||||
.signed_promise(SignedPromiseBuilder()
|
||||
.promise_A(1000000)
|
||||
.promise_B(1000000 + 10)
|
||||
.with_key(&a_pkey)
|
||||
.channel_id(config.channel_id)
|
||||
.finalize())
|
||||
.with_a_key(&a_pkey)
|
||||
.with_b_key(&b_pkey)
|
||||
.finalize(),
|
||||
ton::SmartContract::Args().set_now(21)));
|
||||
ValidateStatePayout(channel_copy->get_state().data).expect_A(1000 + 10).expect_B(2000 - 10).finish().ensure();
|
||||
}
|
||||
|
||||
expect_code(
|
||||
"A sends Promise(1000000, 0) signed by A", wrong_b_signature,
|
||||
channel.write().send_external_message(
|
||||
MsgCloseBuilder()
|
||||
.signed_promise(
|
||||
SignedPromiseBuilder().promise_A(1000000).with_key(&a_pkey).channel_id(config.channel_id).finalize())
|
||||
.with_a_key(&a_pkey)
|
||||
.finalize(),
|
||||
ton::SmartContract::Args().set_now(21)));
|
||||
expect_code(
|
||||
"B sends Promise(1000000, 0) signed by B", wrong_a_signature,
|
||||
channel.write().send_external_message(
|
||||
MsgCloseBuilder()
|
||||
.signed_promise(
|
||||
SignedPromiseBuilder().promise_A(1000000).with_key(&b_pkey).channel_id(config.channel_id).finalize())
|
||||
.with_b_key(&b_pkey)
|
||||
.finalize(),
|
||||
ton::SmartContract::Args().set_now(21)));
|
||||
expect_code("B sends Promise(1000000, 0) signed by A with wrong channel_id", wrong_channel_id,
|
||||
channel.write().send_external_message(MsgCloseBuilder()
|
||||
.signed_promise(SignedPromiseBuilder()
|
||||
.promise_A(1000000)
|
||||
.with_key(&a_pkey)
|
||||
.channel_id(config.channel_id + 1)
|
||||
.finalize())
|
||||
.with_b_key(&b_pkey)
|
||||
.finalize(),
|
||||
ton::SmartContract::Args().set_now(21)));
|
||||
expect_code(
|
||||
"B sends unsigned Promise(1000000, 0)", no_promise_signature,
|
||||
channel.write().send_external_message(
|
||||
MsgCloseBuilder()
|
||||
.signed_promise(SignedPromiseBuilder().promise_A(1000000).channel_id(config.channel_id).finalize())
|
||||
.with_b_key(&b_pkey)
|
||||
.finalize(),
|
||||
ton::SmartContract::Args().set_now(21)));
|
||||
|
||||
expect_ok(
|
||||
"B sends Promise(1000000, 0) signed by A",
|
||||
channel.write().send_external_message(
|
||||
MsgCloseBuilder()
|
||||
.signed_promise(
|
||||
SignedPromiseBuilder().promise_A(1000000).with_key(&a_pkey).channel_id(config.channel_id).finalize())
|
||||
.with_b_key(&b_pkey)
|
||||
.finalize(),
|
||||
ton::SmartContract::Args().set_now(21)));
|
||||
ValidateStateClose(channel->get_state().data)
|
||||
.expect_A(1000)
|
||||
.expect_B(2000)
|
||||
.expect_promise_A(1000000)
|
||||
.expect_promise_B(0)
|
||||
.expect_signed_A(false)
|
||||
.expect_signed_B(true)
|
||||
.expect_expire_at(21 + config.close_timeout)
|
||||
.finish()
|
||||
.ensure();
|
||||
|
||||
expect_ok("B sends Promise(0, 1000000 + 10) signed by A",
|
||||
channel.write().send_external_message(MsgCloseBuilder()
|
||||
.signed_promise(SignedPromiseBuilder()
|
||||
.promise_B(1000000 + 10)
|
||||
.with_key(&b_pkey)
|
||||
.channel_id(config.channel_id)
|
||||
.finalize())
|
||||
.with_a_key(&a_pkey)
|
||||
.finalize(),
|
||||
ton::SmartContract::Args().set_now(21)));
|
||||
ValidateStatePayout(channel->get_state().data).expect_A(1000 + 10).expect_B(2000 - 10).finish().ensure();
|
||||
#undef expect_ok
|
||||
#undef expect_code
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "vm/cells/CellSlice.h"
|
||||
#include "vm/excno.hpp"
|
||||
#include "td/utils/bits.h"
|
||||
#include "td/utils/misc.h"
|
||||
|
||||
namespace vm {
|
||||
|
||||
@ -719,6 +720,10 @@ bool CellSlice::prefetch_bytes(unsigned char* buffer, unsigned bytes) const {
|
||||
}
|
||||
}
|
||||
|
||||
bool CellSlice::fetch_bytes(td::MutableSlice slice) {
|
||||
return fetch_bytes(slice.ubegin(), td::narrow_cast<unsigned>(slice.size()));
|
||||
}
|
||||
|
||||
bool CellSlice::fetch_bytes(unsigned char* buffer, unsigned bytes) {
|
||||
if (prefetch_bytes(buffer, bytes)) {
|
||||
advance(bytes * 8);
|
||||
@ -728,6 +733,10 @@ bool CellSlice::fetch_bytes(unsigned char* buffer, unsigned bytes) {
|
||||
}
|
||||
}
|
||||
|
||||
bool CellSlice::prefetch_bytes(td::MutableSlice slice) const {
|
||||
return prefetch_bytes(slice.ubegin(), td::narrow_cast<unsigned>(slice.size()));
|
||||
}
|
||||
|
||||
Ref<Cell> CellSlice::prefetch_ref(unsigned offset) const {
|
||||
if (offset < size_refs()) {
|
||||
auto ref_id = refs_st + offset;
|
||||
|
@ -218,7 +218,9 @@ class CellSlice : public td::CntObject {
|
||||
return prefetch_bits_to(buffer.bits(), n);
|
||||
}
|
||||
bool fetch_bytes(unsigned char* buffer, unsigned bytes);
|
||||
bool fetch_bytes(td::MutableSlice slice);
|
||||
bool prefetch_bytes(unsigned char* buffer, unsigned bytes) const;
|
||||
bool prefetch_bytes(td::MutableSlice slice) const;
|
||||
td::BitSlice as_bitslice() const {
|
||||
return prefetch_bits(size());
|
||||
}
|
||||
|
@ -148,6 +148,11 @@ class MerkleProofCombineFast {
|
||||
MerkleProofCombineFast(Ref<Cell> a, Ref<Cell> b) : a_(std::move(a)), b_(std::move(b)) {
|
||||
}
|
||||
td::Result<Ref<Cell>> run() {
|
||||
if (a_.is_null()) {
|
||||
return b_;
|
||||
} else if (b_.is_null()) {
|
||||
return a_;
|
||||
}
|
||||
TRY_RESULT_ASSIGN(a_, unpack_proof(a_));
|
||||
TRY_RESULT_ASSIGN(b_, unpack_proof(b_));
|
||||
TRY_RESULT(res, run_raw());
|
||||
@ -204,6 +209,11 @@ class MerkleProofCombine {
|
||||
MerkleProofCombine(Ref<Cell> a, Ref<Cell> b) : a_(std::move(a)), b_(std::move(b)) {
|
||||
}
|
||||
td::Result<Ref<Cell>> run() {
|
||||
if (a_.is_null()) {
|
||||
return b_;
|
||||
} else if (b_.is_null()) {
|
||||
return a_;
|
||||
}
|
||||
TRY_RESULT_ASSIGN(a_, unpack_proof(a_));
|
||||
TRY_RESULT_ASSIGN(b_, unpack_proof(b_));
|
||||
TRY_RESULT(res, run_raw());
|
||||
@ -323,6 +333,10 @@ Ref<Cell> MerkleProof::combine(Ref<Cell> a, Ref<Cell> b) {
|
||||
return res.move_as_ok();
|
||||
}
|
||||
|
||||
td::Result<Ref<Cell>> MerkleProof::combine_status(Ref<Cell> a, Ref<Cell> b) {
|
||||
return MerkleProofCombine(std::move(a), std::move(b)).run();
|
||||
}
|
||||
|
||||
Ref<Cell> MerkleProof::combine_fast(Ref<Cell> a, Ref<Cell> b) {
|
||||
auto res = MerkleProofCombineFast(std::move(a), std::move(b)).run();
|
||||
if (res.is_error()) {
|
||||
@ -331,6 +345,10 @@ Ref<Cell> MerkleProof::combine_fast(Ref<Cell> a, Ref<Cell> b) {
|
||||
return res.move_as_ok();
|
||||
}
|
||||
|
||||
td::Result<Ref<Cell>> MerkleProof::combine_fast_status(Ref<Cell> a, Ref<Cell> b) {
|
||||
return MerkleProofCombineFast(std::move(a), std::move(b)).run();
|
||||
}
|
||||
|
||||
Ref<Cell> MerkleProof::combine_raw(Ref<Cell> a, Ref<Cell> b) {
|
||||
auto res = MerkleProofCombine(std::move(a), std::move(b)).run_raw();
|
||||
if (res.is_error()) {
|
||||
|
@ -38,7 +38,9 @@ class MerkleProof {
|
||||
static Ref<Cell> virtualize(Ref<Cell> cell, int virtualization);
|
||||
|
||||
static Ref<Cell> combine(Ref<Cell> a, Ref<Cell> b);
|
||||
static td::Result<Ref<Cell>> combine_status(Ref<Cell> a, Ref<Cell> b);
|
||||
static Ref<Cell> combine_fast(Ref<Cell> a, Ref<Cell> b);
|
||||
static td::Result<Ref<Cell>> combine_fast_status(Ref<Cell> a, Ref<Cell> b);
|
||||
|
||||
// works with upwrapped proofs
|
||||
// works fine with cell of non-zero level, but this is not supported (yet?) in MerkeProof special cell
|
||||
|
@ -255,15 +255,15 @@ TonDbTransactionImpl::TonDbTransactionImpl(std::shared_ptr<KeyValue> kv) : kv_(s
|
||||
}
|
||||
|
||||
void TonDbTransactionImpl::begin() {
|
||||
kv_->begin_transaction();
|
||||
kv_->begin_write_batch();
|
||||
generation_++;
|
||||
}
|
||||
void TonDbTransactionImpl::commit() {
|
||||
kv_->commit_transaction();
|
||||
kv_->commit_write_batch();
|
||||
reader_.reset(kv_->snapshot().release());
|
||||
}
|
||||
void TonDbTransactionImpl::abort() {
|
||||
kv_->abort_transaction();
|
||||
kv_->abort_write_batch();
|
||||
}
|
||||
void TonDbTransactionImpl::clear_cache() {
|
||||
contracts_ = {};
|
||||
|
@ -77,6 +77,13 @@ class VmError {
|
||||
long long get_arg() const {
|
||||
return arg;
|
||||
}
|
||||
td::Status as_status() const {
|
||||
return td::Status::Error(td::Slice{get_msg()});
|
||||
}
|
||||
template <typename T>
|
||||
td::Status as_status(T pfx) const {
|
||||
return td::Status::Error(PSLICE() << pfx << get_msg());
|
||||
}
|
||||
};
|
||||
|
||||
struct VmNoGas {
|
||||
@ -90,6 +97,13 @@ struct VmNoGas {
|
||||
operator VmError() const {
|
||||
return VmError{Excno::out_of_gas, "out of gas"};
|
||||
}
|
||||
td::Status as_status() const {
|
||||
return td::Status::Error(td::Slice{get_msg()});
|
||||
}
|
||||
template <typename T>
|
||||
td::Status as_status(T pfx) const {
|
||||
return td::Status::Error(PSLICE() << pfx << get_msg());
|
||||
}
|
||||
};
|
||||
|
||||
struct VmVirtError {
|
||||
@ -106,6 +120,13 @@ struct VmVirtError {
|
||||
operator VmError() const {
|
||||
return VmError{Excno::virt_err, "prunned branch", virtualization};
|
||||
}
|
||||
td::Status as_status() const {
|
||||
return td::Status::Error(td::Slice{get_msg()});
|
||||
}
|
||||
template <typename T>
|
||||
td::Status as_status(T pfx) const {
|
||||
return td::Status::Error(PSLICE() << pfx << get_msg());
|
||||
}
|
||||
};
|
||||
|
||||
struct VmFatal {};
|
||||
@ -114,12 +135,12 @@ template <class F>
|
||||
auto try_f(F&& f) noexcept -> decltype(f()) {
|
||||
try {
|
||||
return f();
|
||||
} catch (vm::VmError error) {
|
||||
return td::Status::Error(PSLICE() << "Got a vm exception: " << error.get_msg());
|
||||
} catch (vm::VmVirtError error) {
|
||||
return td::Status::Error(PSLICE() << "Got a vm virtualization exception: " << error.get_msg());
|
||||
} catch (vm::VmNoGas error) {
|
||||
return td::Status::Error(PSLICE() << "Got a vm no gas exception: " << error.get_msg());
|
||||
} catch (vm::VmError& error) {
|
||||
return error.as_status("Got a vm exception: ");
|
||||
} catch (vm::VmVirtError& error) {
|
||||
return error.as_status("Got a vm virtualization exception: ");
|
||||
} catch (vm::VmNoGas& error) {
|
||||
return error.as_status("Got a vm no gas exception: ");
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -33,6 +33,7 @@
|
||||
#include "vm/cells.h"
|
||||
#include "vm/stack.hpp"
|
||||
#include "block/block.h"
|
||||
#include "block/mc-config.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
|
||||
using td::Ref;
|
||||
@ -89,6 +90,9 @@ class TestNode : public td::actor::Actor {
|
||||
|
||||
std::unique_ptr<ton::adnl::AdnlExtClient::Callback> make_callback();
|
||||
|
||||
using creator_stats_func_t =
|
||||
std::function<bool(const td::Bits256&, const block::DiscountedCounter&, const block::DiscountedCounter&)>;
|
||||
|
||||
struct TransId {
|
||||
ton::Bits256 acc_addr;
|
||||
ton::LogicalTime trans_lt;
|
||||
@ -98,6 +102,71 @@ class TestNode : public td::actor::Actor {
|
||||
}
|
||||
};
|
||||
|
||||
struct BlockHdrInfo {
|
||||
ton::BlockIdExt blk_id;
|
||||
Ref<vm::Cell> proof, virt_blk_root;
|
||||
int mode;
|
||||
BlockHdrInfo() : mode(-1) {
|
||||
}
|
||||
BlockHdrInfo(const ton::BlockIdExt blk_id_, Ref<vm::Cell> proof_, Ref<vm::Cell> vroot_, int mode_)
|
||||
: blk_id(blk_id_), proof(std::move(proof_)), virt_blk_root(std::move(vroot_)), mode(mode_) {
|
||||
}
|
||||
};
|
||||
|
||||
struct ConfigInfo {
|
||||
std::unique_ptr<block::Config> config;
|
||||
Ref<vm::Cell> state_proof, config_proof;
|
||||
ConfigInfo() = default;
|
||||
ConfigInfo(std::unique_ptr<block::Config> config_, Ref<vm::Cell> state_proof_, Ref<vm::Cell> config_proof_)
|
||||
: config(std::move(config_)), state_proof(std::move(state_proof_)), config_proof(std::move(config_proof_)) {
|
||||
}
|
||||
};
|
||||
|
||||
struct CreatorStatsRes {
|
||||
int mode;
|
||||
bool complete{false};
|
||||
td::Bits256 last_key;
|
||||
Ref<vm::Cell> state_proof, data_proof;
|
||||
CreatorStatsRes(int mode_ = 0) : mode(mode_) {
|
||||
last_key.set_zero();
|
||||
}
|
||||
CreatorStatsRes(int mode_, const td::Bits256& key_, Ref<vm::Cell> st_proof_ = {}, Ref<vm::Cell> dproof_ = {})
|
||||
: mode(mode_), last_key(key_), state_proof(std::move(st_proof_)), data_proof(std::move(dproof_)) {
|
||||
}
|
||||
};
|
||||
|
||||
struct ValidatorLoadInfo {
|
||||
ton::BlockIdExt blk_id;
|
||||
Ref<vm::Cell> state_proof, data_proof, virt_root;
|
||||
std::unique_ptr<block::Config> config;
|
||||
ton::UnixTime block_created_at{0};
|
||||
ton::UnixTime valid_since{0};
|
||||
ton::LogicalTime end_lt{0};
|
||||
std::unique_ptr<block::ValidatorSet> vset;
|
||||
std::map<ton::Bits256, int> vset_map;
|
||||
std::pair<td::int64, td::int64> created_total;
|
||||
std::vector<std::pair<td::int64, td::int64>> created;
|
||||
ValidatorLoadInfo(ton::BlockIdExt blkid, Ref<vm::Cell> root, Ref<vm::Cell> root2,
|
||||
std::unique_ptr<block::Config> cfg = {})
|
||||
: blk_id(blkid)
|
||||
, state_proof(std::move(root))
|
||||
, data_proof(std::move(root2))
|
||||
, config(std::move(cfg))
|
||||
, valid_since(0) {
|
||||
}
|
||||
bool unpack_vset();
|
||||
bool store_record(const td::Bits256& key, const block::DiscountedCounter& mc_cnt,
|
||||
const block::DiscountedCounter& shard_cnt);
|
||||
bool has_data() const {
|
||||
return blk_id.is_masterchain_ext() && state_proof.not_null() && data_proof.not_null() && config;
|
||||
}
|
||||
td::Status check_header_proof(ton::UnixTime* save_utime = nullptr, ton::LogicalTime* save_lt = nullptr) const;
|
||||
td::Result<Ref<vm::Cell>> build_proof(int idx, td::Bits256* save_pubkey = nullptr) const;
|
||||
td::Result<Ref<vm::Cell>> build_producer_info(int idx, td::Bits256* save_pubkey = nullptr) const;
|
||||
td::Status init_check_proofs();
|
||||
static td::Result<std::unique_ptr<ValidatorLoadInfo>> preinit_from_producer_info(Ref<vm::Cell> prod_info);
|
||||
};
|
||||
|
||||
void run_init_queries();
|
||||
char cur() const {
|
||||
return *parse_ptr_;
|
||||
@ -144,18 +213,24 @@ class TestNode : public td::actor::Actor {
|
||||
bool show_dns_record(std::ostream& os, int cat, Ref<vm::Cell> value, bool raw_dump);
|
||||
bool get_all_shards(std::string filename = "", bool use_last = true, ton::BlockIdExt blkid = {});
|
||||
void got_all_shards(ton::BlockIdExt blk, td::BufferSlice proof, td::BufferSlice data, std::string filename);
|
||||
bool get_config_params(ton::BlockIdExt blkid, td::Promise<td::Unit> do_after, int mode = 0, std::string filename = "",
|
||||
bool parse_get_config_params(ton::BlockIdExt blkid, int mode = 0, std::string filename = "",
|
||||
std::vector<int> params = {});
|
||||
void got_config_params(ton::BlockIdExt req_blkid, ton::BlockIdExt blkid, td::BufferSlice state_proof,
|
||||
td::BufferSlice cfg_proof, int mode, std::string filename, std::vector<int> params,
|
||||
td::Promise<td::Unit> do_after);
|
||||
bool get_config_params(ton::BlockIdExt blkid, td::Promise<std::unique_ptr<block::Config>> promise, int mode = 0,
|
||||
std::string filename = "", std::vector<int> params = {});
|
||||
bool get_config_params_ext(ton::BlockIdExt blkid, td::Promise<ConfigInfo> promise, int mode = 0,
|
||||
std::string filename = "", std::vector<int> params = {});
|
||||
void got_config_params(ton::BlockIdExt req_blkid, int mode, std::string filename, std::vector<int> params,
|
||||
td::Result<td::BufferSlice> R, td::Promise<ConfigInfo> promise);
|
||||
bool get_block(ton::BlockIdExt blk, bool dump = false);
|
||||
void got_block(ton::BlockIdExt blkid, td::BufferSlice data, bool dump);
|
||||
bool get_state(ton::BlockIdExt blk, bool dump = false);
|
||||
void got_state(ton::BlockIdExt blkid, ton::RootHash root_hash, ton::FileHash file_hash, td::BufferSlice data,
|
||||
bool dump);
|
||||
bool get_block_header(ton::BlockIdExt blk, int mode);
|
||||
bool lookup_block(ton::ShardIdFull shard, int mode, td::uint64 arg);
|
||||
bool get_show_block_header(ton::BlockIdExt blk, int mode);
|
||||
bool get_block_header(ton::BlockIdExt blk, int mode, td::Promise<BlockHdrInfo> promise);
|
||||
bool lookup_show_block(ton::ShardIdFull shard, int mode, td::uint64 arg);
|
||||
bool lookup_block(ton::ShardIdFull shard, int mode, td::uint64 arg, td::Promise<BlockHdrInfo>);
|
||||
void got_block_header_raw(td::BufferSlice res, td::Promise<BlockHdrInfo> promise, ton::BlockIdExt req_blkid = {});
|
||||
void got_block_header(ton::BlockIdExt blkid, td::BufferSlice data, int mode);
|
||||
bool show_block_header(ton::BlockIdExt blkid, Ref<vm::Cell> root, int mode);
|
||||
bool show_state_header(ton::BlockIdExt blkid, Ref<vm::Cell> root, int mode);
|
||||
@ -177,9 +252,28 @@ class TestNode : public td::actor::Actor {
|
||||
void got_block_proof(ton::BlockIdExt from, ton::BlockIdExt to, int mode, td::BufferSlice res);
|
||||
bool get_creator_stats(ton::BlockIdExt blkid, int mode, unsigned req_count, ton::Bits256 start_after,
|
||||
ton::UnixTime min_utime);
|
||||
void got_creator_stats(ton::BlockIdExt req_blkid, ton::BlockIdExt blkid, int req_mode, int mode,
|
||||
td::Bits256 start_after, ton::UnixTime min_utime, td::BufferSlice state_proof,
|
||||
td::BufferSlice data_proof, int count, int req_count, bool complete);
|
||||
bool get_creator_stats(ton::BlockIdExt blkid, int mode, unsigned req_count, ton::Bits256 start_after,
|
||||
ton::UnixTime min_utime, creator_stats_func_t func, td::Promise<td::Bits256> promise);
|
||||
bool get_creator_stats(ton::BlockIdExt blkid, unsigned req_count, ton::UnixTime min_utime, creator_stats_func_t func,
|
||||
std::unique_ptr<CreatorStatsRes> state, td::Promise<std::unique_ptr<CreatorStatsRes>> promise);
|
||||
void got_creator_stats(ton::BlockIdExt req_blkid, ton::BlockIdExt blkid, int mode, ton::UnixTime min_utime,
|
||||
td::BufferSlice state_proof, td::BufferSlice data_proof, int count, int req_count,
|
||||
bool complete, creator_stats_func_t func, std::unique_ptr<CreatorStatsRes> state,
|
||||
td::Promise<std::unique_ptr<CreatorStatsRes>> promise);
|
||||
bool check_validator_load(int start_time, int end_time, int mode = 0, std::string file_pfx = "");
|
||||
void continue_check_validator_load(ton::BlockIdExt blkid1, Ref<vm::Cell> root1, ton::BlockIdExt blkid2,
|
||||
Ref<vm::Cell> root2, int mode = 0, std::string file_pfx = "");
|
||||
void continue_check_validator_load2(std::unique_ptr<ValidatorLoadInfo> info1,
|
||||
std::unique_ptr<ValidatorLoadInfo> info2, int mode = 0,
|
||||
std::string file_pfx = "");
|
||||
void continue_check_validator_load3(std::unique_ptr<ValidatorLoadInfo> info1,
|
||||
std::unique_ptr<ValidatorLoadInfo> info2, int mode = 0,
|
||||
std::string file_pfx = "");
|
||||
td::Status write_val_create_proof(ValidatorLoadInfo& info1, ValidatorLoadInfo& info2, int idx, bool severe,
|
||||
std::string file_pfx, int cnt);
|
||||
bool load_creator_stats(std::unique_ptr<ValidatorLoadInfo> load_to,
|
||||
td::Promise<std::unique_ptr<ValidatorLoadInfo>> promise, bool need_proofs);
|
||||
td::Status check_validator_load_proof(std::string filename);
|
||||
bool cache_cell(Ref<vm::Cell> cell);
|
||||
bool list_cached_cells() const;
|
||||
bool dump_cached_cell(td::Slice hash_pfx, td::Slice type_name = {});
|
||||
@ -222,6 +316,17 @@ class TestNode : public td::actor::Actor {
|
||||
bool show_new_blkids(bool all = false);
|
||||
bool complete_blkid(ton::BlockId partial_blkid, ton::BlockIdExt& complete_blkid) const;
|
||||
td::Promise<td::Unit> trivial_promise();
|
||||
template <typename T>
|
||||
td::Promise<T> trivial_promise_of() {
|
||||
return td::PromiseCreator::lambda([Self = actor_id(this)](td::Result<T> res) {
|
||||
if (res.is_error()) {
|
||||
LOG(ERROR) << "error: " << res.move_as_error();
|
||||
}
|
||||
});
|
||||
}
|
||||
static ton::UnixTime now() {
|
||||
return static_cast<td::uint32>(td::Clocks::system());
|
||||
}
|
||||
static const tlb::TypenameLookup& get_tlb_dict();
|
||||
|
||||
public:
|
||||
@ -292,7 +397,8 @@ class TestNode : public td::actor::Actor {
|
||||
//td::actor::SchedulerContext::get()->stop();
|
||||
}
|
||||
|
||||
void got_result();
|
||||
void got_result(td::Result<td::BufferSlice> R, td::Promise<td::BufferSlice> promise);
|
||||
void after_got_result(bool ok);
|
||||
bool envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise);
|
||||
void parse_line(td::BufferSlice data);
|
||||
|
||||
|
@ -44,8 +44,24 @@ class GetArg<R (C::*)(Arg) const> {
|
||||
using type = Arg;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetRet : public GetRet<decltype(&T::operator())> {};
|
||||
|
||||
template <class C, class R, class... Arg>
|
||||
class GetRet<R (C::*)(Arg...)> {
|
||||
public:
|
||||
using type = R;
|
||||
};
|
||||
template <class C, class R, class... Arg>
|
||||
class GetRet<R (C::*)(Arg...) const> {
|
||||
public:
|
||||
using type = R;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using get_arg_t = std::decay_t<typename GetArg<T>::type>;
|
||||
template <class T>
|
||||
using get_ret_t = std::decay_t<typename GetRet<T>::type>;
|
||||
|
||||
template <class T>
|
||||
struct DropResult {
|
||||
@ -131,6 +147,7 @@ constexpr bool is_promise_interface_ptr() {
|
||||
template <class ValueT, class FunctionT>
|
||||
class LambdaPromise : public PromiseInterface<ValueT> {
|
||||
public:
|
||||
using ArgT = ValueT;
|
||||
void set_value(ValueT &&value) override {
|
||||
CHECK(has_lambda_.get());
|
||||
do_ok(std::move(value));
|
||||
@ -288,12 +305,6 @@ class Promise {
|
||||
std::unique_ptr<PromiseInterface<T>> promise_;
|
||||
};
|
||||
|
||||
template <class F>
|
||||
auto make_promise(F &&f) {
|
||||
using ValueT = detail::drop_result_t<detail::get_arg_t<F>>;
|
||||
return Promise<ValueT>(promise_interface_ptr(std::forward<F>(f)));
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <class... ArgsT>
|
||||
class JoinPromise : public PromiseInterface<Unit> {
|
||||
@ -331,6 +342,16 @@ class PromiseCreator {
|
||||
}
|
||||
};
|
||||
|
||||
template <class F>
|
||||
auto make_promise(F &&f) {
|
||||
using ValueT = typename decltype(PromiseCreator::lambda(std::move(f)))::ArgT;
|
||||
return Promise<ValueT>(PromiseCreator::lambda(std::move(f)));
|
||||
}
|
||||
template <class T>
|
||||
auto make_promise(Promise<T> &&f) {
|
||||
return std::move(f);
|
||||
}
|
||||
|
||||
template <class T = Unit>
|
||||
class SafePromise {
|
||||
public:
|
||||
@ -356,4 +377,145 @@ class SafePromise {
|
||||
Promise<T> promise_;
|
||||
Result<T> result_;
|
||||
};
|
||||
|
||||
template <class PromiseT, typename... ArgsT>
|
||||
class PromiseMerger;
|
||||
|
||||
template <class F>
|
||||
struct SplitPromise {
|
||||
using PromiseT = decltype(make_promise(std::declval<F>()));
|
||||
using ArgT = typename PromiseT::ArgT;
|
||||
|
||||
template <class S, class T>
|
||||
static std::pair<Promise<S>, Promise<T>> split(std::pair<S, T>);
|
||||
template <class... ArgsT>
|
||||
static std::tuple<Promise<ArgsT>...> split(std::tuple<ArgsT...>);
|
||||
using SplittedT = decltype(split(std::declval<ArgT>()));
|
||||
|
||||
template <class S, class T>
|
||||
static PromiseMerger<PromiseT, S, T> merger(std::pair<S, T>);
|
||||
template <class... ArgsT>
|
||||
static PromiseMerger<PromiseT, ArgsT...> merger(std::tuple<ArgsT...>);
|
||||
using MergerT = decltype(merger(std::declval<ArgT>()));
|
||||
};
|
||||
|
||||
template <class PromiseT, typename... ArgsT>
|
||||
class PromiseMerger : public std::enable_shared_from_this<PromiseMerger<PromiseT, ArgsT...>> {
|
||||
public:
|
||||
std::tuple<Result<ArgsT>...> args_;
|
||||
PromiseT promise_;
|
||||
|
||||
PromiseMerger(PromiseT promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
~PromiseMerger() {
|
||||
td::Status status;
|
||||
tuple_for_each(args_, [&status](auto &&arg) {
|
||||
if (status.is_error()) {
|
||||
return;
|
||||
}
|
||||
if (arg.is_error()) {
|
||||
status = arg.move_as_error();
|
||||
}
|
||||
});
|
||||
if (status.is_error()) {
|
||||
promise_.set_error(std::move(status));
|
||||
return;
|
||||
}
|
||||
call_tuple([this](auto &&... args) { promise_.set_value({args.move_as_ok()...}); }, std::move(args_));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Promise<typename T::ValueT> make_promise(T &arg) {
|
||||
return [&arg, self = this->shared_from_this()](auto res) { arg = std::move(res); };
|
||||
}
|
||||
|
||||
template <class R>
|
||||
auto split() {
|
||||
return call_tuple([this](auto &&... arg) { return R{this->make_promise(arg)...}; }, std::move(args_));
|
||||
}
|
||||
};
|
||||
|
||||
template <class F>
|
||||
auto split_promise(F &&f) {
|
||||
auto merger = std::make_shared<typename SplitPromise<F>::MergerT>(std::move(f));
|
||||
return merger->template split<typename SplitPromise<F>::SplittedT>();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct PromiseFuture {
|
||||
Result<Promise<T>> promise_;
|
||||
Result<T> result_;
|
||||
~PromiseFuture() {
|
||||
if (promise_.is_ok()) {
|
||||
promise_.move_as_ok().set_result(std::move(result_));
|
||||
} else {
|
||||
LOG(ERROR) << "Lost PromiseFuture";
|
||||
}
|
||||
}
|
||||
};
|
||||
template <class T>
|
||||
struct Future;
|
||||
|
||||
template <class T>
|
||||
std::pair<Promise<T>, Future<T>> make_promise_future();
|
||||
|
||||
template <class T>
|
||||
struct Future {
|
||||
Promise<Promise<T>> promise_;
|
||||
Future(Promise<Promise<T>> promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void finish(Promise<T> promise) {
|
||||
promise_.set_value(std::move(promise));
|
||||
}
|
||||
|
||||
template <class F>
|
||||
auto map(F &&f) {
|
||||
using R = detail::drop_result_t<decltype(f(std::declval<T>()))>;
|
||||
auto pf = make_promise_future<R>();
|
||||
promise_.set_value([p = std::move(pf.first), f = std::move(f)](Result<T> res) mutable {
|
||||
TRY_RESULT_PROMISE(p, x, std::move(res));
|
||||
p.set_result(f(std::move(x)));
|
||||
});
|
||||
|
||||
return std::move(pf.second);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
auto fmap(F &&f) {
|
||||
return flatten(map(std::move(f)));
|
||||
}
|
||||
|
||||
template <class X>
|
||||
static Future<X> flatten(Future<Future<X>> ff) {
|
||||
auto pf = make_promise_future<X>();
|
||||
ff.promise_.set_value([p = std::move(pf.first)](Result<Future<X>> r_f) mutable {
|
||||
TRY_RESULT_PROMISE(p, f, std::move(r_f));
|
||||
// Promise<X> p
|
||||
// Future<X> f
|
||||
f.promise_.set_value(std::move(p));
|
||||
});
|
||||
return std::move(pf.second);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
Future<T> make_future(T &&value) {
|
||||
return Future<T>([value = std::move(value)](Result<Promise<T>> r_promise) mutable {
|
||||
if (r_promise.is_ok()) {
|
||||
r_promise.move_as_ok().set_value(std::move(value));
|
||||
} else {
|
||||
LOG(ERROR) << "Lost future";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::pair<Promise<T>, Future<T>> make_promise_future() {
|
||||
auto pf = std::make_shared<PromiseFuture<T>>();
|
||||
Future<T> future([pf](Result<Promise<T>> res) mutable { pf->promise_ = std::move(res); });
|
||||
Promise<T> promise = [pf = std::move(pf)](Result<T> res) mutable { pf->result_ = std::move(res); };
|
||||
return std::make_pair(std::move(promise), std::move(future));
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -100,6 +100,28 @@ void send_closure(ActorIdT &&actor_id, FunctionT function, ArgsT &&... args) {
|
||||
|
||||
#endif
|
||||
|
||||
template <class ActorIdT, class FunctionT, class... ArgsT, class FunctionClassT = member_function_class_t<FunctionT>,
|
||||
size_t argument_count = member_function_argument_count<FunctionT>(),
|
||||
std::enable_if_t<argument_count == sizeof...(ArgsT), bool> with_promise = false>
|
||||
auto future_send_closure(ActorIdT &&actor_id, FunctionT function, ArgsT &&... args) {
|
||||
using R = ::td::detail::get_ret_t<std::decay_t<FunctionT>>;
|
||||
auto pf = make_promise_future<R>();
|
||||
send_closure(std::forward<ActorIdT>(actor_id), std::move(function), std::forward<ArgsT>(args)...,
|
||||
std::move(pf.first));
|
||||
return std::move(pf.second);
|
||||
}
|
||||
|
||||
template <class R, class ActorIdT, class FunctionT, class... ArgsT,
|
||||
class FunctionClassT = member_function_class_t<FunctionT>,
|
||||
size_t argument_count = member_function_argument_count<FunctionT>(),
|
||||
std::enable_if_t<argument_count != sizeof...(ArgsT), bool> with_promise = true>
|
||||
Future<R> future_send_closure(ActorIdT &&actor_id, FunctionT function, ArgsT &&... args) {
|
||||
auto pf = make_promise_future<R>();
|
||||
send_closure(std::forward<ActorIdT>(actor_id), std::move(function), std::forward<ArgsT>(args)...,
|
||||
std::move(pf.first));
|
||||
return std::move(pf.second);
|
||||
}
|
||||
|
||||
template <typename ActorIdT, typename FunctionT, typename... ArgsT>
|
||||
bool send_closure_bool(ActorIdT &&actor_id, FunctionT function, ArgsT &&... args) {
|
||||
send_closure(std::forward<ActorIdT>(actor_id), function, std::forward<ArgsT>(args)...);
|
||||
|
@ -63,6 +63,36 @@ class ActorSignals {
|
||||
using core::Actor;
|
||||
using core::SchedulerContext;
|
||||
using core::SchedulerId;
|
||||
using core::set_debug;
|
||||
|
||||
struct Debug {
|
||||
public:
|
||||
Debug() = default;
|
||||
Debug(std::shared_ptr<core::SchedulerGroupInfo> group_info) : group_info_(std::move(group_info)) {
|
||||
}
|
||||
template <class F>
|
||||
void for_each(F &&f) {
|
||||
for (auto &scheduler : group_info_->schedulers) {
|
||||
f(scheduler.io_worker->debug);
|
||||
for (auto &cpu : scheduler.cpu_workers) {
|
||||
f(cpu->debug);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dump() {
|
||||
for_each([](core::Debug &debug) {
|
||||
core::DebugInfo info;
|
||||
debug.read(info);
|
||||
if (info.is_active) {
|
||||
LOG(ERROR) << info.name << " " << td::format::as_time(Time::now() - info.start_at);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<core::SchedulerGroupInfo> group_info_;
|
||||
};
|
||||
|
||||
class Scheduler {
|
||||
public:
|
||||
@ -110,6 +140,10 @@ class Scheduler {
|
||||
}
|
||||
}
|
||||
|
||||
Debug get_debug() {
|
||||
return Debug{group_info_};
|
||||
}
|
||||
|
||||
bool run() {
|
||||
start();
|
||||
while (schedulers_[0]->run(10)) {
|
||||
|
@ -32,6 +32,7 @@ void CpuWorker::run() {
|
||||
|
||||
MpmcWaiter::Slot slot;
|
||||
waiter_.init_slot(slot, thread_id);
|
||||
auto &debug = dispatcher.get_debug();
|
||||
while (true) {
|
||||
SchedulerMessage message;
|
||||
if (try_pop(message, thread_id)) {
|
||||
@ -39,6 +40,7 @@ void CpuWorker::run() {
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
auto lock = debug.start(message->get_name());
|
||||
ActorExecutor executor(*message, dispatcher, ActorExecutor::Options().with_from_queue());
|
||||
} else {
|
||||
waiter_.wait(slot);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "td/actor/core/IoWorker.h"
|
||||
|
||||
#include "td/actor/core/ActorExecutor.h"
|
||||
#include "td/actor/core/Scheduler.h"
|
||||
|
||||
namespace td {
|
||||
namespace actor {
|
||||
@ -42,6 +43,7 @@ bool IoWorker::run_once(double timeout) {
|
||||
auto &poll = SchedulerContext::get()->get_poll();
|
||||
#endif
|
||||
auto &heap = SchedulerContext::get()->get_heap();
|
||||
auto &debug = SchedulerContext::get()->get_debug();
|
||||
|
||||
auto now = Time::now(); // update Time::now_cached()
|
||||
while (!heap.empty() && heap.top_key() <= now) {
|
||||
@ -49,6 +51,7 @@ bool IoWorker::run_once(double timeout) {
|
||||
auto *actor_info = ActorInfo::from_heap_node(heap_node);
|
||||
|
||||
auto id = actor_info->unpin();
|
||||
auto lock = debug.start(actor_info->get_name());
|
||||
ActorExecutor executor(*actor_info, dispatcher, ActorExecutor::Options().with_has_poll(true));
|
||||
if (executor.can_send_immediate()) {
|
||||
executor.send_immediate(ActorSignals::one(ActorSignals::Alarm));
|
||||
@ -68,6 +71,7 @@ bool IoWorker::run_once(double timeout) {
|
||||
dispatcher.set_alarm_timestamp(message);
|
||||
continue;
|
||||
}
|
||||
auto lock = debug.start(message->get_name());
|
||||
ActorExecutor executor(*message, dispatcher, ActorExecutor::Options().with_from_queue().with_has_poll(true));
|
||||
}
|
||||
queue_.reader_flush();
|
||||
|
@ -25,6 +25,15 @@ namespace td {
|
||||
namespace actor {
|
||||
namespace core {
|
||||
|
||||
std::atomic<bool> debug;
|
||||
void set_debug(bool flag) {
|
||||
debug = flag;
|
||||
}
|
||||
|
||||
bool need_debug() {
|
||||
return debug.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
Scheduler::Scheduler(std::shared_ptr<SchedulerGroupInfo> scheduler_group_info, SchedulerId id, size_t cpu_threads_count)
|
||||
: scheduler_group_info_(std::move(scheduler_group_info)), cpu_threads_(cpu_threads_count) {
|
||||
scheduler_group_info_->active_scheduler_count++;
|
||||
@ -128,13 +137,14 @@ void Scheduler::do_stop() {
|
||||
}
|
||||
|
||||
Scheduler::ContextImpl::ContextImpl(ActorInfoCreator *creator, SchedulerId scheduler_id, CpuWorkerId cpu_worker_id,
|
||||
SchedulerGroupInfo *scheduler_group, Poll *poll, KHeap<double> *heap)
|
||||
SchedulerGroupInfo *scheduler_group, Poll *poll, KHeap<double> *heap, Debug *debug)
|
||||
: creator_(creator)
|
||||
, scheduler_id_(scheduler_id)
|
||||
, cpu_worker_id_(cpu_worker_id)
|
||||
, scheduler_group_(scheduler_group)
|
||||
, poll_(poll)
|
||||
, heap_(heap) {
|
||||
, heap_(heap)
|
||||
, debug_(debug) {
|
||||
}
|
||||
|
||||
SchedulerId Scheduler::ContextImpl::get_scheduler_id() const {
|
||||
@ -184,6 +194,9 @@ KHeap<double> &Scheduler::ContextImpl::get_heap() {
|
||||
CHECK(has_heap());
|
||||
return *heap_;
|
||||
}
|
||||
Debug &Scheduler::ContextImpl::get_debug() {
|
||||
return *debug_;
|
||||
}
|
||||
|
||||
void Scheduler::ContextImpl::set_alarm_timestamp(const ActorInfoPtr &actor_info_ptr) {
|
||||
// Ideas for optimization
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "td/actor/core/SchedulerId.h"
|
||||
#include "td/actor/core/SchedulerMessage.h"
|
||||
|
||||
#include "td/utils/AtomicRead.h"
|
||||
#include "td/utils/Closure.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/format.h"
|
||||
@ -65,6 +66,54 @@ namespace actor {
|
||||
namespace core {
|
||||
class IoWorker;
|
||||
|
||||
struct DebugInfo {
|
||||
bool is_active{false};
|
||||
double start_at{0};
|
||||
static constexpr size_t name_size{32};
|
||||
char name[name_size] = {};
|
||||
void set_name(td::Slice from) {
|
||||
from.truncate(name_size - 1);
|
||||
std::memcpy(name, from.data(), from.size());
|
||||
name[from.size()] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
void set_debug(bool flag);
|
||||
bool need_debug();
|
||||
|
||||
struct Debug {
|
||||
public:
|
||||
bool is_on() const {
|
||||
return need_debug();
|
||||
}
|
||||
struct Destructor {
|
||||
void operator()(Debug *info) {
|
||||
info->info_.lock().value().is_active = false;
|
||||
}
|
||||
};
|
||||
|
||||
void read(DebugInfo &info) {
|
||||
info_.read(info);
|
||||
}
|
||||
|
||||
std::unique_ptr<Debug, Destructor> start(td::Slice name) {
|
||||
if (!is_on()) {
|
||||
return {};
|
||||
}
|
||||
{
|
||||
auto lock = info_.lock();
|
||||
auto &value = lock.value();
|
||||
value.is_active = true;
|
||||
value.start_at = Time::now();
|
||||
value.set_name(name);
|
||||
}
|
||||
return std::unique_ptr<Debug, Destructor>(this);
|
||||
}
|
||||
|
||||
private:
|
||||
AtomicRead<DebugInfo> info_;
|
||||
};
|
||||
|
||||
struct WorkerInfo {
|
||||
enum class Type { Io, Cpu } type{Type::Io};
|
||||
WorkerInfo() = default;
|
||||
@ -73,6 +122,7 @@ struct WorkerInfo {
|
||||
}
|
||||
ActorInfoCreator actor_info_creator;
|
||||
CpuWorkerId cpu_worker_id;
|
||||
Debug debug;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@ -195,7 +245,7 @@ class Scheduler {
|
||||
class ContextImpl : public SchedulerContext {
|
||||
public:
|
||||
ContextImpl(ActorInfoCreator *creator, SchedulerId scheduler_id, CpuWorkerId cpu_worker_id,
|
||||
SchedulerGroupInfo *scheduler_group, Poll *poll, KHeap<double> *heap);
|
||||
SchedulerGroupInfo *scheduler_group, Poll *poll, KHeap<double> *heap, Debug *debug);
|
||||
|
||||
SchedulerId get_scheduler_id() const override;
|
||||
void add_to_queue(ActorInfoPtr actor_info_ptr, SchedulerId scheduler_id, bool need_poll) override;
|
||||
@ -208,6 +258,8 @@ class Scheduler {
|
||||
bool has_heap() override;
|
||||
KHeap<double> &get_heap() override;
|
||||
|
||||
Debug &get_debug() override;
|
||||
|
||||
void set_alarm_timestamp(const ActorInfoPtr &actor_info_ptr) override;
|
||||
|
||||
bool is_stop_requested() override;
|
||||
@ -225,6 +277,8 @@ class Scheduler {
|
||||
Poll *poll_;
|
||||
|
||||
KHeap<double> *heap_;
|
||||
|
||||
Debug *debug_;
|
||||
};
|
||||
|
||||
template <class F>
|
||||
@ -234,7 +288,8 @@ class Scheduler {
|
||||
#endif
|
||||
bool is_io_worker = worker_info.type == WorkerInfo::Type::Io;
|
||||
ContextImpl context(&worker_info.actor_info_creator, info_->id, worker_info.cpu_worker_id,
|
||||
scheduler_group_info_.get(), is_io_worker ? &poll_ : nullptr, is_io_worker ? &heap_ : nullptr);
|
||||
scheduler_group_info_.get(), is_io_worker ? &poll_ : nullptr, is_io_worker ? &heap_ : nullptr,
|
||||
&worker_info.debug);
|
||||
SchedulerContext::Guard guard(&context);
|
||||
f();
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ class SchedulerDispatcher {
|
||||
virtual void set_alarm_timestamp(const ActorInfoPtr &actor_info_ptr) = 0;
|
||||
};
|
||||
|
||||
struct Debug;
|
||||
class SchedulerContext : public Context<SchedulerContext>, public SchedulerDispatcher {
|
||||
public:
|
||||
virtual ~SchedulerContext() = default;
|
||||
@ -55,6 +56,9 @@ class SchedulerContext : public Context<SchedulerContext>, public SchedulerDispa
|
||||
// Stop all schedulers
|
||||
virtual bool is_stop_requested() = 0;
|
||||
virtual void stop() = 0;
|
||||
|
||||
// Debug
|
||||
virtual Debug &get_debug() = 0;
|
||||
};
|
||||
} // namespace core
|
||||
} // namespace actor
|
||||
|
@ -675,7 +675,8 @@ TEST(Actor2, actor_function_result) {
|
||||
public:
|
||||
A(std::shared_ptr<td::Destructor> watcher) : watcher_(std::move(watcher)) {
|
||||
}
|
||||
void on_result(uint32 x, uint32 y) {
|
||||
void on_result(uint32 x, td::Result<uint32> r_y) {
|
||||
auto y = r_y.move_as_ok();
|
||||
LOG_CHECK(x * x == y) << x << " " << y;
|
||||
if (--cnt_ == 0) {
|
||||
stop();
|
||||
@ -683,7 +684,7 @@ TEST(Actor2, actor_function_result) {
|
||||
}
|
||||
void start_up() {
|
||||
b_ = create_actor<B>(ActorOptions().with_name("B"));
|
||||
cnt_ = 3;
|
||||
cnt_ = 5;
|
||||
send_closure(b_, &B::query, 3, [a = std::make_unique<int>(), self = actor_id(this)](td::Result<uint32> y) {
|
||||
LOG_IF(ERROR, y.is_error()) << y.error();
|
||||
send_closure(self, &A::on_result, 3, y.ok());
|
||||
@ -696,6 +697,11 @@ TEST(Actor2, actor_function_result) {
|
||||
CHECK(!self.empty());
|
||||
send_closure(self, &A::on_result, 5, y);
|
||||
});
|
||||
auto future = future_send_closure(b_, &B::query, 7);
|
||||
future.finish(td::promise_send_closure(actor_id(this), &A::on_result, 7));
|
||||
//TODO: deduce Future type (i.e. Future<td::uint32>)
|
||||
auto future2 = future_send_closure<td::uint32>(b_, &B::query_async, 7);
|
||||
future2.finish(td::promise_send_closure(actor_id(this), &A::on_result, 7));
|
||||
}
|
||||
|
||||
private:
|
||||
@ -714,12 +720,12 @@ TEST(Actor2, actor_function_result) {
|
||||
}
|
||||
|
||||
TEST(Actor2, actor_ping_pong) {
|
||||
auto group_info = std::make_shared<core::SchedulerGroupInfo>(1);
|
||||
core::Scheduler scheduler{group_info, SchedulerId{0}, 3};
|
||||
Scheduler scheduler{{3}, Scheduler::Paused};
|
||||
sb.clear();
|
||||
scheduler.start();
|
||||
|
||||
auto watcher = td::create_shared_destructor([] { SchedulerContext::get()->stop(); });
|
||||
td::actor::set_debug(true);
|
||||
for (int i = 0; i < 2000; i++) {
|
||||
scheduler.run_in_context([watcher] {
|
||||
class PingPong : public Actor {
|
||||
@ -781,9 +787,9 @@ TEST(Actor2, actor_ping_pong) {
|
||||
});
|
||||
}
|
||||
watcher.reset();
|
||||
while (scheduler.run(1000)) {
|
||||
while (scheduler.run(0.1)) {
|
||||
//scheduler.get_debug().dump();
|
||||
}
|
||||
core::Scheduler::close_scheduler_group(*group_info);
|
||||
sb.clear();
|
||||
}
|
||||
|
||||
|
@ -135,6 +135,78 @@ TEST(Actor, safe_promise) {
|
||||
ASSERT_EQ(res, 3);
|
||||
}
|
||||
|
||||
TEST(Actor, split_promise) {
|
||||
using td::Promise;
|
||||
using td::Result;
|
||||
using td::split_promise;
|
||||
using td::SplitPromise;
|
||||
{
|
||||
td::optional<std::pair<int, double>> x;
|
||||
auto pair = [&](Result<std::pair<int, double>> res) { x = res.move_as_ok(); };
|
||||
static_assert(std::is_same<SplitPromise<decltype(pair)>::ArgT, std::pair<int, double>>::value, "A");
|
||||
static_assert(
|
||||
std::is_same<SplitPromise<decltype(pair)>::SplittedT, std::pair<Promise<int>, Promise<double>>>::value, "A");
|
||||
auto splitted = split_promise(pair);
|
||||
static_assert(std::is_same<decltype(splitted), std::pair<Promise<int>, Promise<double>>>::value, "A");
|
||||
|
||||
splitted.first.set_value(1);
|
||||
splitted.second.set_value(2.0);
|
||||
CHECK(x.unwrap() == std::make_pair(1, 2.0));
|
||||
} // namespace td
|
||||
{
|
||||
td::optional<std::tuple<int, double, std::string>> x;
|
||||
auto triple = [&](Result<std::tuple<int, double, std::string>> res) { x = res.move_as_ok(); };
|
||||
static_assert(std::is_same<SplitPromise<decltype(triple)>::ArgT, std::tuple<int, double, std::string>>::value, "A");
|
||||
static_assert(std::is_same<SplitPromise<decltype(triple)>::SplittedT,
|
||||
std::tuple<Promise<int>, Promise<double>, Promise<std::string>>>::value,
|
||||
"A");
|
||||
auto splitted = split_promise(triple);
|
||||
static_assert(
|
||||
std::is_same<decltype(splitted), std::tuple<Promise<int>, Promise<double>, Promise<std::string>>>::value, "A");
|
||||
std::get<0>(splitted).set_value(1);
|
||||
std::get<1>(splitted).set_value(2.0);
|
||||
std::get<2>(splitted).set_value("hello");
|
||||
CHECK(x.unwrap() == std::make_tuple(1, 2.0, "hello"));
|
||||
}
|
||||
{
|
||||
int code = 0;
|
||||
auto pair = [&](Result<std::pair<int, double>> res) {
|
||||
res.ensure_error();
|
||||
code = res.error().code();
|
||||
};
|
||||
auto splitted = split_promise(td::Promise<std::pair<int, double>>(pair));
|
||||
splitted.second.set_error(td::Status::Error(123, "123"));
|
||||
CHECK(code == 0);
|
||||
splitted.first.set_value(1);
|
||||
CHECK(code == 123);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Actor, promise_future) {
|
||||
using td::make_promise_future;
|
||||
{
|
||||
auto pf = make_promise_future<int>();
|
||||
td::optional<int> res;
|
||||
pf.second.map([](int x) { return x * 2; }).map([](int x) { return x + 10; }).map([&](int x) {
|
||||
res = x;
|
||||
return td::Unit();
|
||||
});
|
||||
CHECK(!res);
|
||||
pf.first.set_value(6);
|
||||
ASSERT_EQ(22, res.unwrap());
|
||||
}
|
||||
{
|
||||
LOG(ERROR) << "Second test";
|
||||
td::optional<int> res;
|
||||
td::make_future(6)
|
||||
.map([](int x) { return x * 2; })
|
||||
.map([](int x) { return x + 10; })
|
||||
.fmap([&](int x) { return td::make_future(x * 2); })
|
||||
.finish([&](int x) { res = x; });
|
||||
ASSERT_EQ(44, res.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Actor2, actor_lost_promise) {
|
||||
using namespace td::actor;
|
||||
using namespace td;
|
||||
@ -459,7 +531,7 @@ class SampleActor : public Actor {
|
||||
detail::current_actor<Printer>().print_a();
|
||||
co_await OnActor(self);
|
||||
LOG(ERROR) << "exit print_a";
|
||||
co_return{};
|
||||
co_return {};
|
||||
}
|
||||
task<Unit> print_b() {
|
||||
auto self = actor_id(this);
|
||||
@ -468,7 +540,7 @@ class SampleActor : public Actor {
|
||||
detail::current_actor<Printer>().print_b();
|
||||
co_await OnActor(self);
|
||||
LOG(ERROR) << "exit print_b";
|
||||
co_return{};
|
||||
co_return {};
|
||||
}
|
||||
|
||||
immediate_task run_coroutine() {
|
||||
|
@ -55,6 +55,10 @@ class KeyValue : public KeyValueReader {
|
||||
virtual Status set(Slice key, Slice value) = 0;
|
||||
virtual Status erase(Slice key) = 0;
|
||||
|
||||
virtual Status begin_write_batch() = 0;
|
||||
virtual Status commit_write_batch() = 0;
|
||||
virtual Status abort_write_batch() = 0;
|
||||
|
||||
virtual Status begin_transaction() = 0;
|
||||
virtual Status commit_transaction() = 0;
|
||||
virtual Status abort_transaction() = 0;
|
||||
@ -86,6 +90,16 @@ class PrefixedKeyValue : public KeyValue {
|
||||
return kv_->erase(PSLICE() << prefix_ << key);
|
||||
}
|
||||
|
||||
Status begin_write_batch() override {
|
||||
return kv_->begin_write_batch();
|
||||
}
|
||||
Status commit_write_batch() override {
|
||||
return kv_->commit_write_batch();
|
||||
}
|
||||
Status abort_write_batch() override {
|
||||
return kv_->abort_write_batch();
|
||||
}
|
||||
|
||||
Status begin_transaction() override {
|
||||
return kv_->begin_transaction();
|
||||
}
|
||||
|
@ -61,6 +61,15 @@ std::unique_ptr<KeyValueReader> MemoryKeyValue::snapshot() {
|
||||
std::string MemoryKeyValue::stats() const {
|
||||
return PSTRING() << "MemoryKeyValueStats{" << tag("get_count", get_count_) << "}";
|
||||
}
|
||||
Status MemoryKeyValue::begin_write_batch() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
Status MemoryKeyValue::commit_write_batch() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
Status MemoryKeyValue::abort_write_batch() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
Status MemoryKeyValue::begin_transaction() {
|
||||
UNREACHABLE();
|
||||
|
@ -29,6 +29,10 @@ class MemoryKeyValue : public KeyValue {
|
||||
Status erase(Slice key) override;
|
||||
Result<size_t> count(Slice prefix) override;
|
||||
|
||||
Status begin_write_batch() override;
|
||||
Status commit_write_batch() override;
|
||||
Status abort_write_batch() override;
|
||||
|
||||
Status begin_transaction() override;
|
||||
Status commit_transaction() override;
|
||||
Status abort_transaction() override;
|
||||
|
@ -78,7 +78,18 @@ Result<RocksDb> RocksDb::open(std::string path) {
|
||||
options.bytes_per_sync = 1 << 20;
|
||||
options.writable_file_max_buffer_size = 2 << 14;
|
||||
options.statistics = statistics;
|
||||
TRY_STATUS(from_rocksdb(rocksdb::OptimisticTransactionDB::Open(options, std::move(path), &db)));
|
||||
rocksdb::OptimisticTransactionDBOptions occ_options;
|
||||
occ_options.validate_policy = rocksdb::OccValidationPolicy::kValidateSerial;
|
||||
rocksdb::ColumnFamilyOptions cf_options(options);
|
||||
std::vector<rocksdb::ColumnFamilyDescriptor> column_families;
|
||||
column_families.push_back(rocksdb::ColumnFamilyDescriptor(rocksdb::kDefaultColumnFamilyName, cf_options));
|
||||
std::vector<rocksdb::ColumnFamilyHandle *> handles;
|
||||
TRY_STATUS(from_rocksdb(
|
||||
rocksdb::OptimisticTransactionDB::Open(options, occ_options, std::move(path), column_families, &handles, &db)));
|
||||
CHECK(handles.size() == 1);
|
||||
// i can delete the handle since DBImpl is always holding a reference to
|
||||
// default column family
|
||||
delete handles[0];
|
||||
}
|
||||
return RocksDb(std::shared_ptr<rocksdb::OptimisticTransactionDB>(db), std::move(statistics));
|
||||
}
|
||||
@ -161,31 +172,41 @@ Result<size_t> RocksDb::count(Slice prefix) {
|
||||
return res;
|
||||
}
|
||||
|
||||
Status RocksDb::begin_write_batch() {
|
||||
CHECK(!transaction_);
|
||||
write_batch_ = std::make_unique<rocksdb::WriteBatch>();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status RocksDb::begin_transaction() {
|
||||
//write_batch_ = std::make_unique<rocksdb::WriteBatch>();
|
||||
CHECK(!write_batch_);
|
||||
rocksdb::WriteOptions options;
|
||||
options.sync = true;
|
||||
transaction_.reset(db_->BeginTransaction(options, {}));
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status RocksDb::commit_transaction() {
|
||||
//CHECK(write_batch_);
|
||||
//auto write_batch = std::move(write_batch_);
|
||||
//rocksdb::WriteOptions options;
|
||||
//options.sync = true;
|
||||
//TRY_STATUS(from_rocksdb(db_->Write(options, write_batch.get())));
|
||||
//return Status::OK();
|
||||
Status RocksDb::commit_write_batch() {
|
||||
CHECK(write_batch_);
|
||||
auto write_batch = std::move(write_batch_);
|
||||
rocksdb::WriteOptions options;
|
||||
options.sync = true;
|
||||
return from_rocksdb(db_->Write(options, write_batch.get()));
|
||||
}
|
||||
|
||||
Status RocksDb::commit_transaction() {
|
||||
CHECK(transaction_);
|
||||
auto res = from_rocksdb(transaction_->Commit());
|
||||
transaction_.reset();
|
||||
return res;
|
||||
auto transaction = std::move(transaction_);
|
||||
return from_rocksdb(transaction->Commit());
|
||||
}
|
||||
|
||||
Status RocksDb::abort_write_batch() {
|
||||
CHECK(write_batch_);
|
||||
write_batch_.reset();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status RocksDb::abort_transaction() {
|
||||
//CHECK(write_batch_);
|
||||
//write_batch_.reset();
|
||||
CHECK(transaction_);
|
||||
transaction_.reset();
|
||||
return Status::OK();
|
||||
|
@ -45,6 +45,10 @@ class RocksDb : public KeyValue {
|
||||
Status erase(Slice key) override;
|
||||
Result<size_t> count(Slice prefix) override;
|
||||
|
||||
Status begin_write_batch() override;
|
||||
Status commit_write_batch() override;
|
||||
Status abort_write_batch() override;
|
||||
|
||||
Status begin_transaction() override;
|
||||
Status commit_transaction() override;
|
||||
Status abort_transaction() override;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
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