Update comment decryption UI

This commit is contained in:
Ali 2020-03-25 17:59:03 +04:00
parent 44b57ffcce
commit 5d55b67c3a
171 changed files with 5267 additions and 1448 deletions

View File

@ -384,7 +384,7 @@ project: check_env kill_xcode
bazel_app_debug_arm64: bazel_app_debug_arm64:
APP_VERSION="${APP_VERSION}" \ APP_VERSION="${APP_VERSION}" \
build-system/prepare-build.sh distribution build-system/prepare-build.sh Telegram distribution
"${BAZEL}" build Telegram/Telegram ${BAZEL_CACHE_FLAGS} ${BAZEL_COMMON_FLAGS} ${BAZEL_DEBUG_FLAGS} \ "${BAZEL}" build Telegram/Telegram ${BAZEL_CACHE_FLAGS} ${BAZEL_COMMON_FLAGS} ${BAZEL_DEBUG_FLAGS} \
-c dbg \ -c dbg \
--ios_multi_cpus=arm64 \ --ios_multi_cpus=arm64 \
@ -394,7 +394,7 @@ bazel_app_debug_arm64:
bazel_app_arm64: bazel_app_arm64:
APP_VERSION="${APP_VERSION}" \ APP_VERSION="${APP_VERSION}" \
BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \ BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \
build-system/prepare-build.sh distribution build-system/prepare-build.sh Telegram distribution
"${BAZEL}" build Telegram/Telegram ${BAZEL_CACHE_FLAGS} ${BAZEL_COMMON_FLAGS} ${BAZEL_OPT_FLAGS} \ "${BAZEL}" build Telegram/Telegram ${BAZEL_CACHE_FLAGS} ${BAZEL_COMMON_FLAGS} ${BAZEL_OPT_FLAGS} \
-c opt \ -c opt \
--ios_multi_cpus=arm64 \ --ios_multi_cpus=arm64 \
@ -408,7 +408,7 @@ bazel_app_arm64:
bazel_prepare_development_build: bazel_prepare_development_build:
APP_VERSION="${APP_VERSION}" \ APP_VERSION="${APP_VERSION}" \
BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \ BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \
build-system/prepare-build.sh development build-system/prepare-build.sh Telegram development
bazel_project: kill_xcode bazel_prepare_development_build bazel_project: kill_xcode bazel_prepare_development_build
APP_VERSION="${APP_VERSION}" \ APP_VERSION="${APP_VERSION}" \

View File

@ -9,15 +9,11 @@ load("@build_bazel_rules_apple//apple:watchos.bzl",
"watchos_extension", "watchos_extension",
) )
load("@build_bazel_rules_apple//apple:versioning.bzl",
"apple_bundle_version",
)
load("@build_bazel_rules_swift//swift:swift.bzl", load("@build_bazel_rules_swift//swift:swift.bzl",
"swift_library", "swift_library",
) )
load("//build-system:plist_fragment.bzl", load("//build-system/bazel-utils:plist_fragment.bzl",
"plist_fragment", "plist_fragment",
) )
@ -179,42 +175,42 @@ plist_fragment(
template = template =
""" """
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>{telegram_version}</string> <string>{telegram_version}</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>{telegram_build_number}</string> <string>{telegram_build_number}</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
<array> <array>
<dict> <dict>
<key>CFBundleTypeRole</key> <key>CFBundleTypeRole</key>
<string>Viewer</string> <string>Viewer</string>
<key>CFBundleURLName</key> <key>CFBundleURLName</key>
<string>{telegram_bundle_id}</string> <string>{telegram_bundle_id}</string>
<key>CFBundleURLSchemes</key> <key>CFBundleURLSchemes</key>
<array> <array>
<string>telegram</string> <string>telegram</string>
</array> </array>
</dict> </dict>
<dict> <dict>
<key>CFBundleTypeRole</key> <key>CFBundleTypeRole</key>
<string>Viewer</string> <string>Viewer</string>
<key>CFBundleURLName</key> <key>CFBundleURLName</key>
<string>{telegram_bundle_id}.ton</string> <string>{telegram_bundle_id}.ton</string>
<key>CFBundleURLSchemes</key> <key>CFBundleURLSchemes</key>
<array> <array>
<string>ton</string> <string>ton</string>
</array> </array>
</dict> </dict>
<dict> <dict>
<key>CFBundleTypeRole</key> <key>CFBundleTypeRole</key>
<string>Viewer</string> <string>Viewer</string>
<key>CFBundleURLName</key> <key>CFBundleURLName</key>
<string>{telegram_bundle_id}.compatibility</string> <string>{telegram_bundle_id}.compatibility</string>
<key>CFBundleURLSchemes</key> <key>CFBundleURLSchemes</key>
<array> <array>
<string>tg</string> <string>tg</string>
</array> </array>
</dict> </dict>
</array> </array>
""".format( """.format(
telegram_version = telegram_version, telegram_version = telegram_version,
telegram_build_number = telegram_build_number, telegram_build_number = telegram_build_number,

View File

@ -1,5 +1,9 @@
include Utils.makefile include Utils.makefile
APP_VERSION="1.0"
CORE_COUNT=$(shell sysctl -n hw.logicalcpu)
CORE_COUNT_MINUS_ONE=$(shell expr ${CORE_COUNT} \- 1)
WALLET_BUCK_OPTIONS=\ WALLET_BUCK_OPTIONS=\
--config custom.appVersion="1.0" \ --config custom.appVersion="1.0" \
--config custom.developmentCodeSignIdentity="${DEVELOPMENT_CODE_SIGN_IDENTITY}" \ --config custom.developmentCodeSignIdentity="${DEVELOPMENT_CODE_SIGN_IDENTITY}" \
@ -21,6 +25,23 @@ WALLET_BUCK_OPTIONS=\
BAZEL=$(shell which bazel) BAZEL=$(shell which bazel)
ifneq ($(BAZEL_CACHE_DIR),)
export BAZEL_CACHE_FLAGS=\
--disk_cache="${BAZEL_CACHE_DIR}"
endif
BAZEL_COMMON_FLAGS=\
--announce_rc \
--features=swift.use_global_module_cache \
BAZEL_DEBUG_FLAGS=\
--features=swift.enable_batch_mode \
--swiftcopt=-j${CORE_COUNT_MINUS_ONE} \
BAZEL_OPT_FLAGS=\
--swiftcopt=-whole-module-optimization \
--swiftcopt='-num-threads' --swiftcopt='16' \
wallet_deps: check_env wallet_deps: check_env
$(BUCK) query "deps(//Wallet:AppPackage)" --output-attribute buck.type \ $(BUCK) query "deps(//Wallet:AppPackage)" --output-attribute buck.type \
${WALLET_BUCK_OPTIONS} ${BUCK_RELEASE_OPTIONS} ${WALLET_BUCK_OPTIONS} ${BUCK_RELEASE_OPTIONS}
@ -51,5 +72,30 @@ wallet_package:
wallet_app: build_wallet wallet_package wallet_app: build_wallet wallet_package
tulsi_project: bazel_wallet_debug_arm64:
${HOME}/Applications/Tulsi.app/Contents/MacOS/Tulsi -- --genconfig Wallet/Wallet.tulsiproj:Default --bazel "${BAZEL}" WALLET_APP_VERSION="${APP_VERSION}" \
build-system/prepare-build.sh Wallet distribution
"${BAZEL}" build Wallet/Wallet ${BAZEL_CACHE_FLAGS} ${BAZEL_COMMON_FLAGS} ${BAZEL_DEBUG_FLAGS} \
-c dbg \
--ios_multi_cpus=arm64 \
--watchos_cpus=armv7k,arm64_32 \
--verbose_failures
bazel_wallet:
WALLET_APP_VERSION="${APP_VERSION}" \
build-system/prepare-build.sh Wallet distribution
"${BAZEL}" build Wallet/Wallet ${BAZEL_CACHE_FLAGS} ${BAZEL_COMMON_FLAGS} ${BAZEL_OPT_FLAGS} \
-c opt \
--ios_multi_cpus=armv7,arm64 \
--watchos_cpus=armv7k,arm64_32 \
--verbose_failures
bazel_wallet_prepare_development_build:
WALLET_APP_VERSION="${APP_VERSION}" \
BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \
build-system/prepare-build.sh Wallet development
bazel_wallet_project: kill_xcode bazel_wallet_prepare_development_build
WALLET_APP_VERSION="${APP_VERSION}" \
BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR}" \
build-system/generate-xcode-project.sh Wallet

View File

@ -1,25 +1,132 @@
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_application", "ios_framework") load("@build_bazel_rules_apple//apple:ios.bzl",
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") "ios_application",
"ios_extension",
"ios_framework",
)
version_info_plist_source = """ load("@build_bazel_rules_swift//swift:swift.bzl",
echo \ "swift_library",
'<?xml version="1.0" encoding="UTF-8"?>' \ )
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' \
'<plist version="1.0">' \ load("//build-system/bazel-utils:plist_fragment.bzl",
'<dict>' \ "plist_fragment",
' <key>CFBundleShortVersionString</key>' \ )
' <string>{}</string>' \
' <key>CFBundleVersion</key>' \ load(
' <string>{}</string>' \ "//build-input/data:variables.bzl",
'</dict>' \ "wallet_build_number",
'</plist>' \ "wallet_version",
> "$@" "wallet_bundle_id",
""".format("1.0", "30") "wallet_team_id",
)
config_setting(
name = "debug",
values = {
"compilation_mode": "dbg",
},
)
genrule( genrule(
name = "VersionInfoPlist", name = "empty",
outs = ["VersionInfo.plist"], outs = ["empty.swift"],
cmd = version_info_plist_source, cmd = "touch $(OUTS)",
)
swift_library(
name = "_LocalDebugOptions",
srcs = [":empty"],
copts = [
"-Xfrontend",
"-serialize-debugging-options",
],
deps = [
],
module_name = "_LocalDebugOptions",
tags = ["no-remote"],
visibility = ["//visibility:public"],
)
debug_deps = select({
":debug": [":_LocalDebugOptions"],
"//conditions:default": [],
})
plist_fragment(
name = "WalletInfoPlist",
extension = "plist",
template =
"""
<key>CFBundleShortVersionString</key>
<string>{wallet_version}</string>
<key>CFBundleVersion</key>
<string>{wallet_build_number}</string>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>TON Wallet</string>
<key>CFBundleIdentifier</key>
<string>{wallet_bundle_id}</string>
<key>CFBundleName</key>
<string>TON Wallet</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSCameraUsageDescription</key>
<string>Please allow TON Wallet access to your camera for scanning QR codes.</string>
<key>NSFaceIDUsageDescription</key>
<string>For better security, please allow TON Wallet to use your Face ID to authenticate payments.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Please allow TON Wallet access to your Photo Stream in case you need to scan a QR code from a picture.</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIFileSharingEnabled</key>
<false/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIRequiresPersistentWiFi</key>
<true/>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIViewEdgeAntialiasing</key>
<false/>
<key>UIViewGroupOpacity</key>
<false/>
""".format(
wallet_version = wallet_version,
wallet_build_number = wallet_build_number,
wallet_bundle_id = wallet_bundle_id,
)
) )
filegroup( filegroup(
@ -29,6 +136,13 @@ filegroup(
], exclude = ["Strings/**/.*"]), ], exclude = ["Strings/**/.*"]),
) )
filegroup(
name = "Icons",
srcs = glob([
"Icons.xcassets/**/*",
], exclude = ["Icons.xcassets/**/.*"]),
)
objc_library( objc_library(
name = "Main", name = "Main",
srcs = [ srcs = [
@ -36,73 +150,37 @@ objc_library(
], ],
) )
ios_framework(
name = "AsyncDisplayKitFramework",
deps = ["//submodules/AsyncDisplayKit:AsyncDisplayKit"],
bundle_id = "org.telegram.Telegram.AsyncDisplayKit",
families = ["iphone", "ipad"],
minimum_os_version = "9.0",
infoplists = [
"Info.plist"
],
)
swift_library( swift_library(
name = "Lib", name = "Lib",
srcs = glob([ srcs = glob([
"Sources/**/*.swift", "Sources/**/*.swift",
]), ]),
data = [ data = [
":Strings",
], ],
deps = [ deps = [
"//submodules/GZip:GZip", "//submodules/WalletUI:WalletUI",
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/SSignalKit/SSignalKit:SSignalKit",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/ObjCRuntimeUtils:ObjCRuntimeUtils",
"//submodules/UIKitRuntimeUtils:UIKitRuntimeUtils",
"//submodules/Display:Display",
"//submodules/AlertUI:AlertUI",
"//submodules/ActivityIndicator:ActivityIndicator",
"//submodules/OverlayStatusController:OverlayStatusController",
"//submodules/openssl:openssl",
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider",
"//submodules/WalletCore:WalletCore", "//submodules/WalletCore:WalletCore",
"//submodules/BuildConfig:BuildConfig", "//submodules/BuildConfig:BuildConfig",
"//submodules/AppBundle:AppBundle", "//submodules/OverlayStatusController:OverlayStatusController",
"//submodules/SolidRoundedButtonNode:SolidRoundedButtonNode",
"//submodules/Camera:Camera",
"//submodules/QrCode:QrCode",
"//submodules/MergeLists:MergeLists",
"//submodules/GlassButtonNode:GlassButtonNode",
"//submodules/UrlEscaping:UrlEscaping",
"//submodules/LocalAuth:LocalAuth",
"//submodules/ScreenCaptureDetection:ScreenCaptureDetection",
"//submodules/WalletUrl:WalletUrl",
"//submodules/ProgressNavigationButtonNode:ProgressNavigationButtonNode",
"//submodules/Markdown:Markdown",
"//submodules/StringPluralization:StringPluralization",
"//submodules/YuvConversion:YuvConversion",
"//submodules/rlottie:RLottieBinding",
"//submodules/AnimatedStickerNode:AnimatedStickerNode",
"//submodules/WalletUI:WalletUI",
"//submodules/FFMpegBinding:FFMpegBinding",
], ],
) )
ios_application( ios_application(
name = "Wallet", name = "Wallet",
bundle_id = "{wallet_bundle_id}", bundle_id = wallet_bundle_id,
families = ["iphone", "ipad"], families = ["iphone", "ipad"],
minimum_os_version = "9.0", minimum_os_version = "9.0",
provisioning_profile = "Wallet.mobileprovision", provisioning_profile = "//build-input/data/provisioning-profiles:Wallet.mobileprovision",
infoplists = [ infoplists = [
":Info.plist", ":WalletInfoPlist.plist",
":VersionInfoPlist",
], ],
frameworks = [ app_icons = [
":AsyncDisplayKitFramework", ":Icons",
],
launch_storyboard = "LaunchScreen.xib",
strings = [
":Strings",
], ],
deps = [ deps = [
":Main", ":Main",

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>

Binary file not shown.

View File

@ -1,4 +1,4 @@
load("//build-system:defines.bzl", load("//build-system/bazel-utils:defines.bzl",
"string_value", "string_value",
) )

View File

@ -0,0 +1,104 @@
#!/bin/sh
copy_provisioning_profiles () {
if [ "$CODESIGNING_DATA_PATH" = "" ]; then
>&2 echo "CODESIGNING_DATA_PATH not defined"
exit 1
fi
PROFILES_TYPE="$1"
case "$PROFILES_TYPE" in
development)
EXPECTED_VARIABLES=(\
WALLET_DEVELOPMENT_PROVISIONING_PROFILE_APP \
)
;;
distribution)
EXPECTED_VARIABLES=(\
WALLET_DISTRIBUTION_PROVISIONING_PROFILE_APP \
)
;;
*)
echo "Unknown build provisioning type: $PROFILES_TYPE"
exit 1
;;
esac
EXPECTED_VARIABLE_NAMES=(\
Wallet \
)
local SEARCH_NAMES=()
local MISSING_VARIABLES="0"
for VARIABLE_NAME in ${EXPECTED_VARIABLES[@]}; do
if [ "${!VARIABLE_NAME}" = "" ]; then
echo "$VARIABLE_NAME not defined"
MISSING_VARIABLES="1"
fi
done
if [ "$MISSING_VARIABLES" == "1" ]; then
exit 1
fi
local VARIABLE_COUNT=${#EXPECTED_VARIABLES[@]}
for (( i=0; i<$VARIABLE_COUNT; i=i+1 )); do
VARIABLE_NAME="${EXPECTED_VARIABLES[$(($i))]}"
SEARCH_NAMES=("${SEARCH_NAMES[@]}" "${EXPECTED_VARIABLE_NAMES[$i]}" "${!VARIABLE_NAME}")
done
local DATA_PATH="build-input/data"
local OUTPUT_DIRECTORY="$DATA_PATH/provisioning-profiles"
rm -rf "$OUTPUT_DIRECTORY"
mkdir -p "$OUTPUT_DIRECTORY"
local BUILD_PATH="$OUTPUT_DIRECTORY/BUILD"
touch "$BUILD_PATH"
echo "exports_files([" >> "$BUILD_PATH"
local ELEMENT_COUNT=${#SEARCH_NAMES[@]}
local REMAINDER=$(($ELEMENT_COUNT % 2))
if [ $REMAINDER != 0 ]; then
>&2 echo "Expecting key-value pairs"
exit 1
fi
for PROFILE in `find "$CODESIGNING_DATA_PATH" -type f -name "*.mobileprovision"`; do
PROFILE_DATA=$(security cms -D -i "$PROFILE")
PROFILE_NAME=$(/usr/libexec/PlistBuddy -c "Print :Name" /dev/stdin <<< $(echo $PROFILE_DATA))
for (( i=0; i<$ELEMENT_COUNT; i=i+2 )); do
ID=${SEARCH_NAMES[$i]}
SEARCH_NAME=${SEARCH_NAMES[$(($i + 1))]}
if [ "$PROFILE_NAME" = "$SEARCH_NAME" ]; then
VARIABLE_NAME="FOUND_PROFILE_$ID"
if [ "${!VARIABLE_NAME}" = "" ]; then
eval "FOUND_PROFILE_$ID=\"$PROFILE\""
else
>&2 echo "Found multiple profiles with name \"$SEARCH_NAME\""
exit 1
fi
fi
done
done
for (( i=0; i<$ELEMENT_COUNT; i=i+2 )); do
ID=${SEARCH_NAMES[$i]}
SEARCH_NAME=${SEARCH_NAMES[$(($i + 1))]}
VARIABLE_NAME="FOUND_PROFILE_$ID"
FOUND_PROFILE="${!VARIABLE_NAME}"
if [ "$FOUND_PROFILE" = "" ]; then
>&2 echo "Profile \"$SEARCH_NAME\" not found"
exit 1
fi
cp "$FOUND_PROFILE" "$OUTPUT_DIRECTORY/$ID.mobileprovision"
echo " \"$ID.mobileprovision\"," >> $BUILD_PATH
done
echo "])" >> "$BUILD_PATH"
}

View File

@ -4,7 +4,7 @@ set -e
APP_TARGET="$1" APP_TARGET="$1"
if [ "$APP_TARGET" == "" ]; then if [ "$APP_TARGET" == "" ]; then
echo "Usage: sh generate-xcode-project.sh app_target" echo "Usage: sh generate-xcode-project.sh app_target_folder"
exit 1 exit 1
fi fi
@ -22,31 +22,6 @@ if [ "$INSTALLED_XCODE_VERSION" != "$XCODE_VERSION" ]; then
exit 1 exit 1
fi fi
EXPECTED_VARIABLES=(\
BUILD_NUMBER \
APP_VERSION \
BUNDLE_ID \
DEVELOPMENT_TEAM \
API_ID \
API_HASH \
APP_CENTER_ID \
IS_INTERNAL_BUILD \
IS_APPSTORE_BUILD \
APPSTORE_ID \
APP_SPECIFIC_URL_SCHEME \
)
MISSING_VARIABLES="0"
for VARIABLE_NAME in ${EXPECTED_VARIABLES[@]}; do
if [ "${!VARIABLE_NAME}" = "" ]; then
echo "$VARIABLE_NAME not defined"
MISSING_VARIABLES="1"
fi
done
if [ "$MISSING_VARIABLES" == "1" ]; then
exit 1
fi
GEN_DIRECTORY="build-input/gen/project" GEN_DIRECTORY="build-input/gen/project"
rm -rf "$GEN_DIRECTORY" rm -rf "$GEN_DIRECTORY"
mkdir -p "$GEN_DIRECTORY" mkdir -p "$GEN_DIRECTORY"
@ -84,18 +59,16 @@ fi
--bazel "$BAZEL" \ --bazel "$BAZEL" \
--outputfolder "$GEN_DIRECTORY" \ --outputfolder "$GEN_DIRECTORY" \
--target "$APP_TARGET":"$APP_TARGET" \ --target "$APP_TARGET":"$APP_TARGET" \
--target "$APP_TARGET":Main \
--target "$APP_TARGET":Lib \
PATCH_OPTIONS="BazelBuildOptionsDebug BazelBuildOptionsRelease" PATCH_OPTIONS="BazelBuildOptionsDebug BazelBuildOptionsRelease"
for NAME in $PATCH_OPTIONS; do for NAME in $PATCH_OPTIONS; do
sed -i "" -e '1h;2,$H;$!d;g' -e 's/\("'"$NAME"'" : {\n[ ]*"p" : "$(inherited)\)/\1'" ${BAZEL_OPTIONS[*]}"'/' "$GEN_DIRECTORY/$APP_TARGET.tulsiproj/Configs/$APP_TARGET.tulsigen" sed -i "" -e '1h;2,$H;$!d;g' -e 's/\("'"$NAME"'" : {\n[ ]*"p" : "$(inherited)\)/\1'" ${BAZEL_OPTIONS[*]}"'/' "$GEN_DIRECTORY/${APP_TARGET}.tulsiproj/Configs/${APP_TARGET}.tulsigen"
done done
sed -i "" -e '1h;2,$H;$!d;g' -e 's/\("sourceFilters" : \[\n[ ]*\)"\.\/\.\.\."/\1"$APP_TARGET\/...", "submodules\/..."/' "$GEN_DIRECTORY/$APP_TARGET.tulsiproj/Configs/$APP_TARGET.tulsigen" sed -i "" -e '1h;2,$H;$!d;g' -e 's/\("sourceFilters" : \[\n[ ]*\)"\.\/\.\.\."/\1"'"${APP_TARGET}"'\/...", "submodules\/..."/' "$GEN_DIRECTORY/${APP_TARGET}.tulsiproj/Configs/${APP_TARGET}.tulsigen"
"$TULSI" -- \ "$TULSI" -- \
--verbose \ --verbose \
--genconfig "$GEN_DIRECTORY/$APP_TARGET.tulsiproj:$APP_TARGET" \ --genconfig "$GEN_DIRECTORY/${APP_TARGET}.tulsiproj:${APP_TARGET}" \
--bazel "$BAZEL" \ --bazel "$BAZEL" \
--outputfolder "$GEN_DIRECTORY" \ --outputfolder "$GEN_DIRECTORY" \

View File

@ -0,0 +1,63 @@
#!/bin/sh
set -e
prepare_build_variables () {
BUILD_TYPE="$1"
case "$BUILD_TYPE" in
development)
APS_ENVIRONMENT="development"
;;
distribution)
APS_ENVIRONMENT="production"
;;
*)
echo "Unknown build provisioning type: $BUILD_TYPE"
exit 1
;;
esac
local BAZEL="$(which bazel)"
if [ "$BAZEL" = "" ]; then
echo "bazel not found in PATH"
exit 1
fi
local EXPECTED_VARIABLES=(\
BUILD_NUMBER \
WALLET_APP_VERSION \
WALLET_BUNDLE_ID \
WALLET_DEVELOPMENT_TEAM \
)
local MISSING_VARIABLES="0"
for VARIABLE_NAME in ${EXPECTED_VARIABLES[@]}; do
if [ "${!VARIABLE_NAME}" = "" ]; then
echo "$VARIABLE_NAME not defined"
MISSING_VARIABLES="1"
fi
done
if [ "$MISSING_VARIABLES" == "1" ]; then
exit 1
fi
local VARIABLES_DIRECTORY="build-input/data"
mkdir -p "$VARIABLES_DIRECTORY"
local VARIABLES_PATH="$VARIABLES_DIRECTORY/variables.bzl"
rm -f "$VARIABLES_PATH"
echo "wallet_build_number = \"$BUILD_NUMBER\"" >> "$VARIABLES_PATH"
echo "wallet_version = \"$WALLET_APP_VERSION\"" >> "$VARIABLES_PATH"
echo "wallet_bundle_id = \"$WALLET_BUNDLE_ID\"" >> "$VARIABLES_PATH"
echo "wallet_api_id = \"$WALLET_API_ID\"" >> "$VARIABLES_PATH"
echo "wallet_team_id = \"$WALLET_DEVELOPMENT_TEAM\"" >> "$VARIABLES_PATH"
echo "telegram_api_id = \"1\"" >> "$VARIABLES_PATH"
echo "telegram_api_hash = \"1\"" >> "$VARIABLES_PATH"
echo "telegram_app_center_id = \"1\"" >> "$VARIABLES_PATH"
echo "telegram_appstore_id = \"1\"" >> "$VARIABLES_PATH"
echo "telegram_is_internal_build = \"false\"" >> "$VARIABLES_PATH"
echo "telegram_is_appstore_build = \"true\"" >> "$VARIABLES_PATH"
echo "telegram_app_specific_url_scheme = \"\"" >> "$VARIABLES_PATH"
}

View File

@ -2,7 +2,13 @@
set -e set -e
BUILD_TYPE="$1" APP_TARGET="$1"
if [ "$APP_TARGET" == "" ]; then
echo "Usage: sh prepare-build.sh app_target development|distribution"
exit 1
fi
BUILD_TYPE="$2"
case "$BUILD_TYPE" in case "$BUILD_TYPE" in
development) development)
PROFILES_TYPE="development" PROFILES_TYPE="development"
@ -18,13 +24,26 @@ esac
BASE_PATH=$(dirname $0) BASE_PATH=$(dirname $0)
COPY_PROVISIONING_PROFILES_SCRIPT="$BASE_PATH/copy-provisioning-profiles-$APP_TARGET.sh"
PREPARE_BUILD_VARIABLES_SCRIPT="$BASE_PATH/prepare-build-variables-$APP_TARGET.sh"
if [ ! -f "$COPY_PROVISIONING_PROFILES_SCRIPT" ]; then
echo "$COPY_PROVISIONING_PROFILES_SCRIPT not found"
exit 1
fi
if [ ! -f "$PREPARE_BUILD_VARIABLES_SCRIPT" ]; then
echo "$PREPARE_BUILD_VARIABLES_SCRIPT not found"
exit 1
fi
DATA_DIRECTORY="build-input/data" DATA_DIRECTORY="build-input/data"
rm -rf "$DATA_DIRECTORY" rm -rf "$DATA_DIRECTORY"
mkdir -p "$DATA_DIRECTORY" mkdir -p "$DATA_DIRECTORY"
touch "$DATA_DIRECTORY/BUILD" touch "$DATA_DIRECTORY/BUILD"
source "$BASE_PATH/copy-provisioning-profiles.sh" source "$COPY_PROVISIONING_PROFILES_SCRIPT"
source "$BASE_PATH/prepare-build-variables.sh" source "$PREPARE_BUILD_VARIABLES_SCRIPT"
echo "Copying provisioning profiles..." echo "Copying provisioning profiles..."
copy_provisioning_profiles "$PROFILES_TYPE" copy_provisioning_profiles "$PROFILES_TYPE"

View File

@ -1 +1 @@
11.3.1 11.4

View File

@ -543,7 +543,7 @@ public final class AnimatedStickerNode: ASDisplayNode {
let frameSourceHolder = self.frameSource let frameSourceHolder = self.frameSource
self.queue.async { [weak self] in self.queue.async { [weak self] in
var maybeFrameSource: AnimatedStickerFrameSource? var maybeFrameSource: AnimatedStickerFrameSource?
var notifyUpdated: (() -> Void)? let notifyUpdated: (() -> Void)? = nil
if let directData = directData { if let directData = directData {
maybeFrameSource = AnimatedStickerDirectFrameSource(queue: queue, data: directData.0, width: directData.2, height: directData.3) maybeFrameSource = AnimatedStickerDirectFrameSource(queue: queue, data: directData.0, width: directData.2, height: directData.3)
} else if let (cachedData, cachedDataComplete) = cachedData { } else if let (cachedData, cachedDataComplete) = cachedData {

View File

@ -42,7 +42,6 @@ public class ActionSheetSwitchNode: ActionSheetItemNode {
override public init(theme: ActionSheetControllerTheme) { override public init(theme: ActionSheetControllerTheme) {
self.theme = theme self.theme = theme
let defaultFont = Font.regular(floor(theme.baseFontSize * 20.0 / 17.0))
self.button = HighlightTrackingButton() self.button = HighlightTrackingButton()
self.button.isAccessibilityElement = false self.button.isAccessibilityElement = false

View File

@ -152,8 +152,7 @@ public extension ContainedViewLayoutTransition {
if let completion = completion { if let completion = completion {
completion(true) completion(true)
} }
case let .animated(duration, curve): case .animated:
let previousBounds = node.bounds
let previousCenter = node.frame.center let previousCenter = node.frame.center
node.position = frame.center node.position = frame.center
node.bounds = CGRect(origin: node.bounds.origin, size: frame.size) node.bounds = CGRect(origin: node.bounds.origin, size: frame.size)

View File

@ -1,6 +1,5 @@
import Foundation import Foundation
import AsyncDisplayKit import AsyncDisplayKit
import Display
public final class ContextContentContainerNode: ASDisplayNode { public final class ContextContentContainerNode: ASDisplayNode {
public var contentNode: ContextContentNode? public var contentNode: ContextContentNode?

View File

@ -1,6 +1,5 @@
import Foundation import Foundation
import AsyncDisplayKit import AsyncDisplayKit
import Display
public final class ContextExtractedContentContainingNode: ASDisplayNode { public final class ContextExtractedContentContainingNode: ASDisplayNode {
public let contentNode: ContextExtractedContentNode public let contentNode: ContextExtractedContentNode

View File

@ -1,6 +1,5 @@
import Foundation import Foundation
import AsyncDisplayKit import AsyncDisplayKit
import Display
public final class ContextControllerSourceNode: ASDisplayNode { public final class ContextControllerSourceNode: ASDisplayNode {
private var contextGesture: ContextGesture? private var contextGesture: ContextGesture?

View File

@ -1,7 +1,6 @@
import Foundation import Foundation
import UIKit import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display
public enum ContextGestureTransition { public enum ContextGestureTransition {
case begin case begin
@ -207,7 +206,7 @@ public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDeleg
override public func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) { override public func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesCancelled(touches, with: event) super.touchesCancelled(touches, with: event)
if let touch = touches.first, !self.currentProgress.isZero, self.isValidated { if let _ = touches.first, !self.currentProgress.isZero, self.isValidated {
let previousProgress = self.currentProgress let previousProgress = self.currentProgress
self.currentProgress = 0.0 self.currentProgress = 0.0
self.activationProgress?(0.0, .ended(previousProgress)) self.activationProgress?(0.0, .ended(previousProgress))

View File

@ -34,7 +34,7 @@ public struct Font {
public static func with(size: CGFloat, design: Design = .regular, traits: Traits = []) -> UIFont { public static func with(size: CGFloat, design: Design = .regular, traits: Traits = []) -> UIFont {
if #available(iOS 13.0, *) { if #available(iOS 13.0, *) {
var descriptor = UIFont.systemFont(ofSize: size).fontDescriptor let descriptor = UIFont.systemFont(ofSize: size).fontDescriptor
var symbolicTraits = descriptor.symbolicTraits var symbolicTraits = descriptor.symbolicTraits
if traits.contains(.bold) { if traits.contains(.bold) {
symbolicTraits.insert(.traitBold) symbolicTraits.insert(.traitBold)

View File

@ -179,13 +179,13 @@ private struct WrappedGridSection: Equatable, Hashable {
self.section = section self.section = section
} }
var hashValue: Int {
return self.section.hashValue
}
static func ==(lhs: WrappedGridSection, rhs: WrappedGridSection) -> Bool { static func ==(lhs: WrappedGridSection, rhs: WrappedGridSection) -> Bool {
return lhs.section.isEqual(to: rhs.section) return lhs.section.isEqual(to: rhs.section)
} }
func hash(into hasher: inout Hasher) {
hasher.combine(self.section.hashValue)
}
} }
public struct GridNodeVisibleItems { public struct GridNodeVisibleItems {
@ -200,10 +200,6 @@ public struct GridNodeVisibleItems {
private struct WrappedGridItemNode: Hashable { private struct WrappedGridItemNode: Hashable {
let node: ASDisplayNode let node: ASDisplayNode
var hashValue: Int {
return node.hashValue
}
static func ==(lhs: WrappedGridItemNode, rhs: WrappedGridItemNode) -> Bool { static func ==(lhs: WrappedGridItemNode, rhs: WrappedGridItemNode) -> Bool {
return lhs.node === rhs.node return lhs.node === rhs.node
} }

View File

@ -6,79 +6,24 @@ import SwiftSignalKit
private enum Corner: Hashable { private enum Corner: Hashable {
case TopLeft(Int), TopRight(Int), BottomLeft(Int), BottomRight(Int) case TopLeft(Int), TopRight(Int), BottomLeft(Int), BottomRight(Int)
var hashValue: Int {
switch self {
case let .TopLeft(radius):
return radius | (1 << 24)
case let .TopRight(radius):
return radius | (2 << 24)
case let .BottomLeft(radius):
return radius | (3 << 24)
case let .BottomRight(radius):
return radius | (4 << 24)
}
}
var radius: Int { var radius: Int {
switch self { switch self {
case let .TopLeft(radius): case let .TopLeft(radius):
return radius return radius
case let .TopRight(radius): case let .TopRight(radius):
return radius return radius
case let .BottomLeft(radius): case let .BottomLeft(radius):
return radius return radius
case let .BottomRight(radius): case let .BottomRight(radius):
return radius return radius
} }
} }
} }
private func ==(lhs: Corner, rhs: Corner) -> Bool {
switch lhs {
case let .TopLeft(lhsRadius):
switch rhs {
case let .TopLeft(rhsRadius) where rhsRadius == lhsRadius:
return true
default:
return false
}
case let .TopRight(lhsRadius):
switch rhs {
case let .TopRight(rhsRadius) where rhsRadius == lhsRadius:
return true
default:
return false
}
case let .BottomLeft(lhsRadius):
switch rhs {
case let .BottomLeft(rhsRadius) where rhsRadius == lhsRadius:
return true
default:
return false
}
case let .BottomRight(lhsRadius):
switch rhs {
case let .BottomRight(rhsRadius) where rhsRadius == lhsRadius:
return true
default:
return false
}
}
}
private enum Tail: Hashable { private enum Tail: Hashable {
case BottomLeft(Int) case BottomLeft(Int)
case BottomRight(Int) case BottomRight(Int)
var hashValue: Int {
switch self {
case let .BottomLeft(radius):
return radius | (1 << 24)
case let .BottomRight(radius):
return radius | (2 << 24)
}
}
var radius: Int { var radius: Int {
switch self { switch self {
case let .BottomLeft(radius): case let .BottomLeft(radius):
@ -89,25 +34,6 @@ private enum Tail: Hashable {
} }
} }
private func ==(lhs: Tail, rhs: Tail) -> Bool {
switch lhs {
case let .BottomLeft(lhsRadius):
switch rhs {
case let .BottomLeft(rhsRadius) where rhsRadius == lhsRadius:
return true
default:
return false
}
case let .BottomRight(lhsRadius):
switch rhs {
case let .BottomRight(rhsRadius) where rhsRadius == lhsRadius:
return true
default:
return false
}
}
}
private var cachedCorners = Atomic<[Corner: DrawingContext]>(value: [:]) private var cachedCorners = Atomic<[Corner: DrawingContext]>(value: [:])
private func cornerContext(_ corner: Corner) -> DrawingContext { private func cornerContext(_ corner: Corner) -> DrawingContext {

View File

@ -13,8 +13,9 @@ public struct KeyShortcut: Hashable {
self.action = action self.action = action
} }
public var hashValue: Int { public func hash(into hasher: inout Hasher) {
return input.hashValue ^ modifiers.hashValue hasher.combine(self.input)
hasher.combine(self.modifiers)
} }
public static func ==(lhs: KeyShortcut, rhs: KeyShortcut) -> Bool { public static func ==(lhs: KeyShortcut, rhs: KeyShortcut) -> Bool {

View File

@ -882,8 +882,6 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
var completeHeight: CGFloat = 0.0 var completeHeight: CGFloat = 0.0
var topItemFound = false var topItemFound = false
var bottomItemFound = false var bottomItemFound = false
var topItemEdge: CGFloat = 0.0
var bottomItemEdge: CGFloat = 0.0
for i in 0 ..< self.itemNodes.count { for i in 0 ..< self.itemNodes.count {
if let index = itemNodes[i].index { if let index = itemNodes[i].index {
@ -900,25 +898,15 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
effectiveInsets.top = max(effectiveInsets.top, self.visibleSize.height - additionalInverseTopInset) effectiveInsets.top = max(effectiveInsets.top, self.visibleSize.height - additionalInverseTopInset)
} }
if topItemFound {
topItemEdge = itemNodes[0].apparentFrame.origin.y
}
var bottomItemNode: ListViewItemNode?
for i in (0 ..< self.itemNodes.count).reversed() { for i in (0 ..< self.itemNodes.count).reversed() {
if let index = itemNodes[i].index { if let index = itemNodes[i].index {
if index == self.items.count - 1 { if index == self.items.count - 1 {
bottomItemNode = itemNodes[i]
bottomItemFound = true bottomItemFound = true
} }
break break
} }
} }
if bottomItemFound {
bottomItemEdge = itemNodes[itemNodes.count - 1].apparentFrame.maxY
}
if topItemFound && bottomItemFound { if topItemFound && bottomItemFound {
for itemNode in self.itemNodes { for itemNode in self.itemNodes {
completeHeight += itemNode.apparentBounds.height completeHeight += itemNode.apparentBounds.height
@ -1119,7 +1107,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
} }
} }
if topItemIndexAndMinY.0 == 0 { if topItemIndexAndMinY.0 == 0 {
var offsetValue: CGFloat = -(topItemIndexAndMinY.1 - self.insets.top) let offsetValue: CGFloat = -(topItemIndexAndMinY.1 - self.insets.top)
offset = .known(offsetValue) offset = .known(offsetValue)
} else if topItemIndexAndMinY.0 == -1 { } else if topItemIndexAndMinY.0 == -1 {
offset = .none offset = .none
@ -1950,7 +1938,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
private func fillMissingNodes(synchronous: Bool, synchronousLoads: Bool, animated: Bool, inputAnimatedInsertIndices: Set<Int>, insertDirectionHints: [Int: ListViewItemOperationDirectionHint], inputState: ListViewState, inputPreviousNodes: [Int: QueueLocalObject<ListViewItemNode>], inputOperations: [ListViewStateOperation], inputCompletion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) { private func fillMissingNodes(synchronous: Bool, synchronousLoads: Bool, animated: Bool, inputAnimatedInsertIndices: Set<Int>, insertDirectionHints: [Int: ListViewItemOperationDirectionHint], inputState: ListViewState, inputPreviousNodes: [Int: QueueLocalObject<ListViewItemNode>], inputOperations: [ListViewStateOperation], inputCompletion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) {
let animatedInsertIndices = inputAnimatedInsertIndices let animatedInsertIndices = inputAnimatedInsertIndices
var state = inputState var state = inputState
var previousNodes = inputPreviousNodes let previousNodes = inputPreviousNodes
var operations = inputOperations var operations = inputOperations
let completion = inputCompletion let completion = inputCompletion
let updateAnimation: ListViewItemUpdateAnimation = animated ? .System(duration: insertionAnimationDuration) : .None let updateAnimation: ListViewItemUpdateAnimation = animated ? .System(duration: insertionAnimationDuration) : .None
@ -2680,7 +2668,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
self.visibleSize = updateSizeAndInsets.size self.visibleSize = updateSizeAndInsets.size
var offsetFix: CGFloat var offsetFix: CGFloat
var insetDeltaOffsetFix: CGFloat = 0.0 let insetDeltaOffsetFix: CGFloat = 0.0
if self.isTracking || isExperimentalSnapToScrollToItem { if self.isTracking || isExperimentalSnapToScrollToItem {
offsetFix = 0.0 offsetFix = 0.0
} else if self.snapToBottomInsetUntilFirstInteraction { } else if self.snapToBottomInsetUntilFirstInteraction {
@ -4009,7 +3997,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
} }
public func cancelSelection() { public func cancelSelection() {
if let selectionTouchLocation = self.selectionTouchLocation { if let _ = self.selectionTouchLocation {
self.clearHighlightAnimated(true) self.clearHighlightAnimated(true)
self.selectionTouchLocation = nil self.selectionTouchLocation = nil
} }

View File

@ -23,6 +23,8 @@ public enum WindowUserInterfaceStyle {
self = .light self = .light
case .dark: case .dark:
self = .dark self = .dark
@unknown default:
self = .dark
} }
} }
} }
@ -188,33 +190,6 @@ private final class WindowRootViewController: UIViewController, UIViewController
private var previewingContext: AnyObject? private var previewingContext: AnyObject?
private func updatePreviewingRegistration() { private func updatePreviewingRegistration() {
var shouldRegister = false
var isVoiceOverRunning = false
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
isVoiceOverRunning = UIAccessibility.isVoiceOverRunning
}
if !isVoiceOverRunning {
shouldRegister = true
}
shouldRegister = false
if shouldRegister != self.registeredForPreviewing {
self.registeredForPreviewing = shouldRegister
if shouldRegister {
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
self.previewingContext = self.registerForPreviewing(with: self, sourceView: self.view)
}
} else if let previewingContext = self.previewingContext {
self.previewingContext = nil
if let previewingContext = previewingContext as? UIViewControllerPreviewing {
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
self.unregisterForPreviewing(withContext: previewingContext)
}
}
}
}
} }
private weak var previousPreviewingHostView: (UIView & PreviewingHostView)? private weak var previousPreviewingHostView: (UIView & PreviewingHostView)?

View File

@ -41,7 +41,7 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
update(strongSelf) update(strongSelf)
} }
})) }))
if let localIsReady = localIsReady { if let _ = localIsReady {
self.isReady = true self.isReady = true
} else { } else {
localIsReady = false localIsReady = false
@ -170,12 +170,9 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
let topController = self.controllers[self.controllers.count - 1] let topController = self.controllers[self.controllers.count - 1]
let bottomController = self.controllers[self.controllers.count - 2] let bottomController = self.controllers[self.controllers.count - 2]
if let topController = topController as? ViewController { if !topController.attemptNavigation({
if !topController.attemptNavigation({ [weak self] in }) {
//let _ = self?.popViewController(animated: true) return
}) {
return
}
} }
topController.viewWillDisappear(true) topController.viewWillDisappear(true)
@ -221,12 +218,11 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
if velocity > 1000 || navigationTransitionCoordinator.progress > 0.2 { if velocity > 1000 || navigationTransitionCoordinator.progress > 0.2 {
navigationTransitionCoordinator.animateCompletion(velocity, completion: { [weak self] in navigationTransitionCoordinator.animateCompletion(velocity, completion: { [weak self] in
guard let strongSelf = self, let layout = strongSelf.state.layout, let transition = strongSelf.state.transition, let top = strongSelf.state.top else { guard let strongSelf = self, let _ = strongSelf.state.layout, let _ = strongSelf.state.transition, let top = strongSelf.state.top else {
return return
} }
let topController = top.value let topController = top.value
let bottomController = transition.previous.value
if viewTreeContainsFirstResponder(view: top.value.view) { if viewTreeContainsFirstResponder(view: top.value.view) {
strongSelf.ignoreInputHeight = true strongSelf.ignoreInputHeight = true
@ -349,7 +345,7 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
var updatedStatusBarStyle = self.statusBarStyle var updatedStatusBarStyle = self.statusBarStyle
if let top = self.state.top { if let top = self.state.top {
var updatedLayout = layout var updatedLayout = layout
if let topTransition = self.state.transition, top.value.view.disableAutomaticKeyboardHandling.isEmpty { if let _ = self.state.transition, top.value.view.disableAutomaticKeyboardHandling.isEmpty {
if !viewTreeContainsFirstResponder(view: top.value.view) { if !viewTreeContainsFirstResponder(view: top.value.view) {
updatedLayout = updatedLayout.withUpdatedInputHeight(nil) updatedLayout = updatedLayout.withUpdatedInputHeight(nil)
} }

View File

@ -155,7 +155,7 @@ open class NavigationController: UINavigationController, ContainableController,
private var _viewControllers: [ViewController] = [] private var _viewControllers: [ViewController] = []
override open var viewControllers: [UIViewController] { override open var viewControllers: [UIViewController] {
get { get {
return self._viewControllers.map { $0 as! ViewController } return self._viewControllers.map { $0 as UIViewController }
} set(value) { } set(value) {
self.setViewControllers(value, animated: false) self.setViewControllers(value, animated: false)
} }
@ -287,7 +287,6 @@ open class NavigationController: UINavigationController, ContainableController,
} }
public func updateTheme(_ theme: NavigationControllerTheme) { public func updateTheme(_ theme: NavigationControllerTheme) {
let statusBarStyleUpdated = self.theme.statusBar != theme.statusBar
self.theme = theme self.theme = theme
if let rootContainer = self.rootContainer { if let rootContainer = self.rootContainer {
switch rootContainer { switch rootContainer {
@ -790,7 +789,7 @@ open class NavigationController: UINavigationController, ContainableController,
} }
let rootModalFrame: NavigationModalFrame let rootModalFrame: NavigationModalFrame
var modalFrameTransition: ContainedViewLayoutTransition = transition let modalFrameTransition: ContainedViewLayoutTransition = transition
var forceStatusBarAnimation = false var forceStatusBarAnimation = false
if let current = self.rootModalFrame { if let current = self.rootModalFrame {
rootModalFrame = current rootModalFrame = current
@ -1165,7 +1164,7 @@ open class NavigationController: UINavigationController, ContainableController,
self.overlayContainers.append(container) self.overlayContainers.append(container)
} }
container.isReadyUpdated = { [weak self, weak container] in container.isReadyUpdated = { [weak self, weak container] in
guard let strongSelf = self, let container = container else { guard let strongSelf = self, let _ = container else {
return return
} }
strongSelf.updateContainersNonReentrant(transition: .immediate) strongSelf.updateContainersNonReentrant(transition: .immediate)
@ -1245,7 +1244,7 @@ open class NavigationController: UINavigationController, ContainableController,
self.view.setNeedsLayout() self.view.setNeedsLayout()
} }
private func requestLayout(transition: ContainedViewLayoutTransition) { public func requestLayout(transition: ContainedViewLayoutTransition) {
if self.isViewLoaded, let validLayout = self.validLayout { if self.isViewLoaded, let validLayout = self.validLayout {
self.containerLayoutUpdated(validLayout, transition: transition) self.containerLayoutUpdated(validLayout, transition: transition)
} }

View File

@ -69,7 +69,7 @@ public class NavigationBackButtonNode: ASControlNode {
} }
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
self.label.updateLayout(CGSize(width: max(0.0, constrainedSize.width - self.arrow.frame.size.width - self.arrowSpacing), height: constrainedSize.height)) let _ = self.label.updateLayout(CGSize(width: max(0.0, constrainedSize.width - self.arrow.frame.size.width - self.arrowSpacing), height: constrainedSize.height))
return CGSize(width: self.arrow.frame.size.width + self.arrowSpacing + self.label.calculatedSize.width, height: max(self.arrow.frame.size.height, self.label.calculatedSize.height)) return CGSize(width: self.arrow.frame.size.width + self.arrowSpacing + self.label.calculatedSize.width, height: max(self.arrow.frame.size.height, self.label.calculatedSize.height))
} }

View File

@ -1059,7 +1059,7 @@ open class NavigationBar: ASDisplayNode {
node.updateManualText(self.backButtonNode.manualText) node.updateManualText(self.backButtonNode.manualText)
node.color = accentColor node.color = accentColor
if let (size, defaultHeight, _, _, _, _) = self.validLayout { if let (size, defaultHeight, _, _, _, _) = self.validLayout {
node.updateLayout(constrainedSize: CGSize(width: size.width, height: defaultHeight)) let _ = node.updateLayout(constrainedSize: CGSize(width: size.width, height: defaultHeight))
node.frame = self.backButtonNode.frame node.frame = self.backButtonNode.frame
} }
return node return node
@ -1082,7 +1082,7 @@ open class NavigationBar: ASDisplayNode {
node.updateItems(items) node.updateItems(items)
node.color = accentColor node.color = accentColor
if let (size, defaultHeight, _, _, _, _) = self.validLayout { if let (size, defaultHeight, _, _, _, _) = self.validLayout {
node.updateLayout(constrainedSize: CGSize(width: size.width, height: defaultHeight)) let _ = node.updateLayout(constrainedSize: CGSize(width: size.width, height: defaultHeight))
node.frame = self.backButtonNode.frame node.frame = self.backButtonNode.frame
} }
return node return node

View File

@ -62,22 +62,15 @@ private final class NavigationButtonItemNode: ImmediateTextNode {
} set(value) { } set(value) {
_image = value _image = value
if let value = value { if let _ = value {
if self.imageNode == nil { if self.imageNode == nil {
let imageNode = ASImageNode() let imageNode = ASImageNode()
imageNode.displayWithoutProcessing = true imageNode.displayWithoutProcessing = true
imageNode.displaysAsynchronously = false imageNode.displaysAsynchronously = false
self.imageNode = imageNode self.imageNode = imageNode
if false, value.size == CGSize(width: 30.0, height: 30.0) { if self.imageRippleNode.supernode != nil {
if self.imageRippleNode.supernode == nil { self.imageRippleNode.image = nil
self.addSubnode(self.imageRippleNode) self.imageRippleNode.removeFromSupernode()
self.imageRippleNode.image = generateFilledCircleImage(diameter: 30.0, color: self.rippleColor)
}
} else {
if self.imageRippleNode.supernode != nil {
self.imageRippleNode.image = nil
self.imageRippleNode.removeFromSupernode()
}
} }
self.addSubnode(imageNode) self.addSubnode(imageNode)

View File

@ -48,7 +48,7 @@ public class NavigationTitleNode: ASDisplayNode {
} }
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
self.label.updateLayout(constrainedSize) let _ = self.label.updateLayout(constrainedSize)
return self.label.calculatedSize return self.label.calculatedSize
} }

View File

@ -54,7 +54,7 @@ public struct TransformImageArguments: Equatable {
} }
public static func ==(lhs: TransformImageArguments, rhs: TransformImageArguments) -> Bool { public static func ==(lhs: TransformImageArguments, rhs: TransformImageArguments) -> Bool {
var result = lhs.imageSize == rhs.imageSize && lhs.boundingSize == rhs.boundingSize && lhs.corners == rhs.corners && lhs.emptyColor == rhs.emptyColor let result = lhs.imageSize == rhs.imageSize && lhs.boundingSize == rhs.boundingSize && lhs.corners == rhs.corners && lhs.emptyColor == rhs.emptyColor
if result { if result {
if let lhsCustom = lhs.custom, let rhsCustom = rhs.custom { if let lhsCustom = lhs.custom, let rhsCustom = rhs.custom {
return lhsCustom.serialized().isEqual(rhsCustom.serialized()) return lhsCustom.serialized().isEqual(rhsCustom.serialized())

View File

@ -316,7 +316,7 @@ public func assertNotOnMainThread(_ file: String = #file, line: Int = #line) {
} }
public extension UIImage { public extension UIImage {
public func precomposed() -> UIImage { func precomposed() -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale) UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
self.draw(at: CGPoint()) self.draw(at: CGPoint())
let result = UIGraphicsGetImageFromCurrentImageContext()! let result = UIGraphicsGetImageFromCurrentImageContext()!

View File

@ -562,18 +562,6 @@ public enum TabBarItemContextActionType {
@available(iOSApplicationExtension 9.0, iOS 9.0, *) @available(iOSApplicationExtension 9.0, iOS 9.0, *)
open func registerForPreviewing(with delegate: UIViewControllerPreviewingDelegate, sourceView: UIView, theme: PeekControllerTheme, onlyNative: Bool) { open func registerForPreviewing(with delegate: UIViewControllerPreviewingDelegate, sourceView: UIView, theme: PeekControllerTheme, onlyNative: Bool) {
if false, self.traitCollection.forceTouchCapability == .available {
let _ = super.registerForPreviewing(with: delegate, sourceView: sourceView)
} else if !onlyNative {
if self.previewingContext == nil {
let previewingContext = SimulatedViewControllerPreviewing(theme: theme, delegate: delegate, sourceView: sourceView, node: self.displayNode, present: { [weak self] c, a in
self?.presentInGlobalOverlay(c, with: a)
}, customPresent: { [weak self] c, n in
return self?.customPresentPreviewingController?(c, n)
})
self.previewingContext = previewingContext
}
}
} }
@available(iOSApplicationExtension 9.0, iOS 9.0, *) @available(iOSApplicationExtension 9.0, iOS 9.0, *)

View File

@ -42,7 +42,6 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
public var rotation: CGFloat = 0.0 { public var rotation: CGFloat = 0.0 {
didSet { didSet {
let transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .easeInOut)
var fromValue: CGFloat = 0.0 var fromValue: CGFloat = 0.0
if let value = (self.layer.value(forKeyPath: "transform.rotation.z") as? NSNumber)?.floatValue { if let value = (self.layer.value(forKeyPath: "transform.rotation.z") as? NSNumber)?.floatValue {
fromValue = CGFloat(value) fromValue = CGFloat(value)

View File

@ -338,10 +338,10 @@ public class Window1 {
} }
strongSelf._rootController?.displayNode.accessibilityElementsHidden = strongSelf.presentationContext.hasOpaqueOverlay || strongSelf.topPresentationContext.hasOpaqueOverlay strongSelf._rootController?.displayNode.accessibilityElementsHidden = strongSelf.presentationContext.hasOpaqueOverlay || strongSelf.topPresentationContext.hasOpaqueOverlay
} }
self.presentationContext.updateHasOpaqueOverlay = { [weak self] value in self.presentationContext.updateHasOpaqueOverlay = { value in
updateOpaqueOverlays() updateOpaqueOverlays()
} }
self.topPresentationContext.updateHasOpaqueOverlay = { [weak self] value in self.topPresentationContext.updateHasOpaqueOverlay = { value in
updateOpaqueOverlays() updateOpaqueOverlays()
} }
@ -846,7 +846,7 @@ public class Window1 {
} }
private func layoutSubviews(force: Bool) { private func layoutSubviews(force: Bool) {
if self.tracingStatusBarsInvalidated, let keyboardManager = keyboardManager { if self.tracingStatusBarsInvalidated, let _ = keyboardManager {
self.tracingStatusBarsInvalidated = false self.tracingStatusBarsInvalidated = false
var supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .all) var supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .all)
@ -1226,11 +1226,11 @@ public class Window1 {
if let navigationController = self._rootController as? NavigationController { if let navigationController = self._rootController as? NavigationController {
if !excludeNavigationSubControllers { if !excludeNavigationSubControllers {
for case let controller as ContainableController in navigationController.viewControllers { for case let controller as ContainableController in navigationController.viewControllers {
!f(controller) let _ = f(controller)
} }
} }
if let controller = navigationController.topOverlayController { if let controller = navigationController.topOverlayController {
!f(controller) let _ = f(controller)
} }
} }
for (controller, _) in self.presentationContext.controllers { for (controller, _) in self.presentationContext.controllers {

View File

@ -13,12 +13,14 @@ public struct LocalAuth {
if context.canEvaluatePolicy(LAPolicy(rawValue: Int(kLAPolicyDeviceOwnerAuthenticationWithBiometrics))!, error: nil) { if context.canEvaluatePolicy(LAPolicy(rawValue: Int(kLAPolicyDeviceOwnerAuthenticationWithBiometrics))!, error: nil) {
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) { if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
switch context.biometryType { switch context.biometryType {
case .faceID: case .faceID:
return .faceId return .faceId
case .touchID: case .touchID:
return .touchId return .touchId
case .none: case .none:
return nil return nil
@unknown default:
return nil
} }
} else { } else {
return .touchId return .touchId

View File

@ -13,12 +13,12 @@ public enum QrCodeIcon {
} }
private func floorToContextPixels(_ value: CGFloat, scale: CGFloat? = UIScreenScale) -> CGFloat { private func floorToContextPixels(_ value: CGFloat, scale: CGFloat? = UIScreenScale) -> CGFloat {
var scale = scale ?? UIScreenScale let scale = scale ?? UIScreenScale
return floor(value * scale) / scale return floor(value * scale) / scale
} }
private func roundToContextPixels(_ value: CGFloat, scale: CGFloat? = UIScreenScale) -> CGFloat { private func roundToContextPixels(_ value: CGFloat, scale: CGFloat? = UIScreenScale) -> CGFloat {
var scale = scale ?? UIScreenScale let scale = scale ?? UIScreenScale
return round(value * scale) / scale return round(value * scale) / scale
} }

View File

@ -1,4 +1,4 @@
load("//build-system:unique_directories.bzl", "unique_directories") load("//build-system/bazel-utils:unique_directories.bzl", "unique_directories")
private_headers = glob([ private_headers = glob([
"Sources/**/*.h", "Sources/**/*.h",

View File

@ -152,7 +152,7 @@ public final class DisposableSet : Disposable {
public func remove(_ disposable: Disposable) { public func remove(_ disposable: Disposable) {
pthread_mutex_lock(&self.lock) pthread_mutex_lock(&self.lock)
if let index = self.disposables.index(where: { $0 === disposable }) { if let index = self.disposables.firstIndex(where: { $0 === disposable }) {
self.disposables.remove(at: index) self.disposables.remove(at: index)
} }
pthread_mutex_unlock(&self.lock) pthread_mutex_unlock(&self.lock)

View File

@ -30,19 +30,19 @@ public func deliverOn<T, E>(_ threadPool: ThreadPool) -> (Signal<T, E>) -> Signa
let queue = threadPool.nextQueue() let queue = threadPool.nextQueue()
return signal.start(next: { next in return signal.start(next: { next in
queue.addTask(ThreadPoolTask { state in queue.addTask(ThreadPoolTask { state in
if !state.cancelled.with { $0 } { if !state.cancelled.with({ $0 }) {
subscriber.putNext(next) subscriber.putNext(next)
} }
}) })
}, error: { error in }, error: { error in
queue.addTask(ThreadPoolTask { state in queue.addTask(ThreadPoolTask { state in
if !state.cancelled.with { $0 } { if !state.cancelled.with({ $0 }) {
subscriber.putError(error) subscriber.putError(error)
} }
}) })
}, completed: { }, completed: {
queue.addTask(ThreadPoolTask { state in queue.addTask(ThreadPoolTask { state in
if !state.cancelled.with { $0 } { if !state.cancelled.with({ $0 }) {
subscriber.putCompletion() subscriber.putCompletion()
} }
}) })
@ -97,7 +97,7 @@ public func runOn<T, E>(_ threadPool: ThreadPool) -> (Signal<T, E>) -> Signal<T,
let disposable = MetaDisposable() let disposable = MetaDisposable()
let task = ThreadPoolTask { state in let task = ThreadPoolTask { state in
if cancelled || state.cancelled.with { $0 } { if cancelled || state.cancelled.with({ $0 }) {
return return
} }

View File

@ -13,7 +13,7 @@ public final class ThreadPoolTask {
} }
func execute() { func execute() {
if !state.cancelled.with { $0 } { if !state.cancelled.with({ $0 }) {
self.action(self.state) self.action(self.state)
} }
} }
@ -74,7 +74,7 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool {
pthread_mutex_lock(&threadPool.mutex); pthread_mutex_lock(&threadPool.mutex);
if queue != nil { if queue != nil {
if let index = threadPool.takenQueues.index(of: queue) { if let index = threadPool.takenQueues.firstIndex(of: queue) {
threadPool.takenQueues.remove(at: index) threadPool.takenQueues.remove(at: index)
} }
@ -97,7 +97,7 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool {
task = queue.popFirstTask() task = queue.popFirstTask()
threadPool.takenQueues.append(queue) threadPool.takenQueues.append(queue)
if let index = threadPool.queues.index(of: queue) { if let index = threadPool.queues.firstIndex(of: queue) {
threadPool.queues.remove(at: index) threadPool.queues.remove(at: index)
} }

View File

@ -83,10 +83,10 @@ public final class ScreenCaptureDetectionManager {
public init(check: @escaping () -> Bool) { public init(check: @escaping () -> Bool) {
self.observer = NotificationCenter.default.addObserver(forName: UIApplication.userDidTakeScreenshotNotification, object: nil, queue: .main, using: { [weak self] _ in self.observer = NotificationCenter.default.addObserver(forName: UIApplication.userDidTakeScreenshotNotification, object: nil, queue: .main, using: { [weak self] _ in
guard let strongSelf = self else { guard let _ = self else {
return return
} }
check() let _ = check()
}) })
self.screenRecordingDisposable = screenRecordingActive().start(next: { [weak self] value in self.screenRecordingDisposable = screenRecordingActive().start(next: { [weak self] value in
@ -116,7 +116,9 @@ public final class ScreenCaptureDetectionManager {
} }
deinit { deinit {
NotificationCenter.default.removeObserver(self.observer) if let observer = self.observer {
NotificationCenter.default.removeObserver(observer)
}
self.screenRecordingDisposable?.dispose() self.screenRecordingDisposable?.dispose()
self.screenRecordingCheckTimer?.invalidate() self.screenRecordingCheckTimer?.invalidate()
self.screenRecordingCheckTimer = nil self.screenRecordingCheckTimer = nil

View File

@ -154,7 +154,7 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
} }
let spacingOffset: CGFloat = 9.0 let spacingOffset: CGFloat = 9.0
var verticalInset: CGFloat = self.subtitle == nil ? floor((buttonFrame.height - titleSize.height) / 2.0) : floor((buttonFrame.height - titleSize.height) / 2.0) - spacingOffset let verticalInset: CGFloat = self.subtitle == nil ? floor((buttonFrame.height - titleSize.height) / 2.0) : floor((buttonFrame.height - titleSize.height) / 2.0) - spacingOffset
let titleFrame = CGRect(origin: CGPoint(x: buttonFrame.minX + nextContentOrigin, y: buttonFrame.minY + verticalInset), size: titleSize) let titleFrame = CGRect(origin: CGPoint(x: buttonFrame.minX + nextContentOrigin, y: buttonFrame.minY + verticalInset), size: titleSize)
transition.updateFrame(node: self.titleNode, frame: titleFrame) transition.updateFrame(node: self.titleNode, frame: titleFrame)

View File

@ -59,11 +59,20 @@ NS_ASSUME_NONNULL_BEGIN
@end @end
@interface TONTransactionMessageContentsEncryptedText : NSObject <TONTransactionMessageContents> @interface TONEncryptedData : NSObject
@property (nonatomic, strong, readonly) NSString * _Nonnull sourceAddress;
@property (nonatomic, strong, readonly) NSData * _Nonnull data; @property (nonatomic, strong, readonly) NSData * _Nonnull data;
- (instancetype)initWithData:(NSData * _Nonnull)data; - (instancetype)initWithSourceAddress:(NSString * _Nonnull)sourceAddress data:(NSData * _Nonnull)data;
@end
@interface TONTransactionMessageContentsEncryptedText : NSObject <TONTransactionMessageContents>
@property (nonatomic, strong, readonly) TONEncryptedData * _Nonnull encryptedData;
- (instancetype)initWithEncryptedData:(TONEncryptedData * _Nonnull)encryptedData;
@end @end
@ -168,7 +177,7 @@ NS_ASSUME_NONNULL_BEGIN
- (SSignal *)deleteKey:(TONKey *)key; - (SSignal *)deleteKey:(TONKey *)key;
- (SSignal *)deleteAllKeys; - (SSignal *)deleteAllKeys;
- (SSignal *)getTransactionListWithAddress:(NSString * _Nonnull)address lt:(int64_t)lt hash:(NSData * _Nonnull)hash; - (SSignal *)getTransactionListWithAddress:(NSString * _Nonnull)address lt:(int64_t)lt hash:(NSData * _Nonnull)hash;
- (SSignal *)decryptMessagesWithKey:(TONKey * _Nonnull)key localPassword:(NSData * _Nonnull)localPassword messages:(NSArray<NSData *> * _Nonnull)messages; - (SSignal *)decryptMessagesWithKey:(TONKey * _Nonnull)key localPassword:(NSData * _Nonnull)localPassword messages:(NSArray<TONEncryptedData *> * _Nonnull)messages;
- (NSData *)encrypt:(NSData *)decryptedData secret:(NSData *)data; - (NSData *)encrypt:(NSData *)decryptedData secret:(NSData *)data;
- (NSData * __nullable)decrypt:(NSData *)encryptedData secret:(NSData *)data; - (NSData * __nullable)decrypt:(NSData *)encryptedData secret:(NSData *)data;

View File

@ -46,8 +46,8 @@ static TONTransactionMessage * _Nullable parseTransactionMessage(tonlib_api::obj
if (message == nullptr) { if (message == nullptr) {
return nil; return nil;
} }
NSString *source = readString(message->source_); NSString *source = readString(message->source_->account_address_);
NSString *destination = readString(message->destination_); NSString *destination = readString(message->destination_->account_address_);
id<TONTransactionMessageContents> contents = nil; id<TONTransactionMessageContents> contents = nil;
if (message->msg_data_->get_id() == tonlib_api::msg_dataRaw::ID) { if (message->msg_data_->get_id() == tonlib_api::msg_dataRaw::ID) {
@ -71,7 +71,8 @@ static TONTransactionMessage * _Nullable parseTransactionMessage(tonlib_api::obj
} }
} else if (message->msg_data_->get_id() == tonlib_api::msg_dataEncryptedText::ID) { } else if (message->msg_data_->get_id() == tonlib_api::msg_dataEncryptedText::ID) {
auto msgData = tonlib_api::move_object_as<tonlib_api::msg_dataEncryptedText>(message->msg_data_); auto msgData = tonlib_api::move_object_as<tonlib_api::msg_dataEncryptedText>(message->msg_data_);
contents = [[TONTransactionMessageContentsEncryptedText alloc] initWithData:makeData(msgData->text_)]; TONEncryptedData *encryptedData = [[TONEncryptedData alloc] initWithSourceAddress:source data:makeData(msgData->text_)];
contents = [[TONTransactionMessageContentsEncryptedText alloc] initWithEncryptedData:encryptedData];
} else { } else {
contents = [[TONTransactionMessageContentsRawData alloc] initWithData:[NSData data]]; contents = [[TONTransactionMessageContentsRawData alloc] initWithData:[NSData data]];
} }
@ -150,10 +151,10 @@ static TONTransactionMessage * _Nullable parseTransactionMessage(tonlib_api::obj
@implementation TONTransactionMessageContentsEncryptedText @implementation TONTransactionMessageContentsEncryptedText
- (instancetype)initWithData:(NSData * _Nonnull)data { - (instancetype)initWithEncryptedData:(TONEncryptedData * _Nonnull)encryptedData {
self = [super init]; self = [super init];
if (self != nil) { if (self != nil) {
_data = data; _encryptedData = encryptedData;
} }
return self; return self;
} }
@ -274,6 +275,19 @@ static TONTransactionMessage * _Nullable parseTransactionMessage(tonlib_api::obj
@end @end
@implementation TONEncryptedData
- (instancetype)initWithSourceAddress:(NSString * _Nonnull)sourceAddress data:(NSData * _Nonnull)data {
self = [super init];
if (self != nil) {
_sourceAddress = sourceAddress;
_data = data;
}
return self;
}
@end
using tonlib_api::make_object; using tonlib_api::make_object;
@interface TONReceiveThreadParams : NSObject @interface TONReceiveThreadParams : NSObject
@ -752,6 +766,7 @@ typedef enum {
std::vector<tonlib_api::object_ptr<tonlib_api::msg_message> > inputMessages; std::vector<tonlib_api::object_ptr<tonlib_api::msg_message> > inputMessages;
inputMessages.push_back(make_object<tonlib_api::msg_message>( inputMessages.push_back(make_object<tonlib_api::msg_message>(
make_object<tonlib_api::accountAddress>(address.UTF8String), make_object<tonlib_api::accountAddress>(address.UTF8String),
makeString([NSData data]),
amount, amount,
tonlib_api::move_object_as<tonlib_api::msg_Data>(inputMessageData) tonlib_api::move_object_as<tonlib_api::msg_Data>(inputMessageData)
)); ));
@ -812,6 +827,7 @@ typedef enum {
std::vector<tonlib_api::object_ptr<tonlib_api::msg_message> > inputMessages; std::vector<tonlib_api::object_ptr<tonlib_api::msg_message> > inputMessages;
inputMessages.push_back(make_object<tonlib_api::msg_message>( inputMessages.push_back(make_object<tonlib_api::msg_message>(
make_object<tonlib_api::accountAddress>(address.UTF8String), make_object<tonlib_api::accountAddress>(address.UTF8String),
makeString([NSData data]),
amount, amount,
tonlib_api::move_object_as<tonlib_api::msg_Data>(inputMessageData) tonlib_api::move_object_as<tonlib_api::msg_Data>(inputMessageData)
)); ));
@ -1093,7 +1109,7 @@ typedef enum {
}] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]]; }] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
} }
- (SSignal *)decryptMessagesWithKey:(TONKey * _Nonnull)key localPassword:(NSData * _Nonnull)localPassword messages:(NSArray<NSData *> * _Nonnull)messages { - (SSignal *)decryptMessagesWithKey:(TONKey * _Nonnull)key localPassword:(NSData * _Nonnull)localPassword messages:(NSArray<TONEncryptedData *> * _Nonnull)messages {
return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) { return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
NSData *publicKeyData = [key.publicKey dataUsingEncoding:NSUTF8StringEncoding]; NSData *publicKeyData = [key.publicKey dataUsingEncoding:NSUTF8StringEncoding];
if (publicKeyData == nil) { if (publicKeyData == nil) {
@ -1108,24 +1124,24 @@ typedef enum {
if (object->get_id() == tonlib_api::error::ID) { if (object->get_id() == tonlib_api::error::ID) {
auto error = tonlib_api::move_object_as<tonlib_api::error>(object); auto error = tonlib_api::move_object_as<tonlib_api::error>(object);
[subscriber putError:[[TONError alloc] initWithText:[[NSString alloc] initWithUTF8String:error->message_.c_str()]]]; [subscriber putError:[[TONError alloc] initWithText:[[NSString alloc] initWithUTF8String:error->message_.c_str()]]];
} else if (object->get_id() == tonlib_api::msg_dataArray::ID) { } else if (object->get_id() == tonlib_api::msg_dataDecryptedArray::ID) {
auto result = tonlib_api::move_object_as<tonlib_api::msg_dataArray>(object); auto result = tonlib_api::move_object_as<tonlib_api::msg_dataDecryptedArray>(object);
if (result->elements_.size() != messages.count) { if (result->elements_.size() != messages.count) {
[subscriber putError:[[TONError alloc] initWithText:@"API interaction error"]]; [subscriber putError:[[TONError alloc] initWithText:@"API interaction error"]];
} else { } else {
NSMutableArray<id<TONTransactionMessageContents> > *resultMessages = [[NSMutableArray alloc] init]; NSMutableArray<id<TONTransactionMessageContents> > *resultMessages = [[NSMutableArray alloc] init];
int index = 0; int index = 0;
for (auto &it : result->elements_) { for (auto &it : result->elements_) {
if (it->get_id() == tonlib_api::msg_dataDecryptedText::ID) { if (it->data_->get_id() == tonlib_api::msg_dataDecryptedText::ID) {
auto dataDecryptedText = tonlib_api::move_object_as<tonlib_api::msg_dataDecryptedText>(it); auto dataDecryptedText = tonlib_api::move_object_as<tonlib_api::msg_dataDecryptedText>(it->data_);
NSString *decryptedString = readString(dataDecryptedText->text_); NSString *decryptedString = readString(dataDecryptedText->text_);
if (decryptedString != nil) { if (decryptedString != nil) {
[resultMessages addObject:[[TONTransactionMessageContentsPlainText alloc] initWithText:decryptedString]]; [resultMessages addObject:[[TONTransactionMessageContentsPlainText alloc] initWithText:decryptedString]];
} else { } else {
[resultMessages addObject:[[TONTransactionMessageContentsEncryptedText alloc] initWithData:messages[index]]]; [resultMessages addObject:[[TONTransactionMessageContentsEncryptedText alloc] initWithEncryptedData:messages[index]]];
} }
} else { } else {
[resultMessages addObject:[[TONTransactionMessageContentsEncryptedText alloc] initWithData:messages[index]]]; [resultMessages addObject:[[TONTransactionMessageContentsEncryptedText alloc] initWithEncryptedData:messages[index]]];
} }
index++; index++;
} }
@ -1137,10 +1153,20 @@ typedef enum {
} }
}]; }];
std::vector<tonlib_api::object_ptr<tonlib_api::msg_Data>> inputData; std::vector<tonlib_api::object_ptr<tonlib_api::msg_dataEncrypted>> inputData;
for (NSData *message in messages) { for (TONEncryptedData *message in messages) {
inputData.push_back(make_object<tonlib_api::msg_dataEncryptedText>( NSData *sourceAddressData = [message.sourceAddress dataUsingEncoding:NSUTF8StringEncoding];
makeString(message) if (sourceAddressData == nil) {
continue;
}
inputData.push_back(make_object<tonlib_api::msg_dataEncrypted>(
make_object<tonlib_api::accountAddress>(
makeString(sourceAddressData)
),
make_object<tonlib_api::msg_dataEncryptedText>(
makeString(message.data)
)
)); ));
} }
@ -1152,7 +1178,7 @@ typedef enum {
), ),
makeSecureString(localPassword) makeSecureString(localPassword)
), ),
make_object<tonlib_api::msg_dataArray>( make_object<tonlib_api::msg_dataEncryptedArray>(
std::move(inputData) std::move(inputData)
) )
); );

View File

@ -196,7 +196,7 @@ public final class TonInstance {
assertionFailure() assertionFailure()
return return
} }
let cancel = keychain.encrypt(key.secret).start(next: { encryptedSecretData in let _ = keychain.encrypt(key.secret).start(next: { encryptedSecretData in
let _ = self.exportKey(key: key, localPassword: localPassword).start(next: { wordList 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), encryptedSecret: encryptedSecretData), wordList))
subscriber.putCompletion() subscriber.putCompletion()
@ -231,7 +231,7 @@ public final class TonInstance {
subscriber.putError(.generic) subscriber.putError(.generic)
return return
} }
let cancel = keychain.encrypt(key.secret).start(next: { encryptedSecretData in let _ = keychain.encrypt(key.secret).start(next: { encryptedSecretData in
subscriber.putNext(WalletInfo(publicKey: WalletPublicKey(rawValue: key.publicKey), encryptedSecret: encryptedSecretData)) subscriber.putNext(WalletInfo(publicKey: WalletPublicKey(rawValue: key.publicKey), encryptedSecret: encryptedSecretData))
subscriber.putCompletion() subscriber.putCompletion()
}, error: { _ in }, error: { _ in
@ -427,20 +427,22 @@ public final class TonInstance {
} }
} }
fileprivate func decryptWalletTransactions(decryptionKey: WalletTransactionDecryptionKey, encryptedMessages: [Data]) -> Signal<[WalletTransactionMessageContents], DecryptWalletTransactionsError> { fileprivate func decryptWalletTransactions(decryptionKey: WalletTransactionDecryptionKey, encryptedMessages: [WalletTransactionEncryptedMessageData]) -> Signal<[WalletTransactionMessageContents], DecryptWalletTransactionsError> {
return Signal { subscriber in return Signal { subscriber in
let disposable = MetaDisposable() let disposable = MetaDisposable()
self.impl.with { impl in self.impl.with { impl in
impl.withInstance { ton in impl.withInstance { ton in
let cancel = ton.decryptMessages(with: TONKey(publicKey: decryptionKey.walletInfo.publicKey.rawValue, secret: decryptionKey.decryptedSecret), localPassword: decryptionKey.localPassword, messages: encryptedMessages).start(next: { result in let cancel = ton.decryptMessages(with: TONKey(publicKey: decryptionKey.walletInfo.publicKey.rawValue, secret: decryptionKey.decryptedSecret), localPassword: decryptionKey.localPassword, messages: encryptedMessages.map { data in
TONEncryptedData(sourceAddress: data.sourceAddress, data: data.data)
}).start(next: { result in
guard let result = result as? [TONTransactionMessageContents] else { guard let result = result as? [TONTransactionMessageContents] else {
subscriber.putError(.generic) subscriber.putError(.generic)
return return
} }
subscriber.putNext(result.map(WalletTransactionMessageContents.init(tonTransactionMessageContents:))) subscriber.putNext(result.map(WalletTransactionMessageContents.init(tonTransactionMessageContents:)))
}, error: { error in }, error: { error in
if let error = error as? TONError { if let _ = error as? TONError {
subscriber.putError(.generic) subscriber.putError(.generic)
} else { } else {
subscriber.putError(.generic) subscriber.putError(.generic)
@ -735,7 +737,7 @@ public struct CombinedWalletState: Codable, Equatable {
return CombinedWalletState( return CombinedWalletState(
walletState: self.walletState, walletState: self.walletState,
timestamp: self.timestamp, timestamp: self.timestamp,
topTransactions: self.topTransactions, topTransactions: topTransactions,
pendingTransactions: self.pendingTransactions pendingTransactions: self.pendingTransactions
) )
} }
@ -1093,7 +1095,6 @@ public func sendGramsFromWallet(storage: WalletStorageInterface, tonInstance: To
} }
}) })
|> mapToSignal { _ -> Signal<PendingWalletTransaction, SendGramsFromWalletError> in |> mapToSignal { _ -> Signal<PendingWalletTransaction, SendGramsFromWalletError> in
return .complete()
} }
|> then(.single(PendingWalletTransaction(timestamp: Int64(Date().timeIntervalSince1970), validUntilTimestamp: preparedQuery.validUntil, bodyHash: preparedQuery.bodyHash, address: toAddress, value: amount, comment: comment))) |> then(.single(PendingWalletTransaction(timestamp: Int64(Date().timeIntervalSince1970), validUntilTimestamp: preparedQuery.validUntil, bodyHash: preparedQuery.bodyHash, address: toAddress, value: amount, comment: comment)))
|> mapToSignal { result in |> mapToSignal { result in
@ -1134,16 +1135,26 @@ public enum WalletTransactionMessageContentsDecodingError: Error {
case generic case generic
} }
public struct WalletTransactionEncryptedMessageData: Codable, Equatable {
public let sourceAddress: String
public let data: Data
public init(sourceAddress: String, data: Data) {
self.sourceAddress = sourceAddress
self.data = data
}
}
public enum WalletTransactionMessageContents: Codable, Equatable { public enum WalletTransactionMessageContents: Codable, Equatable {
enum Key: CodingKey { enum Key: CodingKey {
case raw case raw
case plainText case plainText
case encryptedText case encryptedData
} }
case raw(Data) case raw(Data)
case plainText(String) case plainText(String)
case encryptedText(Data) case encryptedText(WalletTransactionEncryptedMessageData)
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Key.self) let container = try decoder.container(keyedBy: Key.self)
@ -1151,22 +1162,22 @@ public enum WalletTransactionMessageContents: Codable, Equatable {
self = .raw(data) self = .raw(data)
} else if let plainText = try? container.decode(String.self, forKey: .plainText) { } else if let plainText = try? container.decode(String.self, forKey: .plainText) {
self = .plainText(plainText) self = .plainText(plainText)
} else if let encryptedText = try? container.decode(Data.self, forKey: .encryptedText) { } else if let encryptedData = try? container.decode(WalletTransactionEncryptedMessageData.self, forKey: .encryptedData) {
self = .encryptedText(encryptedText) self = .encryptedText(encryptedData)
} else { } else {
throw WalletTransactionMessageContentsDecodingError.generic throw WalletTransactionMessageContentsDecodingError.generic
} }
} }
public func encode(to encoder: Encoder) throws { public func encode(to encoder: Encoder) throws {
var container = try encoder.container(keyedBy: Key.self) var container = encoder.container(keyedBy: Key.self)
switch self { switch self {
case let .raw(data): case let .raw(data):
try container.encode(data, forKey: .raw) try container.encode(data, forKey: .raw)
case let .plainText(text): case let .plainText(text):
try container.encode(text, forKey: .plainText) try container.encode(text, forKey: .plainText)
case let .encryptedText(data): case let .encryptedText(data):
try container.encode(data, forKey: .encryptedText) try container.encode(data, forKey: .encryptedData)
} }
} }
} }
@ -1178,7 +1189,7 @@ private extension WalletTransactionMessageContents {
} else if let plainText = tonTransactionMessageContents as? TONTransactionMessageContentsPlainText { } else if let plainText = tonTransactionMessageContents as? TONTransactionMessageContentsPlainText {
self = .plainText(plainText.text) self = .plainText(plainText.text)
} else if let encryptedText = tonTransactionMessageContents as? TONTransactionMessageContentsEncryptedText { } else if let encryptedText = tonTransactionMessageContents as? TONTransactionMessageContentsEncryptedText {
self = .encryptedText(encryptedText.data) self = .encryptedText(WalletTransactionEncryptedMessageData(sourceAddress: encryptedText.encryptedData.sourceAddress, data: encryptedText.encryptedData.data))
} else { } else {
self = .raw(Data()) self = .raw(Data())
} }
@ -1383,7 +1394,7 @@ public func decryptWalletTransactions(decryptionKey: WalletTransactionDecryption
case inMessage case inMessage
case outMessage(Int) case outMessage(Int)
} }
var encryptedMessages: [(Int, EncryptedMessagePath, Data)] = [] var encryptedMessages: [(Int, EncryptedMessagePath, WalletTransactionEncryptedMessageData)] = []
for i in 0 ..< transactions.count { for i in 0 ..< transactions.count {
if let inMessage = transactions[i].inMessage { if let inMessage = transactions[i].inMessage {
switch inMessage.contents { switch inMessage.contents {
@ -1506,7 +1517,7 @@ private func getWalletTransactionsOnce(address: String, previousId: WalletTransa
case inMessage case inMessage
case outMessage(Int) case outMessage(Int)
} }
var encryptedMessages: [(Int, EncryptedMessagePath, Data)] = [] var encryptedMessages: [(Int, EncryptedMessagePath, WalletTransactionEncryptedMessageData)] = []
for i in 0 ..< transactions.count { for i in 0 ..< transactions.count {
if let inMessage = transactions[i].inMessage { if let inMessage = transactions[i].inMessage {
switch inMessage.contents { switch inMessage.contents {
@ -1591,7 +1602,7 @@ public enum LocalWalletConfigurationSource: Codable, Equatable {
} }
public func encode(to encoder: Encoder) throws { public func encode(to encoder: Encoder) throws {
var container = try encoder.container(keyedBy: Key.self) var container = encoder.container(keyedBy: Key.self)
switch self { switch self {
case let .url(url): case let .url(url):
try container.encode(url, forKey: .url) try container.encode(url, forKey: .url)

View File

@ -20,6 +20,10 @@ swift_library(
srcs = glob([ srcs = glob([
"Sources/**/*.swift", "Sources/**/*.swift",
]), ]),
data = [
":WalletUIResources",
":WalletUIAssets",
],
deps = [ deps = [
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit",

View File

@ -182,16 +182,8 @@ class ItemListMultilineTextItemNode: ListViewItemNode {
} }
var baseFont = titleFont var baseFont = titleFont
var linkFont = titleFont
var boldFont = titleBoldFont
var italicFont = titleItalicFont
var boldItalicFont = titleBoldItalicFont
if case .monospace = item.font { if case .monospace = item.font {
baseFont = Font.monospace(17.0) baseFont = Font.monospace(17.0)
linkFont = Font.monospace(17.0)
boldFont = Font.semiboldMonospace(17.0)
italicFont = Font.italicMonospace(17.0)
boldItalicFont = Font.semiboldItalicMonospace(17.0)
} }
let string = NSAttributedString(string: item.text, font: baseFont, textColor: textColor) let string = NSAttributedString(string: item.text, font: baseFont, textColor: textColor)
@ -365,7 +357,7 @@ class ItemListMultilineTextItemNode: ListViewItemNode {
private func linkItemAtPoint(_ point: CGPoint) -> String? { private func linkItemAtPoint(_ point: CGPoint) -> String? {
let textNodeFrame = self.textNode.frame let textNodeFrame = self.textNode.frame
if let (_, attributes) = self.textNode.attributesAtPoint(CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)) { if let (_, _) = self.textNode.attributesAtPoint(CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)) {
return nil return nil
} }
return nil return nil

View File

@ -182,7 +182,6 @@ class WalletAmountItemNode: ListViewItemNode, UITextFieldDelegate, ItemListItemN
} }
let leftInset: CGFloat = 16.0 + params.leftInset let leftInset: CGFloat = 16.0 + params.leftInset
var rightInset: CGFloat = 16.0 + params.rightInset
let separatorHeight = UIScreenPixel let separatorHeight = UIScreenPixel

View File

@ -108,7 +108,7 @@ private enum WalletConfigurationScreenEntry: ItemListNodeEntry, Equatable {
}) })
case let .modeInfo(theme, text): case let .modeInfo(theme, text):
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section) return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
case let .configUrl(theme, strings, placeholder, text): case let .configUrl(theme, _, placeholder, text):
return ItemListMultilineInputItem(theme: theme, text: text, placeholder: placeholder, maxLength: nil, sectionId: self.section, style: .blocks, capitalization: false, autocorrection: false, returnKeyType: .done, minimalHeight: nil, textUpdated: { value in return ItemListMultilineInputItem(theme: theme, text: text, placeholder: placeholder, maxLength: nil, sectionId: self.section, style: .blocks, capitalization: false, autocorrection: false, returnKeyType: .done, minimalHeight: nil, textUpdated: { value in
arguments.updateState { state in arguments.updateState { state in
var state = state var state = state
@ -211,12 +211,9 @@ func walletConfigurationScreen(context: WalletContext, currentConfiguration: Loc
} }
var presentControllerImpl: ((ViewController, Any?) -> Void)? var presentControllerImpl: ((ViewController, Any?) -> Void)?
var pushImpl: ((ViewController) -> Void)?
var dismissImpl: (() -> Void)? var dismissImpl: (() -> Void)?
var dismissInputImpl: (() -> Void)? var dismissInputImpl: (() -> Void)?
var ensureItemVisibleImpl: ((WalletConfigurationScreenEntryTag, Bool) -> Void)?
weak var currentStatusController: ViewController?
let arguments = WalletConfigurationScreenArguments(updateState: { f in let arguments = WalletConfigurationScreenArguments(updateState: { f in
updateState(f) updateState(f)
}, dismissInput: { }, dismissInput: {
@ -237,9 +234,6 @@ func walletConfigurationScreen(context: WalletContext, currentConfiguration: Loc
let signal = combineLatest(queue: .mainQueue(), .single(context.presentationData), statePromise.get()) let signal = combineLatest(queue: .mainQueue(), .single(context.presentationData), statePromise.get())
|> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, Any)) in |> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, Any)) in
let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Wallet_Navigation_Cancel), style: .regular, enabled: true, action: {
dismissImpl?()
})
let rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Wallet_Configuration_Apply), style: .bold, enabled: !state.isEmpty, action: { let rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Wallet_Configuration_Apply), style: .bold, enabled: !state.isEmpty, action: {
let state = stateValue.with { $0 } let state = stateValue.with { $0 }
let source: LocalWalletConfigurationSource let source: LocalWalletConfigurationSource
@ -346,9 +340,6 @@ func walletConfigurationScreen(context: WalletContext, currentConfiguration: Loc
presentControllerImpl = { [weak controller] c, a in presentControllerImpl = { [weak controller] c, a in
controller?.present(c, in: .window(.root), with: a) controller?.present(c, in: .window(.root), with: a)
} }
pushImpl = { [weak controller] c in
controller?.push(c)
}
dismissImpl = { [weak controller] in dismissImpl = { [weak controller] in
controller?.view.endEditing(true) controller?.view.endEditing(true)
let _ = controller?.dismiss() let _ = controller?.dismiss()
@ -356,26 +347,5 @@ func walletConfigurationScreen(context: WalletContext, currentConfiguration: Loc
dismissInputImpl = { [weak controller] in dismissInputImpl = { [weak controller] in
controller?.view.endEditing(true) controller?.view.endEditing(true)
} }
ensureItemVisibleImpl = { [weak controller] targetTag, animated in
controller?.afterLayout({
guard let controller = controller else {
return
}
var resultItemNode: ListViewItemNode?
let state = stateValue.with({ $0 })
let _ = controller.frameForItemNode({ itemNode in
if let itemNode = itemNode as? ItemListItemNode {
if let tag = itemNode.tag, tag.isEqual(to: targetTag) {
resultItemNode = itemNode as? ListViewItemNode
return true
}
}
return false
})
if let resultItemNode = resultItemNode {
controller.ensureItemNodeVisible(resultItemNode, animated: animated)
}
})
}
return controller return controller
} }

View File

@ -142,7 +142,7 @@ private enum WalletCreateInvoiceScreenEntry: ItemListNodeEntry {
arguments.updateText(WalletCreateInvoiceScreenEntryTag.comment, text) arguments.updateText(WalletCreateInvoiceScreenEntryTag.comment, text)
}, shouldUpdateText: { text in }, shouldUpdateText: { text in
let textLength: Int = text.data(using: .utf8, allowLossyConversion: true)?.count ?? 0 let textLength: Int = text.data(using: .utf8, allowLossyConversion: true)?.count ?? 0
return text.count <= walletTextLimit return textLength <= walletTextLimit
}, updatedFocus: { focus in }, updatedFocus: { focus in
arguments.updateState { state in arguments.updateState { state in
var state = state var state = state
@ -171,7 +171,7 @@ private struct WalletCreateInvoiceScreenState: Equatable {
private func walletCreateInvoiceScreenEntries(presentationData: WalletPresentationData, address: String, state: WalletCreateInvoiceScreenState) -> [WalletCreateInvoiceScreenEntry] { private func walletCreateInvoiceScreenEntries(presentationData: WalletPresentationData, address: String, state: WalletCreateInvoiceScreenState) -> [WalletCreateInvoiceScreenEntry] {
var entries: [WalletCreateInvoiceScreenEntry] = [] var entries: [WalletCreateInvoiceScreenEntry] = []
entries.append(.amount(presentationData.theme, state.amount ?? "")) entries.append(.amount(presentationData.theme, state.amount))
entries.append(.amountInfo(presentationData.theme, presentationData.strings.Wallet_Receive_CreateInvoiceInfo)) entries.append(.amountInfo(presentationData.theme, presentationData.strings.Wallet_Receive_CreateInvoiceInfo))
entries.append(.commentHeader(presentationData.theme, presentationData.strings.Wallet_Receive_CommentHeader)) entries.append(.commentHeader(presentationData.theme, presentationData.strings.Wallet_Receive_CommentHeader))
entries.append(.comment(presentationData.theme, presentationData.strings.Wallet_Receive_CommentInfo, state.comment)) entries.append(.comment(presentationData.theme, presentationData.strings.Wallet_Receive_CommentInfo, state.comment))
@ -196,13 +196,10 @@ func walletCreateInvoiceScreen(context: WalletContext, address: String) -> ViewC
statePromise.set(stateValue.modify { f($0) }) statePromise.set(stateValue.modify { f($0) })
} }
var presentControllerImpl: ((ViewController, Any?) -> Void)?
var pushImpl: ((ViewController) -> Void)? var pushImpl: ((ViewController) -> Void)?
var dismissImpl: (() -> Void)?
var dismissInputImpl: (() -> Void)? var dismissInputImpl: (() -> Void)?
var ensureItemVisibleImpl: ((WalletCreateInvoiceScreenEntryTag, Bool) -> Void)? var ensureItemVisibleImpl: ((WalletCreateInvoiceScreenEntryTag, Bool) -> Void)?
weak var currentStatusController: ViewController?
let arguments = WalletCreateInvoiceScreenArguments(context: context, updateState: { f in let arguments = WalletCreateInvoiceScreenArguments(context: context, updateState: { f in
updateState(f) updateState(f)
}, updateText: { tag, value in }, updateText: { tag, value in
@ -250,16 +247,9 @@ func walletCreateInvoiceScreen(context: WalletContext, address: String) -> ViewC
return state return state
} }
} }
presentControllerImpl = { [weak controller] c, a in
controller?.present(c, in: .window(.root), with: a)
}
pushImpl = { [weak controller] c in pushImpl = { [weak controller] c in
controller?.push(c) controller?.push(c)
} }
dismissImpl = { [weak controller] in
controller?.view.endEditing(true)
let _ = controller?.dismiss()
}
dismissInputImpl = { [weak controller] in dismissInputImpl = { [weak controller] in
controller?.view.endEditing(true) controller?.view.endEditing(true)
} }
@ -269,7 +259,6 @@ func walletCreateInvoiceScreen(context: WalletContext, address: String) -> ViewC
return return
} }
var resultItemNode: ListViewItemNode? var resultItemNode: ListViewItemNode?
let state = stateValue.with({ $0 })
let _ = controller.frameForItemNode({ itemNode in let _ = controller.frameForItemNode({ itemNode in
if let itemNode = itemNode as? ItemListItemNode { if let itemNode = itemNode as? ItemListItemNode {
if let tag = itemNode.tag, tag.isEqual(to: targetTag) { if let tag = itemNode.tag, tag.isEqual(to: targetTag) {

View File

@ -89,7 +89,7 @@ final class WalletInfoEmptyItemNode: ListViewItemNode {
super.didLoad() super.didLoad()
let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:))) let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:)))
recognizer.tapActionAtPoint = { [weak self] point in recognizer.tapActionAtPoint = { point in
return .waitForSingleTap return .waitForSingleTap
} }
self.addressNode.view.addGestureRecognizer(recognizer) self.addressNode.view.addGestureRecognizer(recognizer)
@ -98,7 +98,7 @@ final class WalletInfoEmptyItemNode: ListViewItemNode {
@objc func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { @objc func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
switch recognizer.state { switch recognizer.state {
case .ended: case .ended:
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation {
switch gesture { switch gesture {
case .longTap: case .longTap:
self.item?.displayAddressContextMenu(self, self.addressNode.frame) self.item?.displayAddressContextMenu(self, self.addressNode.frame)
@ -129,7 +129,7 @@ final class WalletInfoEmptyItemNode: ListViewItemNode {
let contentVerticalOrigin: CGFloat = 10.0 let contentVerticalOrigin: CGFloat = 10.0
let sideInset: CGFloat = 16.0 let sideInset: CGFloat = 16.0
var iconOffset = CGPoint() let iconOffset = CGPoint()
let title = item.strings.Wallet_Info_WalletCreated let title = item.strings.Wallet_Info_WalletCreated
let text = item.strings.Wallet_Info_Address let text = item.strings.Wallet_Info_Address

View File

@ -122,7 +122,7 @@ public final class WalletInfoScreen: ViewController {
strongSelf.push(walletSendScreen(context: strongSelf.context, randomId: randomId, walletInfo: walletInfo)) strongSelf.push(walletSendScreen(context: strongSelf.context, randomId: randomId, walletInfo: walletInfo))
} }
}, receiveAction: { [weak self] in }, receiveAction: { [weak self] in
guard let strongSelf = self, let walletInfo = strongSelf.walletInfo else { guard let strongSelf = self, let _ = strongSelf.walletInfo else {
return return
} }
strongSelf.push(WalletReceiveScreen(context: strongSelf.context, mode: .receive(address: strongSelf.address))) strongSelf.push(WalletReceiveScreen(context: strongSelf.context, mode: .receive(address: strongSelf.address)))
@ -221,7 +221,6 @@ final class WalletInfoBalanceNode: ASDisplayNode {
let balanceIntegralTextFrame = CGRect(origin: balanceOrigin, size: balanceIntegralTextSize) let balanceIntegralTextFrame = CGRect(origin: balanceOrigin, size: balanceIntegralTextSize)
let apparentBalanceIntegralTextFrame = CGRect(origin: balanceIntegralTextFrame.origin, size: CGSize(width: balanceIntegralTextFrame.width * integralScale, height: balanceIntegralTextFrame.height * integralScale)) let apparentBalanceIntegralTextFrame = CGRect(origin: balanceIntegralTextFrame.origin, size: CGSize(width: balanceIntegralTextFrame.width * integralScale, height: balanceIntegralTextFrame.height * integralScale))
var balanceFractionalTextFrame = CGRect(origin: CGPoint(x: balanceIntegralTextFrame.maxX, y: balanceIntegralTextFrame.maxY - balanceFractionalTextSize.height), size: balanceFractionalTextSize) var balanceFractionalTextFrame = CGRect(origin: CGPoint(x: balanceIntegralTextFrame.maxX, y: balanceIntegralTextFrame.maxY - balanceFractionalTextSize.height), size: balanceFractionalTextSize)
let apparentBalanceFractionalTextFrame = CGRect(origin: balanceFractionalTextFrame.origin, size: CGSize(width: balanceFractionalTextFrame.width * fractionalScale, height: balanceFractionalTextFrame.height * fractionalScale))
balanceFractionalTextFrame.origin.x -= (balanceFractionalTextFrame.width / 4.0) * scaleTransition + 0.25 * (balanceFractionalTextFrame.width / 2.0) * (1.0 - scaleTransition) balanceFractionalTextFrame.origin.x -= (balanceFractionalTextFrame.width / 4.0) * scaleTransition + 0.25 * (balanceFractionalTextFrame.width / 2.0) * (1.0 - scaleTransition)
balanceFractionalTextFrame.origin.y += balanceFractionalTextFrame.height * 0.5 * (0.8 - fractionalScale) balanceFractionalTextFrame.origin.y += balanceFractionalTextFrame.height * 0.5 * (0.8 - fractionalScale)
@ -332,21 +331,9 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
func update(size: CGSize, navigationHeight: CGFloat, offset: CGFloat, transition: ContainedViewLayoutTransition, isScrolling: Bool) { func update(size: CGSize, navigationHeight: CGFloat, offset: CGFloat, transition: ContainedViewLayoutTransition, isScrolling: Bool) {
let sideInset: CGFloat = 16.0 let sideInset: CGFloat = 16.0
let buttonSideInset: CGFloat = 48.0
let titleSpacing: CGFloat = 10.0
let termsSpacing: CGFloat = 10.0
let buttonHeight: CGFloat = 50.0 let buttonHeight: CGFloat = 50.0
let balanceSubtitleSpacing: CGFloat = 0.0 let balanceSubtitleSpacing: CGFloat = 0.0
let alphaTransition: ContainedViewLayoutTransition
if transition.isAnimated {
alphaTransition = transition
} else if isScrolling {
alphaTransition = .animated(duration: 0.2, curve: .easeInOut)
} else {
alphaTransition = transition
}
let minOffset = navigationHeight let minOffset = navigationHeight
let maxOffset = size.height let maxOffset = size.height
@ -438,11 +425,11 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
transition.updateAlpha(node: self.receiveGramsButtonNode, alpha: buttonAlpha, beginWithCurrentState: true) transition.updateAlpha(node: self.receiveGramsButtonNode, alpha: buttonAlpha, beginWithCurrentState: true)
transition.updateFrame(node: self.receiveButtonNode, frame: leftButtonFrame) transition.updateFrame(node: self.receiveButtonNode, frame: leftButtonFrame)
transition.updateAlpha(node: self.receiveButtonNode, alpha: buttonAlpha, beginWithCurrentState: true) transition.updateAlpha(node: self.receiveButtonNode, alpha: buttonAlpha, beginWithCurrentState: true)
self.receiveGramsButtonNode.updateLayout(width: fullButtonFrame.width, transition: transition) let _ = self.receiveGramsButtonNode.updateLayout(width: fullButtonFrame.width, transition: transition)
self.receiveButtonNode.updateLayout(width: leftButtonFrame.width, transition: transition) let _ = self.receiveButtonNode.updateLayout(width: leftButtonFrame.width, transition: transition)
transition.updateFrame(node: self.sendButtonNode, frame: sendButtonFrame) transition.updateFrame(node: self.sendButtonNode, frame: sendButtonFrame)
transition.updateAlpha(node: self.sendButtonNode, alpha: buttonAlpha, beginWithCurrentState: true) transition.updateAlpha(node: self.sendButtonNode, alpha: buttonAlpha, beginWithCurrentState: true)
self.sendButtonNode.updateLayout(width: sendButtonFrame.width, transition: transition) let _ = self.sendButtonNode.updateLayout(width: sendButtonFrame.width, transition: transition)
} }
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
@ -610,6 +597,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
self.listNode.verticalScrollIndicatorFollowsOverscroll = true self.listNode.verticalScrollIndicatorFollowsOverscroll = true
self.listNode.isHidden = false self.listNode.isHidden = false
self.listNode.view.disablesInteractiveModalDismiss = true self.listNode.view.disablesInteractiveModalDismiss = true
//self.listNode.keepMinimalScrollHeightWithTopInset = 0.0
super.init() super.init()
@ -628,7 +616,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
} }
self.listNode.updateFloatingHeaderOffset = { [weak self] offset, listTransition in self.listNode.updateFloatingHeaderOffset = { [weak self] offset, listTransition in
guard let strongSelf = self, let (layout, navigationHeight) = strongSelf.validLayout else { guard let strongSelf = self, let (_, navigationHeight) = strongSelf.validLayout else {
return return
} }
@ -662,7 +650,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
self.listNode.didEndScrolling = { [weak self] in self.listNode.didEndScrolling = { [weak self] in
canBeginRefresh = true canBeginRefresh = true
guard let strongSelf = self, let (_, navigationHeight) = strongSelf.validLayout else { guard let strongSelf = self, let (_, _) = strongSelf.validLayout else {
return return
} }
switch strongSelf.listNode.visibleContentOffset() { switch strongSelf.listNode.visibleContentOffset() {
@ -765,7 +753,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
return return
} }
strongSelf.headerNode.refreshNode.refreshProgress = progress strongSelf.headerNode.refreshNode.refreshProgress = progress
if strongSelf.headerNode.isRefreshing, strongSelf.isReady, let (layout, navigationHeight) = strongSelf.validLayout { if strongSelf.headerNode.isRefreshing, strongSelf.isReady, let (_, _) = strongSelf.validLayout {
strongSelf.headerNode.refreshNode.update(state: .refreshing) strongSelf.headerNode.refreshNode.update(state: .refreshing)
} }
}) })
@ -951,7 +939,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
strongSelf.headerNode.timestamp = Int32(clamping: combinedState.timestamp) strongSelf.headerNode.timestamp = Int32(clamping: combinedState.timestamp)
} }
if strongSelf.isReady, let (layout, navigationHeight) = strongSelf.validLayout { if strongSelf.isReady, let (_, navigationHeight) = strongSelf.validLayout {
strongSelf.headerNode.update(size: strongSelf.headerNode.bounds.size, navigationHeight: navigationHeight, offset: strongSelf.listOffset ?? 0.0, transition: .immediate, isScrolling: false) strongSelf.headerNode.update(size: strongSelf.headerNode.bounds.size, navigationHeight: navigationHeight, offset: strongSelf.listOffset ?? 0.0, transition: .immediate, isScrolling: false)
} }
@ -960,7 +948,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
strongSelf.headerNode.isRefreshing = false strongSelf.headerNode.isRefreshing = false
if strongSelf.isReady, let (layout, navigationHeight) = strongSelf.validLayout { if strongSelf.isReady, let (_, navigationHeight) = strongSelf.validLayout {
strongSelf.headerNode.update(size: strongSelf.headerNode.bounds.size, navigationHeight: navigationHeight, offset: strongSelf.listOffset ?? 0.0, transition: .animated(duration: 0.2, curve: .easeInOut), isScrolling: false) strongSelf.headerNode.update(size: strongSelf.headerNode.bounds.size, navigationHeight: navigationHeight, offset: strongSelf.listOffset ?? 0.0, transition: .animated(duration: 0.2, curve: .easeInOut), isScrolling: false)
} }
@ -999,7 +987,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
self.headerNode.timestamp = Int32(clamping: combinedState.timestamp) self.headerNode.timestamp = Int32(clamping: combinedState.timestamp)
if self.isReady, let (layout, navigationHeight) = self.validLayout { if self.isReady, let (_, navigationHeight) = self.validLayout {
self.headerNode.update(size: self.headerNode.bounds.size, navigationHeight: navigationHeight, offset: self.listOffset ?? 0.0, transition: .immediate, isScrolling: false) self.headerNode.update(size: self.headerNode.bounds.size, navigationHeight: navigationHeight, offset: self.listOffset ?? 0.0, transition: .immediate, isScrolling: false)
} }
@ -1033,7 +1021,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
self.headerNode.isRefreshing = false self.headerNode.isRefreshing = false
} }
if self.isReady, let (layout, navigationHeight) = self.validLayout { if self.isReady, let (_, navigationHeight) = self.validLayout {
self.headerNode.update(size: self.headerNode.bounds.size, navigationHeight: navigationHeight, offset: self.listOffset ?? 0.0, transition: .animated(duration: 0.2, curve: .easeInOut), isScrolling: false) self.headerNode.update(size: self.headerNode.bounds.size, navigationHeight: navigationHeight, offset: self.listOffset ?? 0.0, transition: .animated(duration: 0.2, curve: .easeInOut), isScrolling: false)
} }
} else { } else {
@ -1090,10 +1078,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
return return
} }
strongSelf.transactionsLoaded(isReload: false, isEmpty: false, transactions: transactions, pendingTransactions: []) strongSelf.transactionsLoaded(isReload: false, isEmpty: false, transactions: transactions, pendingTransactions: [])
}, error: { [weak self] _ in }, error: { _ in
guard let strongSelf = self else {
return
}
})) }))
} }
@ -1133,7 +1118,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
var existingIds = Set<WalletInfoListEntryId>() var existingIds = Set<WalletInfoListEntryId>()
for entry in updatedEntries { for entry in updatedEntries {
switch entry { switch entry {
case let .transaction(_, transaction): case .transaction:
existingIds.insert(entry.stableId) existingIds.insert(entry.stableId)
case .empty: case .empty:
break break
@ -1152,7 +1137,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
self.replaceEntries(updatedEntries) self.replaceEntries(updatedEntries)
if !self.transactionDecryptionKeyRequested { if !self.transactionDecryptionKeyRequested && false {
var encryptedTransactions: [WalletTransactionId: WalletTransaction] = [:] var encryptedTransactions: [WalletTransactionId: WalletTransaction] = [:]
for entry in updatedEntries { for entry in updatedEntries {
switch entry { switch entry {
@ -1233,7 +1218,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
} }
private func dequeueTransaction() { private func dequeueTransaction() {
guard let layout = self.validLayout, let transaction = self.enqueuedTransactions.first else { guard let _ = self.validLayout, let transaction = self.enqueuedTransactions.first else {
return return
} }

View File

@ -98,6 +98,7 @@ class WalletInfoTransactionItem: ListViewItem {
private let titleFont = Font.medium(17.0) private let titleFont = Font.medium(17.0)
private let textFont = Font.monospace(15.0) private let textFont = Font.monospace(15.0)
private let descriptionFont = Font.regular(15.0) private let descriptionFont = Font.regular(15.0)
private let descriptionMonospaceFont = Font.monospace(15.0)
private let dateFont = Font.regular(14.0) private let dateFont = Font.regular(14.0)
private let directionFont = Font.regular(15.0) private let directionFont = Font.regular(15.0)
@ -222,6 +223,7 @@ class WalletInfoTransactionItemNode: ListViewItemNode {
} }
var text: String = "" var text: String = ""
var description: String = "" var description: String = ""
var descriptionIsMonospace = false
if transferredValue <= 0 { if transferredValue <= 0 {
sign = "" sign = ""
title = "\(formatBalanceText(-transferredValue, decimalSeparator: item.dateTimeFormat.decimalSeparator))" title = "\(formatBalanceText(-transferredValue, decimalSeparator: item.dateTimeFormat.decimalSeparator))"
@ -246,7 +248,8 @@ class WalletInfoTransactionItemNode: ListViewItemNode {
case .raw: case .raw:
break break
case .encryptedText: case .encryptedText:
description.append("<encrypted>") description.append("Encrypted Comment")
descriptionIsMonospace = true
case let .plainText(text): case let .plainText(text):
description.append(text) description.append(text)
} }
@ -279,7 +282,8 @@ class WalletInfoTransactionItemNode: ListViewItemNode {
case .raw: case .raw:
description = "" description = ""
case .encryptedText: case .encryptedText:
description = "<encrypted>" description = "Encrypted Comment"
descriptionIsMonospace = true
case let .plainText(text): case let .plainText(text):
description = text description = text
} }
@ -326,7 +330,7 @@ class WalletInfoTransactionItemNode: ListViewItemNode {
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: text, font: textFont, textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - leftInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: text, font: textFont, textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - leftInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (descriptionLayout, descriptionApply) = makeDescriptionLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: description, font: descriptionFont, textColor: item.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - leftInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (descriptionLayout, descriptionApply) = makeDescriptionLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: description, font: descriptionIsMonospace ? descriptionMonospaceFont : descriptionFont, textColor: item.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - leftInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (feesLayout, feesApply) = makeFeesLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: feeText, font: descriptionFont, textColor: item.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - leftInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (feesLayout, feesApply) = makeFeesLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: feeText, font: descriptionFont, textColor: item.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - leftInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))

View File

@ -18,7 +18,7 @@ private func generateFrameImage() -> UIImage? {
context.setLineWidth(4.0) context.setLineWidth(4.0)
context.setLineCap(.round) context.setLineCap(.round)
var path = CGMutablePath(); let path = CGMutablePath()
path.move(to: CGPoint(x: 2.0, y: 2.0 + 26.0)) path.move(to: CGPoint(x: 2.0, y: 2.0 + 26.0))
path.addArc(tangent1End: CGPoint(x: 2.0, y: 2.0), tangent2End: CGPoint(x: 2.0 + 26.0, y: 2.0), radius: 6.0) path.addArc(tangent1End: CGPoint(x: 2.0, y: 2.0), tangent2End: CGPoint(x: 2.0 + 26.0, y: 2.0), radius: 6.0)
path.addLine(to: CGPoint(x: 2.0 + 26.0, y: 2.0)) path.addLine(to: CGPoint(x: 2.0 + 26.0, y: 2.0))

View File

@ -232,15 +232,14 @@ private final class WalletReceiveScreenNode: ViewControllerTracingNode {
} }
let textFont = Font.regular(16.0) let textFont = Font.regular(16.0)
let textColor = self.presentationData.theme.list.itemPrimaryTextColor
let secondaryTextColor = self.presentationData.theme.list.itemSecondaryTextColor let secondaryTextColor = self.presentationData.theme.list.itemSecondaryTextColor
let url = urlForMode(self.mode) let url = urlForMode(self.mode)
switch self.mode { switch self.mode {
case let .receive(address): case .receive:
self.textNode.attributedText = NSAttributedString(string: self.presentationData.strings.Wallet_Receive_ShareUrlInfo, font: textFont, textColor: secondaryTextColor) self.textNode.attributedText = NSAttributedString(string: self.presentationData.strings.Wallet_Receive_ShareUrlInfo, font: textFont, textColor: secondaryTextColor)
self.buttonNode.title = self.presentationData.strings.Wallet_Receive_ShareAddress self.buttonNode.title = self.presentationData.strings.Wallet_Receive_ShareAddress
self.secondaryButtonNode.setTitle(self.presentationData.strings.Wallet_Receive_CreateInvoice, with: Font.regular(17.0), with: self.presentationData.theme.list.itemAccentColor, for: .normal) self.secondaryButtonNode.setTitle(self.presentationData.strings.Wallet_Receive_CreateInvoice, with: Font.regular(17.0), with: self.presentationData.theme.list.itemAccentColor, for: .normal)
case let .invoice(address, amount, comment): case .invoice:
self.textNode.attributedText = NSAttributedString(string: self.presentationData.strings.Wallet_Receive_ShareUrlInfo, font: textFont, textColor: secondaryTextColor, paragraphAlignment: .center) self.textNode.attributedText = NSAttributedString(string: self.presentationData.strings.Wallet_Receive_ShareUrlInfo, font: textFont, textColor: secondaryTextColor, paragraphAlignment: .center)
self.buttonNode.title = self.presentationData.strings.Wallet_Receive_ShareInvoiceUrl self.buttonNode.title = self.presentationData.strings.Wallet_Receive_ShareInvoiceUrl
} }
@ -255,7 +254,7 @@ private final class WalletReceiveScreenNode: ViewControllerTracingNode {
super.didLoad() super.didLoad()
let addressGestureRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapAddressGesture(_:))) let addressGestureRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapAddressGesture(_:)))
addressGestureRecognizer.tapActionAtPoint = { [weak self] point in addressGestureRecognizer.tapActionAtPoint = { point in
return .waitForSingleTap return .waitForSingleTap
} }
self.urlTextNode.view.addGestureRecognizer(addressGestureRecognizer) self.urlTextNode.view.addGestureRecognizer(addressGestureRecognizer)
@ -264,7 +263,7 @@ private final class WalletReceiveScreenNode: ViewControllerTracingNode {
@objc func tapLongTapOrDoubleTapAddressGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { @objc func tapLongTapOrDoubleTapAddressGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
switch recognizer.state { switch recognizer.state {
case .ended: case .ended:
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation {
switch gesture { switch gesture {
case .longTap: case .longTap:
self.displayCopyContextMenu?(self, self.urlTextNode.frame, urlForMode(self.mode)) self.displayCopyContextMenu?(self, self.urlTextNode.frame, urlForMode(self.mode))
@ -299,7 +298,7 @@ private final class WalletReceiveScreenNode: ViewControllerTracingNode {
let makeImageLayout = self.qrImageNode.asyncLayout() let makeImageLayout = self.qrImageNode.asyncLayout()
let imageSide: CGFloat = 215.0 let imageSide: CGFloat = 215.0
var imageSize = CGSize(width: imageSide, height: imageSide) let imageSize = CGSize(width: imageSide, height: imageSide)
let imageApply = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: nil)) let imageApply = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: nil))
let _ = imageApply() let _ = imageApply()
@ -353,6 +352,6 @@ private final class WalletReceiveScreenNode: ViewControllerTracingNode {
let buttonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonWidth) / 2.0), y: layout.size.height - bottomInset - buttonHeight + buttonOffset), size: CGSize(width: buttonWidth, height: buttonHeight)) let buttonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonWidth) / 2.0), y: layout.size.height - bottomInset - buttonHeight + buttonOffset), size: CGSize(width: buttonWidth, height: buttonHeight))
transition.updateFrame(node: self.buttonNode, frame: buttonFrame) transition.updateFrame(node: self.buttonNode, frame: buttonFrame)
self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition) let _ = self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition)
} }
} }

View File

@ -93,12 +93,7 @@ private func lastUpdateTimestampString(strings: WalletStrings, dateTimeFormat: W
if dayDifference == 0 || dayDifference == -1 { if dayDifference == 0 || dayDifference == -1 {
let day: RelativeTimestampFormatDay let day: RelativeTimestampFormatDay
if dayDifference == 0 { if dayDifference == 0 {
if expanded { day = .today
day = .today
} else {
let minutes = difference / (60 * 60)
return strings.Wallet_Updated_HoursAgo(minutes)
}
} else { } else {
day = .yesterday day = .yesterday
} }
@ -226,13 +221,10 @@ final class WalletRefreshNode: ASDisplayNode {
let previousState = self.state let previousState = self.state
self.state = state self.state = state
var pullProgress: CGFloat = 0.0
let title: String let title: String
switch state { switch state {
case let .pullToRefresh(ts, progress): case let .pullToRefresh(ts, _):
title = lastUpdateTimestampString(strings: self.strings, dateTimeFormat: dateTimeFormat, statusTimestamp: ts, relativeTo: Int32(Date().timeIntervalSince1970)) title = lastUpdateTimestampString(strings: self.strings, dateTimeFormat: dateTimeFormat, statusTimestamp: ts, relativeTo: Int32(Date().timeIntervalSince1970))
pullProgress = progress
case .refreshing: case .refreshing:
if ignoreProgressValue { if ignoreProgressValue {
title = self.strings.Wallet_Info_Updating title = self.strings.Wallet_Info_Updating

View File

@ -64,7 +64,7 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
case addressInfo(WalletTheme, String) case addressInfo(WalletTheme, String)
case commentHeader(WalletTheme, String) case commentHeader(WalletTheme, String)
case comment(WalletTheme, String, String, Bool) case comment(WalletTheme, String, String, Bool)
case commendEncryption(WalletTheme, String, Bool) case commentEncryption(WalletTheme, String, Bool)
var section: ItemListSectionId { var section: ItemListSectionId {
switch self { switch self {
@ -72,7 +72,7 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
return WalletSendScreenSection.amount.rawValue return WalletSendScreenSection.amount.rawValue
case .addressHeader, .address, .addressInfo: case .addressHeader, .address, .addressInfo:
return WalletSendScreenSection.address.rawValue return WalletSendScreenSection.address.rawValue
case .commentHeader, .comment, .commendEncryption: case .commentHeader, .comment, .commentEncryption:
return WalletSendScreenSection.comment.rawValue return WalletSendScreenSection.comment.rawValue
} }
} }
@ -93,7 +93,7 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
return 5 return 5
case .comment: case .comment:
return 6 return 6
case .commendEncryption: case .commentEncryption:
return 7 return 7
} }
} }
@ -142,8 +142,8 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .commendEncryption(lhsTheme, lhsText, lhsValue): case let .commentEncryption(lhsTheme, lhsText, lhsValue):
if case let .commendEncryption(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsText == rhsText { if case let .commentEncryption(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsText == rhsText, lhsValue == rhsValue {
return true return true
} else { } else {
return false return false
@ -268,7 +268,7 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
arguments.proceed() arguments.proceed()
} }
}) })
case let .commendEncryption(theme, text, value): case let .commentEncryption(theme, text, value):
return ItemListSwitchItem(theme: theme, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in return ItemListSwitchItem(theme: theme, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
arguments.updateIsEncrypted(value) arguments.updateIsEncrypted(value)
}) })
@ -291,7 +291,7 @@ private func walletSendScreenEntries(presentationData: WalletPresentationData, b
let amount = amountValue(state.amount) let amount = amountValue(state.amount)
let balance = max(0, balance ?? 0) let balance = max(0, balance ?? 0)
entries.append(.amount(presentationData.theme, state.amount ?? "")) entries.append(.amount(presentationData.theme, state.amount))
entries.append(.balance(presentationData.theme, presentationData.strings.Wallet_Send_Balance("").0, formatBalanceText(balance, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator), balance == 0 || (amount > 0 && balance < amount))) entries.append(.balance(presentationData.theme, presentationData.strings.Wallet_Send_Balance("").0, formatBalanceText(balance, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator), balance == 0 || (amount > 0 && balance < amount)))
entries.append(.addressHeader(presentationData.theme, presentationData.strings.Wallet_Send_AddressHeader)) entries.append(.addressHeader(presentationData.theme, presentationData.strings.Wallet_Send_AddressHeader))
@ -300,7 +300,7 @@ private func walletSendScreenEntries(presentationData: WalletPresentationData, b
entries.append(.commentHeader(presentationData.theme, presentationData.strings.Wallet_Receive_CommentHeader)) entries.append(.commentHeader(presentationData.theme, presentationData.strings.Wallet_Receive_CommentHeader))
entries.append(.comment(presentationData.theme, presentationData.strings.Wallet_Receive_CommentInfo, state.comment, sendEnabled)) entries.append(.comment(presentationData.theme, presentationData.strings.Wallet_Receive_CommentInfo, state.comment, sendEnabled))
entries.append(.commendEncryption(presentationData.theme, presentationData.strings.Wallet_Send_EncryptComment, state.isCommentEncrypted)) entries.append(.commentEncryption(presentationData.theme, presentationData.strings.Wallet_Send_EncryptComment, state.isCommentEncrypted))
return entries return entries
} }
@ -478,7 +478,7 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|> deliverOnMainQueue).start(next: { serverSalt in |> deliverOnMainQueue).start(next: { serverSalt in
if let serverSalt = serverSalt { if let serverSalt = serverSalt {
if let commentData = state.comment.data(using: .utf8) { if let commentData = state.comment.data(using: .utf8) {
pushImpl?(WalletSplashScreen(context: context, mode: .sending(walletInfo: walletInfo, address: state.address, amount: amount, comment: commentData, encryptComment: state.isCommentEncrypted && !verificationResult.canNotEncryptComment, randomId: randomId, serverSalt: serverSalt), walletCreatedPreloadState: nil)) pushImpl?(WalletSplashScreen(context: context, mode: .sending(WalletSplashModeSending(walletInfo: walletInfo, address: state.address, amount: amount, comment: commentData, encryptComment: state.isCommentEncrypted && !verificationResult.canNotEncryptComment, randomId: randomId, serverSalt: serverSalt)), walletCreatedPreloadState: nil))
} }
} }
}) })
@ -624,7 +624,7 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
controller?.push(c) controller?.push(c)
} }
popImpl = { [weak controller] in popImpl = { [weak controller] in
(controller?.navigationController as? NavigationController)?.popViewController(animated: true) let _ = (controller?.navigationController as? NavigationController)?.popViewController(animated: true)
} }
dismissImpl = { [weak controller] in dismissImpl = { [weak controller] in
controller?.view.endEditing(true) controller?.view.endEditing(true)
@ -658,7 +658,6 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
} }
var resultItemNode: ListViewItemNode? var resultItemNode: ListViewItemNode?
let state = stateValue.with({ $0 })
let _ = controller.frameForItemNode({ itemNode in let _ = controller.frameForItemNode({ itemNode in
if let itemNode = itemNode as? ItemListItemNode { if let itemNode = itemNode as? ItemListItemNode {
if let tag = itemNode.tag, tag.isEqual(to: targetTag) { if let tag = itemNode.tag, tag.isEqual(to: targetTag) {

View File

@ -105,12 +105,7 @@ private func walletSettingsControllerEntries(presentationData: WalletPresentatio
public func walletSettingsController(context: WalletContext, walletInfo: WalletInfo) -> ViewController { public func walletSettingsController(context: WalletContext, walletInfo: WalletInfo) -> ViewController {
let statePromise = ValuePromise(WalletSettingsControllerState(), ignoreRepeated: true) let statePromise = ValuePromise(WalletSettingsControllerState(), ignoreRepeated: true)
let stateValue = Atomic(value: WalletSettingsControllerState())
let updateState: ((WalletSettingsControllerState) -> WalletSettingsControllerState) -> Void = { f in
statePromise.set(stateValue.modify { f($0) })
}
var dismissImpl: (() -> Void)?
var presentControllerImpl: ((ViewController, Any?) -> Void)? var presentControllerImpl: ((ViewController, Any?) -> Void)?
var pushControllerImpl: ((ViewController) -> Void)? var pushControllerImpl: ((ViewController) -> Void)?
@ -181,10 +176,6 @@ public func walletSettingsController(context: WalletContext, walletInfo: WalletI
let controller = ItemListController(theme: context.presentationData.theme, strings: context.presentationData.strings, updatedPresentationData: .single((context.presentationData.theme, context.presentationData.strings)), state: signal, tabBarItem: nil) let controller = ItemListController(theme: context.presentationData.theme, strings: context.presentationData.strings, updatedPresentationData: .single((context.presentationData.theme, context.presentationData.strings)), state: signal, tabBarItem: nil)
controller.navigationPresentation = .modal controller.navigationPresentation = .modal
controller.enableInteractiveDismiss = true controller.enableInteractiveDismiss = true
dismissImpl = { [weak controller] in
controller?.view.endEditing(true)
controller?.dismiss()
}
presentControllerImpl = { [weak controller] c, a in presentControllerImpl = { [weak controller] c, a in
controller?.present(c, in: .window(.root), with: a) controller?.present(c, in: .window(.root), with: a)
} }

View File

@ -17,12 +17,40 @@ public enum WalletSecureStorageResetReason {
case changed case changed
} }
public struct WalletSplashModeSending {
public let walletInfo: WalletInfo
public let address: String
public let amount: Int64
public let comment: Data
public let encryptComment: Bool
public let randomId: Int64
public let serverSalt: Data
public init(
walletInfo: WalletInfo,
address: String,
amount: Int64,
comment: Data,
encryptComment: Bool,
randomId: Int64,
serverSalt: Data
) {
self.walletInfo = walletInfo
self.address = address
self.amount = amount
self.comment = comment
self.encryptComment = encryptComment
self.randomId = randomId
self.serverSalt = serverSalt
}
}
public enum WalletSplashMode { public enum WalletSplashMode {
case intro case intro
case created(walletInfo: WalletInfo, words: [String]?) case created(walletInfo: WalletInfo, words: [String]?)
case success(walletInfo: WalletInfo) case success(walletInfo: WalletInfo)
case restoreFailed case restoreFailed
case sending(walletInfo: WalletInfo, address: String, amount: Int64, comment: Data, encryptComment: Bool, randomId: Int64, serverSalt: Data) case sending(WalletSplashModeSending)
case sent(walletInfo: WalletInfo, amount: Int64) case sent(walletInfo: WalletInfo, amount: Int64)
case secureStorageNotAvailable case secureStorageNotAvailable
case secureStorageReset(WalletSecureStorageResetReason) case secureStorageReset(WalletSecureStorageResetReason)
@ -81,15 +109,16 @@ public final class WalletSplashScreen: ViewController {
self.navigationBar?.intrinsicCanTransitionInline = false self.navigationBar?.intrinsicCanTransitionInline = false
switch self.mode { switch self.mode {
case let .intro: self.navigationItem.setRightBarButton(UIBarButtonItem(title: self.presentationData.strings.Wallet_Intro_ImportExisting, style: .plain, target: self, action: #selector(self.importPressed)), animated: false) case .intro:
case let .sending(walletInfo, address, amount, comment, encryptComment, randomId, serverSalt): self.navigationItem.setRightBarButton(UIBarButtonItem(title: self.presentationData.strings.Wallet_Intro_ImportExisting, style: .plain, target: self, action: #selector(self.importPressed)), animated: false)
case let .sending(sending):
self.navigationItem.setLeftBarButton(UIBarButtonItem(customDisplayNode: ASDisplayNode())!, animated: false) self.navigationItem.setLeftBarButton(UIBarButtonItem(customDisplayNode: ASDisplayNode())!, animated: false)
let _ = (self.context.keychain.decrypt(walletInfo.encryptedSecret) let _ = (self.context.keychain.decrypt(sending.walletInfo.encryptedSecret)
|> deliverOnMainQueue).start(next: { [weak self] decryptedSecret in |> deliverOnMainQueue).start(next: { [weak self] decryptedSecret in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
strongSelf.sendGrams(walletInfo: walletInfo, decryptedSecret: decryptedSecret, address: address, amount: amount, comment: comment, encryptComment: encryptComment, forceIfDestinationNotInitialized: true, randomId: randomId, serverSalt: serverSalt) strongSelf.sendGrams(walletInfo: sending.walletInfo, decryptedSecret: decryptedSecret, address: sending.address, amount: sending.amount, comment: sending.comment, encryptComment: sending.encryptComment, forceIfDestinationNotInitialized: true, randomId: sending.randomId, serverSalt: sending.serverSalt)
}, error: { [weak self] error in }, error: { [weak self] error in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -242,7 +271,7 @@ public final class WalletSplashScreen: ViewController {
let controller = textAlertController(alertContext: AlertControllerContext(theme: theme.alert, themeSignal: .single(theme.alert)), title: strongSelf.presentationData.strings.Wallet_Send_UninitializedTitle, text: text, actions: [ let controller = textAlertController(alertContext: AlertControllerContext(theme: theme.alert, themeSignal: .single(theme.alert)), title: strongSelf.presentationData.strings.Wallet_Send_UninitializedTitle, text: text, actions: [
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Wallet_Navigation_Cancel, action: { TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Wallet_Navigation_Cancel, action: {
if let navigationController = strongSelf.navigationController as? NavigationController { if let navigationController = strongSelf.navigationController as? NavigationController {
navigationController.popViewController(animated: true) let _ = navigationController.popViewController(animated: true)
} }
}), }),
TextAlertAction(type: .defaultAction, title: "Send Anyway", action: { TextAlertAction(type: .defaultAction, title: "Send Anyway", action: {
@ -258,7 +287,7 @@ public final class WalletSplashScreen: ViewController {
let theme = strongSelf.presentationData.theme let theme = strongSelf.presentationData.theme
let controller = textAlertController(alertContext: AlertControllerContext(theme: theme.alert, themeSignal: .single(theme.alert)), title: title, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Wallet_Alert_OK, action: { let controller = textAlertController(alertContext: AlertControllerContext(theme: theme.alert, themeSignal: .single(theme.alert)), title: title, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Wallet_Alert_OK, action: {
if let navigationController = strongSelf.navigationController as? NavigationController { if let navigationController = strongSelf.navigationController as? NavigationController {
navigationController.popViewController(animated: true) let _ = navigationController.popViewController(animated: true)
} }
})]) })])
strongSelf.present(controller, in: .window(.root)) strongSelf.present(controller, in: .window(.root))
@ -286,14 +315,14 @@ public final class WalletSplashScreen: ViewController {
return true return true
} }
let _ = (walletAddress(publicKey: sending.0.publicKey, tonInstance: self.context.tonInstance) let _ = (walletAddress(publicKey: sending.walletInfo.publicKey, tonInstance: self.context.tonInstance)
|> deliverOnMainQueue).start(next: { [weak self] address in |> deliverOnMainQueue).start(next: { [weak self] address in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
if !controllers.contains(where: { $0 is WalletInfoScreen }) { if !controllers.contains(where: { $0 is WalletInfoScreen }) {
let infoScreen = WalletInfoScreen(context: strongSelf.context, walletInfo: sending.0, address: address, enableDebugActions: false) let infoScreen = WalletInfoScreen(context: strongSelf.context, walletInfo: sending.walletInfo, address: address, enableDebugActions: false)
infoScreen.navigationPresentation = .modal infoScreen.navigationPresentation = .modal
controllers.append(infoScreen) controllers.append(infoScreen)
} }
@ -498,14 +527,14 @@ public final class WalletSplashScreen: ViewController {
return true return true
} }
let _ = (walletAddress(publicKey: sending.0.publicKey, tonInstance: strongSelf.context.tonInstance) let _ = (walletAddress(publicKey: sending.walletInfo.publicKey, tonInstance: strongSelf.context.tonInstance)
|> deliverOnMainQueue).start(next: { [weak self] address in |> deliverOnMainQueue).start(next: { [weak self] address in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
if !controllers.contains(where: { $0 is WalletInfoScreen }) { if !controllers.contains(where: { $0 is WalletInfoScreen }) {
let infoScreen = WalletInfoScreen(context: strongSelf.context, walletInfo: sending.0, address: address, enableDebugActions: false) let infoScreen = WalletInfoScreen(context: strongSelf.context, walletInfo: sending.walletInfo, address: address, enableDebugActions: false)
infoScreen.navigationPresentation = .modal infoScreen.navigationPresentation = .modal
controllers.append(infoScreen) controllers.append(infoScreen)
} }
@ -891,7 +920,7 @@ private final class WalletSplashScreenNode: ViewControllerTracingNode {
let buttonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonWidth) / 2.0), y: layout.size.height - bottomInset - buttonHeight), size: CGSize(width: buttonWidth, height: buttonHeight)) let buttonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonWidth) / 2.0), y: layout.size.height - bottomInset - buttonHeight), size: CGSize(width: buttonWidth, height: buttonHeight))
transition.updateFrame(node: self.buttonNode, frame: buttonFrame) transition.updateFrame(node: self.buttonNode, frame: buttonFrame)
self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition) let _ = self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition)
var maxContentVerticalOrigin = buttonFrame.minY - 12.0 - contentHeight var maxContentVerticalOrigin = buttonFrame.minY - 12.0 - contentHeight

View File

@ -69,6 +69,33 @@ private func stringForAddress(strings: WalletStrings, address: WalletTransaction
} }
} }
private extension WalletInfoTransaction {
var isEncrypted: Bool {
switch self {
case .pending:
return false
case let .completed(transaction):
if let inMessage = transaction.inMessage {
switch inMessage.contents {
case .encryptedText:
return true
default:
break
}
}
for message in transaction.outMessages {
switch message.contents {
case .encryptedText:
return true
default:
break
}
}
return false
}
}
}
private func extractAddress(_ walletTransaction: WalletInfoTransaction) -> WalletTransactionAddress { private func extractAddress(_ walletTransaction: WalletInfoTransaction) -> WalletTransactionAddress {
switch walletTransaction { switch walletTransaction {
case let .completed(walletTransaction): case let .completed(walletTransaction):
@ -90,17 +117,17 @@ private func extractAddress(_ walletTransaction: WalletInfoTransaction) -> Walle
return .unknown return .unknown
} }
} }
return .none
case let .pending(pending): case let .pending(pending):
return .list([pending.address]) return .list([pending.address])
} }
} }
private func extractDescription(_ walletTransaction: WalletInfoTransaction) -> String { private func extractDescription(_ walletTransaction: WalletInfoTransaction) -> (string: String, isEncrypted: Bool) {
switch walletTransaction { switch walletTransaction {
case let .completed(walletTransaction): case let .completed(walletTransaction):
let transferredValue = walletTransaction.transferredValueWithoutFees let transferredValue = walletTransaction.transferredValueWithoutFees
var text = "" var text = ""
var isEncrypted = false
if transferredValue <= 0 { if transferredValue <= 0 {
for message in walletTransaction.outMessages { for message in walletTransaction.outMessages {
if !text.isEmpty { if !text.isEmpty {
@ -110,7 +137,8 @@ private func extractDescription(_ walletTransaction: WalletInfoTransaction) -> S
case .raw: case .raw:
break break
case .encryptedText: case .encryptedText:
text.append("<encrypted>") text.append("Encrypted Comment")
isEncrypted = true
case let .plainText(plainText): case let .plainText(plainText):
text.append(plainText) text.append(plainText)
} }
@ -121,15 +149,16 @@ private func extractDescription(_ walletTransaction: WalletInfoTransaction) -> S
case .raw: case .raw:
text = "" text = ""
case .encryptedText: case .encryptedText:
text = "<encrypted>" text = "Encrypted Comment"
isEncrypted = true
case let .plainText(plainText): case let .plainText(plainText):
text = plainText text = plainText
} }
} }
} }
return text return (text, isEncrypted)
case let .pending(pending): case let .pending(pending):
return String(data: pending.comment, encoding: .utf8) ?? "" return (String(data: pending.comment, encoding: .utf8) ?? "", false)
} }
} }
@ -160,7 +189,7 @@ private func messageBubbleImage(incoming: Bool, fillColor: UIColor, strokeColor:
final class WalletTransactionInfoScreen: ViewController { final class WalletTransactionInfoScreen: ViewController {
private let context: WalletContext private let context: WalletContext
private let walletInfo: WalletInfo? private let walletInfo: WalletInfo?
private let walletTransaction: WalletInfoTransaction private var walletTransaction: WalletInfoTransaction
private let walletState: Signal<(CombinedWalletState, Bool), NoError> private let walletState: Signal<(CombinedWalletState, Bool), NoError>
private var presentationData: WalletPresentationData private var presentationData: WalletPresentationData
@ -234,6 +263,39 @@ final class WalletTransactionInfoScreen: ViewController {
} }
} }
} }
(self.displayNode as! WalletTransactionInfoScreenNode).requestDecryption = { [weak self] in
guard let strongSelf = self, let walletInfo = strongSelf.walletInfo, case let .completed(walletTransaction) = strongSelf.walletTransaction else {
return
}
let keychain = strongSelf.context.keychain
let _ = (strongSelf.context.getServerSalt()
|> map(Optional.init)
|> `catch` { _ -> Signal<Data?, NoError> in
return .single(nil)
}
|> mapToSignal { serverSalt -> Signal<WalletTransactionDecryptionKey?, NoError> in
guard let serverSalt = serverSalt else {
return .single(nil)
}
return walletTransactionDecryptionKey(keychain: keychain, walletInfo: walletInfo, localPassword: serverSalt)
}
|> deliverOnMainQueue).start(next: { decryptionKey in
guard let strongSelf = self else {
return
}
if let decryptionKey = decryptionKey {
let _ = (decryptWalletTransactions(decryptionKey: decryptionKey, transactions: [walletTransaction], tonInstance: strongSelf.context.tonInstance)
|> deliverOnMainQueue).start(next: { result in
guard let strongSelf = self, let updatedTransaction = result.first else {
return
}
strongSelf.walletTransaction = .completed(updatedTransaction)
(strongSelf.displayNode as! WalletTransactionInfoScreenNode).updateTransaction(strongSelf.walletTransaction)
(strongSelf.navigationController as? NavigationController)?.requestLayout(transition: .immediate)
})
}
})
}
(self.displayNode as! WalletTransactionInfoScreenNode).displayFeesTooltip = { [weak self] node, rect in (self.displayNode as! WalletTransactionInfoScreenNode).displayFeesTooltip = { [weak self] node, rect in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -255,7 +317,7 @@ final class WalletTransactionInfoScreen: ViewController {
} }
} }
strongSelf.present(controller, in: .window(.root), with: TooltipControllerPresentationArguments(sourceViewAndRect: { strongSelf.present(controller, in: .window(.root), with: TooltipControllerPresentationArguments(sourceViewAndRect: {
if let strongSelf = self { if let _ = self {
return (node.view, rect.insetBy(dx: 0.0, dy: -4.0)) return (node.view, rect.insetBy(dx: 0.0, dy: -4.0))
} }
return nil return nil
@ -286,7 +348,8 @@ final class WalletTransactionInfoScreen: ViewController {
let minHeight: CGFloat = 424.0 let minHeight: CGFloat = 424.0
let maxHeight: CGFloat = min(596.0, layout.size.height) let maxHeight: CGFloat = min(596.0, layout.size.height)
let text = NSAttributedString(string: extractDescription(self.walletTransaction), font: Font.regular(17.0), textColor: .black) let (plainText, textIsEncrypted) = extractDescription(self.walletTransaction)
let text = NSAttributedString(string: plainText, font: textIsEncrypted ? Font.monospace(17.0) : Font.regular(17.0), textColor: .black)
let makeTextLayout = TextNode.asyncLayout(self.measureTextNode) let makeTextLayout = TextNode.asyncLayout(self.measureTextNode)
let (textLayout, _) = makeTextLayout(TextNodeLayoutArguments(attributedString: text, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: layout.size.width - 36.0 * 2.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (textLayout, _) = makeTextLayout(TextNodeLayoutArguments(attributedString: text, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: layout.size.width - 36.0 * 2.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
@ -296,7 +359,13 @@ final class WalletTransactionInfoScreen: ViewController {
let minOverscroll: CGFloat = 42.0 let minOverscroll: CGFloat = 42.0
let maxOverscroll: CGFloat = 148.0 let maxOverscroll: CGFloat = 148.0
let contentHeight = minHeight + textHeight var contentHeight = minHeight + textHeight
if textIsEncrypted {
let (decryptTextLayout, _) = TextNode.asyncLayout(nil)(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Decrypt", font: Font.regular(17.0), textColor: presentationData.theme.list.itemAccentColor), maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: layout.size.width - 40.0, height: .greatestFiniteMagnitude), alignment: .center, insets: UIEdgeInsets()))
contentHeight += 10.0 + decryptTextLayout.size.height + 10.0
}
let difference = contentHeight - maxHeight let difference = contentHeight - maxHeight
if difference < 0.0 { if difference < 0.0 {
resultHeight = contentHeight resultHeight = contentHeight
@ -329,7 +398,7 @@ private let fractionalFont = Font.medium(24.0)
private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate { private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate {
private let context: WalletContext private let context: WalletContext
private var presentationData: WalletPresentationData private var presentationData: WalletPresentationData
private let walletTransaction: WalletInfoTransaction private var walletTransaction: WalletInfoTransaction
private let incoming: Bool private let incoming: Bool
private let titleNode: ImmediateTextNode private let titleNode: ImmediateTextNode
@ -345,12 +414,15 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
private let commentBackgroundNode: ASImageNode private let commentBackgroundNode: ASImageNode
private let commentTextNode: ImmediateTextNode private let commentTextNode: ImmediateTextNode
private let commentSeparatorNode: ASDisplayNode private let commentSeparatorNode: ASDisplayNode
private let commentDecryptButtonTitle: ImmediateTextNode
private let commentDecryptButton: HighlightableButtonNode
private let addressTextNode: ImmediateTextNode private let addressTextNode: ImmediateTextNode
private let buttonNode: SolidRoundedButtonNode private let buttonNode: SolidRoundedButtonNode
private var validLayout: (ContainerViewLayout, CGFloat)? private var validLayout: (ContainerViewLayout, CGFloat)?
var send: ((String) -> Void)? var send: ((String) -> Void)?
var requestDecryption: (() -> Void)?
var displayFeesTooltip: ((ASDisplayNode, CGRect) -> Void)? var displayFeesTooltip: ((ASDisplayNode, CGRect) -> Void)?
var displayCopyContextMenu: ((ASDisplayNode, CGRect, String) -> Void)? var displayCopyContextMenu: ((ASDisplayNode, CGRect, String) -> Void)?
@ -401,6 +473,15 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
self.commentSeparatorNode = ASDisplayNode() self.commentSeparatorNode = ASDisplayNode()
self.commentSeparatorNode.backgroundColor = self.presentationData.theme.list.itemPlainSeparatorColor self.commentSeparatorNode.backgroundColor = self.presentationData.theme.list.itemPlainSeparatorColor
self.commentDecryptButtonTitle = ImmediateTextNode()
self.commentDecryptButtonTitle.attributedText = NSAttributedString(string: "Decrypt", font: Font.regular(17.0), textColor: presentationData.theme.list.itemAccentColor)
self.commentDecryptButtonTitle.textAlignment = .natural
self.commentDecryptButtonTitle.maximumNumberOfLines = 0
self.commentDecryptButtonTitle.isUserInteractionEnabled = false
self.commentDecryptButton = HighlightableButtonNode()
self.commentDecryptButton.hitTestSlop = UIEdgeInsets(top: -10.0, left: -10.0, bottom: -10.0, right: -10.0)
self.addressTextNode = ImmediateTextNode() self.addressTextNode = ImmediateTextNode()
self.addressTextNode.maximumNumberOfLines = 4 self.addressTextNode.maximumNumberOfLines = 4
self.addressTextNode.textAlignment = .justified self.addressTextNode.textAlignment = .justified
@ -438,8 +519,12 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
self.addSubnode(self.timeNode) self.addSubnode(self.timeNode)
self.addSubnode(self.amountNode) self.addSubnode(self.amountNode)
self.addSubnode(self.commentSeparatorNode) self.addSubnode(self.commentSeparatorNode)
self.commentDecryptButton.addSubnode(self.commentDecryptButtonTitle)
self.scrollNode.addSubnode(self.commentDecryptButton)
self.addSubnode(self.addressTextNode) self.addSubnode(self.addressTextNode)
self.addSubnode(self.buttonNode) self.addSubnode(self.buttonNode)
self.commentDecryptButton.isHidden = !walletTransaction.isEncrypted
let titleFont = Font.semibold(17.0) let titleFont = Font.semibold(17.0)
let subtitleFont = Font.regular(13.0) let subtitleFont = Font.regular(13.0)
@ -485,7 +570,8 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
commentBackgroundColor = UIColor(rgb: 0xf1f1f4) commentBackgroundColor = UIColor(rgb: 0xf1f1f4)
} }
self.commentBackgroundNode.image = messageBubbleImage(incoming: transferredValue > 0, fillColor: commentBackgroundColor, strokeColor: presentationData.theme.transaction.descriptionBackgroundColor) self.commentBackgroundNode.image = messageBubbleImage(incoming: transferredValue > 0, fillColor: commentBackgroundColor, strokeColor: presentationData.theme.transaction.descriptionBackgroundColor)
self.commentTextNode.attributedText = NSAttributedString(string: extractDescription(walletTransaction), font: Font.regular(17.0), textColor: presentationData.theme.transaction.descriptionTextColor) let (plainText, textIsEncrypted) = extractDescription(walletTransaction)
self.commentTextNode.attributedText = NSAttributedString(string: plainText, font: textIsEncrypted ? Font.monospace(17.0) : Font.regular(17.0), textColor: presentationData.theme.transaction.descriptionTextColor)
let address = extractAddress(walletTransaction) let address = extractAddress(walletTransaction)
var singleAddress: String? var singleAddress: String?
@ -501,6 +587,21 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
self?.send?(address) self?.send?(address)
} }
} }
self.commentDecryptButton.addTarget(self, action: #selector(self.decryptCommentPressed), forControlEvents: .touchUpInside)
}
@objc private func decryptCommentPressed() {
self.requestDecryption?()
}
func updateTransaction(_ walletTransaction: WalletInfoTransaction) {
self.walletTransaction = walletTransaction
let (plainText, textIsEncrypted) = extractDescription(walletTransaction)
self.commentTextNode.attributedText = NSAttributedString(string: plainText, font: textIsEncrypted ? Font.monospace(17.0) : Font.regular(17.0), textColor: presentationData.theme.transaction.descriptionTextColor)
self.commentDecryptButton.isHidden = !walletTransaction.isEncrypted
} }
override func didLoad() { override func didLoad() {
@ -509,15 +610,17 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
self.scrollNode.view.delegate = self self.scrollNode.view.delegate = self
self.scrollNode.view.alwaysBounceVertical = true self.scrollNode.view.alwaysBounceVertical = true
self.scrollNode.view.showsVerticalScrollIndicator = false self.scrollNode.view.showsVerticalScrollIndicator = false
self.scrollNode.view.delaysContentTouches = false
self.scrollNode.view.canCancelContentTouches = true
let commentGestureRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapCommentGesture(_:))) let commentGestureRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapCommentGesture(_:)))
commentGestureRecognizer.tapActionAtPoint = { [weak self] point in commentGestureRecognizer.tapActionAtPoint = { point in
return .waitForSingleTap return .waitForSingleTap
} }
self.commentBackgroundNode.view.addGestureRecognizer(commentGestureRecognizer) self.commentBackgroundNode.view.addGestureRecognizer(commentGestureRecognizer)
let addressGestureRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapAddressGesture(_:))) let addressGestureRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapAddressGesture(_:)))
addressGestureRecognizer.tapActionAtPoint = { [weak self] point in addressGestureRecognizer.tapActionAtPoint = { point in
return .waitForSingleTap return .waitForSingleTap
} }
self.addressTextNode.view.addGestureRecognizer(addressGestureRecognizer) self.addressTextNode.view.addGestureRecognizer(addressGestureRecognizer)
@ -526,10 +629,10 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
@objc func tapLongTapOrDoubleTapCommentGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { @objc func tapLongTapOrDoubleTapCommentGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
switch recognizer.state { switch recognizer.state {
case .ended: case .ended:
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation {
switch gesture { switch gesture {
case .longTap: case .longTap:
let description = extractDescription(self.walletTransaction) let (description, _) = extractDescription(self.walletTransaction)
if !description.isEmpty { if !description.isEmpty {
self.displayCopyContextMenu?(self, self.commentBackgroundNode.convert(self.commentBackgroundNode.bounds, to: self), description) self.displayCopyContextMenu?(self, self.commentBackgroundNode.convert(self.commentBackgroundNode.bounds, to: self), description)
} }
@ -545,7 +648,7 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
@objc func tapLongTapOrDoubleTapAddressGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { @objc func tapLongTapOrDoubleTapAddressGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
switch recognizer.state { switch recognizer.state {
case .ended: case .ended:
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation {
switch gesture { switch gesture {
case .longTap: case .longTap:
let address = extractAddress(self.walletTransaction) let address = extractAddress(self.walletTransaction)
@ -668,7 +771,7 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
let buttonHeight: CGFloat = 50.0 let buttonHeight: CGFloat = 50.0
let buttonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonWidth) / 2.0), y: layout.size.height - bottomInset - buttonHeight), size: CGSize(width: buttonWidth, height: buttonHeight)) let buttonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonWidth) / 2.0), y: layout.size.height - bottomInset - buttonHeight), size: CGSize(width: buttonWidth, height: buttonHeight))
transition.updateFrame(node: self.buttonNode, frame: buttonFrame) transition.updateFrame(node: self.buttonNode, frame: buttonFrame)
self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition) let _ = self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition)
let addressSize = self.addressTextNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: CGFloat.greatestFiniteMagnitude)) let addressSize = self.addressTextNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: CGFloat.greatestFiniteMagnitude))
let addressFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - addressSize.width) / 2.0), y: buttonFrame.minY - addressSize.height - 34.0), size: addressSize) let addressFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - addressSize.width) / 2.0), y: buttonFrame.minY - addressSize.height - 34.0), size: addressSize)
@ -695,7 +798,18 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
} }
transition.updateFrame(node: self.commentBackgroundNode, frame: commentBackgroundFrame) transition.updateFrame(node: self.commentBackgroundNode, frame: commentBackgroundFrame)
let contentHeight = commentOrigin.y + commentBackgroundFrame.height var commentMaxY = commentOrigin.y + commentBackgroundFrame.height
let decryptSize = self.commentDecryptButtonTitle.updateLayout(CGSize(width: layout.size.width - 40.0, height: .greatestFiniteMagnitude))
let decryptButtonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - decryptSize.width) / 2.0), y: commentMaxY + 10.0), size: decryptSize)
transition.updateFrame(node: self.commentDecryptButton, frame: decryptButtonFrame)
transition.updateFrame(node: self.commentDecryptButtonTitle, frame: CGRect(origin: CGPoint(), size: decryptSize))
if self.walletTransaction.isEncrypted {
commentMaxY = decryptButtonFrame.maxY + 10.0
}
let contentHeight = commentMaxY
self.scrollNode.view.contentSize = CGSize(width: layout.size.width, height: contentHeight) self.scrollNode.view.contentSize = CGSize(width: layout.size.width, height: contentHeight)
let isScrollEnabled = contentHeight - scrollFrame.height > 20.0 let isScrollEnabled = contentHeight - scrollFrame.height > 20.0

View File

@ -82,7 +82,6 @@ func isValidAmount(_ amount: String) -> Bool {
return false return false
} }
var hasDecimalSeparator = false var hasDecimalSeparator = false
var hasLeadingZero = false
var index = 0 var index = 0
for c in amount { for c in amount {
if c == "." || c == "," { if c == "." || c == "," {

View File

@ -321,11 +321,8 @@ private final class WalletWordDisplayScreenNode: ViewControllerTracingNode, UISc
contentHeight = textFrame.maxY + textSpacing contentHeight = textFrame.maxY + textSpacing
let rowWidth = layout.size.width - buttonSideInset * 2.0
let rowCount = self.wordNodes.count / 2 let rowCount = self.wordNodes.count / 2
let indexWidth: CGFloat = 16.0
var wordSizes: [(CGSize, CGSize)] = [] var wordSizes: [(CGSize, CGSize)] = []
var columnIndexWidth: [CGFloat] = [0.0, 0.0] var columnIndexWidth: [CGFloat] = [0.0, 0.0]
var columnWordWidth: [CGFloat] = [0.0, 0.0] var columnWordWidth: [CGFloat] = [0.0, 0.0]
@ -371,16 +368,14 @@ private final class WalletWordDisplayScreenNode: ViewControllerTracingNode, UISc
} }
} }
let minimalFullscreenBottomInset: CGFloat = 74.0
let minimalScrollBottomInset: CGFloat = 30.0 let minimalScrollBottomInset: CGFloat = 30.0
let fullscreenBottomInset = layout.intrinsicInsets.bottom + minimalFullscreenBottomInset
let scrollBottomInset = layout.intrinsicInsets.bottom + minimalScrollBottomInset let scrollBottomInset = layout.intrinsicInsets.bottom + minimalScrollBottomInset
let buttonWidth = layout.size.width - buttonSideInset * 2.0 let buttonWidth = layout.size.width - buttonSideInset * 2.0
let buttonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonWidth) / 2.0), y: max(contentHeight + buttonSpacing, layout.size.height - scrollBottomInset - buttonHeight)), size: CGSize(width: buttonWidth, height: buttonHeight)) let buttonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonWidth) / 2.0), y: max(contentHeight + buttonSpacing, layout.size.height - scrollBottomInset - buttonHeight)), size: CGSize(width: buttonWidth, height: buttonHeight))
transition.updateFrame(node: self.buttonNode, frame: buttonFrame) transition.updateFrame(node: self.buttonNode, frame: buttonFrame)
self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition) let _ = self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition)
self.scrollNode.view.contentSize = CGSize(width: layout.size.width, height: max(layout.size.height, buttonFrame.maxY + scrollBottomInset)) self.scrollNode.view.contentSize = CGSize(width: layout.size.width, height: max(layout.size.height, buttonFrame.maxY + scrollBottomInset))
@ -395,7 +390,7 @@ private final class WalletWordDisplayScreenNode: ViewControllerTracingNode, UISc
if let path = getAppBundle().path(forResource: "WalletApologiesAccepted", ofType: "tgs") { if let path = getAppBundle().path(forResource: "WalletApologiesAccepted", ofType: "tgs") {
let toastNode = ToastNode(theme: self.presentationData.theme, animationPath: path, text: self.presentationData.strings.Wallet_Words_NotDoneResponse) let toastNode = ToastNode(theme: self.presentationData.theme, animationPath: path, text: self.presentationData.strings.Wallet_Words_NotDoneResponse)
self.toastNode = toastNode self.toastNode = toastNode
if let (layout, navigationHeight) = self.validLayout { if let (layout, _) = self.validLayout {
toastNode.update(layout: layout, transition: .immediate) toastNode.update(layout: layout, transition: .immediate)
} }
self.addSubnode(toastNode) self.addSubnode(toastNode)

View File

@ -1,4 +1,4 @@
load("//build-system:unique_directories.bzl", "unique_directories") load("//build-system/bazel-utils:unique_directories.bzl", "unique_directories")
private_headers = glob([ private_headers = glob([
"lottie-ios/**/*.h", "lottie-ios/**/*.h",

View File

@ -48,6 +48,7 @@ set(TON_CRYPTO_SOURCE
common/refint.h common/refint.h
common/bigexp.h common/bigexp.h
common/util.h common/util.h
common/linalloc.hpp
ellcurve/Ed25519.h ellcurve/Ed25519.h
ellcurve/Fp25519.h ellcurve/Fp25519.h
@ -390,7 +391,7 @@ endif()
add_executable(create-state block/create-state.cpp) add_executable(create-state block/create-state.cpp)
target_include_directories(create-state PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> target_include_directories(create-state PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>) $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_link_libraries(create-state PUBLIC ton_crypto fift-lib ton_block) target_link_libraries(create-state PUBLIC ton_crypto fift-lib ton_block tonlib)
if (WINGETOPT_FOUND) if (WINGETOPT_FOUND)
target_link_libraries_system(create-state wingetopt) target_link_libraries_system(create-state wingetopt)
endif() endif()

View File

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "crypto/Ed25519.h" #include "crypto/Ed25519.h"
@ -310,6 +310,10 @@ Result<SecureString> Ed25519::compute_shared_secret(const PublicKey &public_key,
return std::move(result); return std::move(result);
} }
int Ed25519::version() {
return OPENSSL_VERSION_NUMBER;
}
#else #else
Result<Ed25519::PrivateKey> Ed25519::generate_private_key() { Result<Ed25519::PrivateKey> Ed25519::generate_private_key() {
@ -387,6 +391,10 @@ Result<SecureString> Ed25519::compute_shared_secret(const PublicKey &public_key,
return std::move(shared_secret); return std::move(shared_secret);
} }
int Ed25519::version() {
return 0;
}
#endif #endif
} // namespace td } // namespace td

View File

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License 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/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#pragma once #pragma once
@ -65,6 +65,8 @@ class Ed25519 {
static Result<PrivateKey> generate_private_key(); static Result<PrivateKey> generate_private_key();
static Result<SecureString> compute_shared_secret(const PublicKey &public_key, const PrivateKey &private_key); static Result<SecureString> compute_shared_secret(const PublicKey &public_key, const PrivateKey &private_key);
static int version();
}; };
} // namespace td } // namespace td

View File

@ -14,6 +14,7 @@
// uses built-in type `uint` // uses built-in type `uint`
// uses built-in type `bits` // uses built-in type `bits`
// uses built-in type `int8` // uses built-in type `int8`
// uses built-in type `uint8`
// uses built-in type `uint13` // uses built-in type `uint13`
// uses built-in type `uint15` // uses built-in type `uint15`
// uses built-in type `int16` // uses built-in type `int16`
@ -23,6 +24,7 @@
// uses built-in type `uint63` // uses built-in type `uint63`
// uses built-in type `int64` // uses built-in type `int64`
// uses built-in type `uint64` // uses built-in type `uint64`
// uses built-in type `uint256`
// uses built-in type `int257` // uses built-in type `int257`
// uses built-in type `bits256` // uses built-in type `bits256`
@ -10686,38 +10688,42 @@ int BlockInfo::check_tag(const vm::CellSlice& cs) const {
} }
bool BlockInfo::skip(vm::CellSlice& cs) const { bool BlockInfo::skip(vm::CellSlice& cs) const {
int not_master, after_merge, vert_seqno_incr, seq_no, vert_seq_no, prev_seq_no; int not_master, after_merge, vert_seqno_incr, flags, seq_no, vert_seq_no, prev_seq_no;
return cs.advance(64) return cs.advance(64)
&& cs.fetch_bool_to(not_master) && cs.fetch_bool_to(not_master)
&& cs.fetch_bool_to(after_merge) && cs.fetch_bool_to(after_merge)
&& cs.advance(5) && cs.advance(5)
&& cs.fetch_bool_to(vert_seqno_incr) && cs.fetch_bool_to(vert_seqno_incr)
&& cs.advance(8) && cs.fetch_uint_to(8, flags)
&& flags <= 1
&& cs.fetch_uint_to(32, seq_no) && cs.fetch_uint_to(32, seq_no)
&& cs.fetch_uint_to(32, vert_seq_no) && cs.fetch_uint_to(32, vert_seq_no)
&& vert_seqno_incr <= vert_seq_no && vert_seqno_incr <= vert_seq_no
&& add_r1(prev_seq_no, 1, seq_no) && add_r1(prev_seq_no, 1, seq_no)
&& cs.advance(392) && cs.advance(392)
&& (!(flags & 1) || cs.advance(104))
&& (!not_master || cs.advance_refs(1)) && (!not_master || cs.advance_refs(1))
&& cs.advance_refs(1) && cs.advance_refs(1)
&& (!vert_seqno_incr || cs.advance_refs(1)); && (!vert_seqno_incr || cs.advance_refs(1));
} }
bool BlockInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { bool BlockInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
int not_master, after_merge, vert_seqno_incr, seq_no, vert_seq_no, prev_seq_no; int not_master, after_merge, vert_seqno_incr, flags, seq_no, vert_seq_no, prev_seq_no;
return cs.fetch_ulong(32) == 0x9bc7a987U return cs.fetch_ulong(32) == 0x9bc7a987U
&& cs.advance(32) && cs.advance(32)
&& cs.fetch_bool_to(not_master) && cs.fetch_bool_to(not_master)
&& cs.fetch_bool_to(after_merge) && cs.fetch_bool_to(after_merge)
&& cs.advance(5) && cs.advance(5)
&& cs.fetch_bool_to(vert_seqno_incr) && cs.fetch_bool_to(vert_seqno_incr)
&& cs.advance(8) && cs.fetch_uint_to(8, flags)
&& flags <= 1
&& cs.fetch_uint_to(32, seq_no) && cs.fetch_uint_to(32, seq_no)
&& cs.fetch_uint_to(32, vert_seq_no) && cs.fetch_uint_to(32, vert_seq_no)
&& vert_seqno_incr <= vert_seq_no && vert_seqno_incr <= vert_seq_no
&& add_r1(prev_seq_no, 1, seq_no) && add_r1(prev_seq_no, 1, seq_no)
&& t_ShardIdent.validate_skip(ops, cs, weak) && t_ShardIdent.validate_skip(ops, cs, weak)
&& cs.advance(288) && cs.advance(288)
&& (!(flags & 1) || t_GlobalVersion.validate_skip(ops, cs, weak))
&& (!not_master || t_BlkMasterInfo.validate_skip_ref(ops, cs, weak)) && (!not_master || t_BlkMasterInfo.validate_skip_ref(ops, cs, weak))
&& BlkPrevInfo{after_merge}.validate_skip_ref(ops, cs, weak) && BlkPrevInfo{after_merge}.validate_skip_ref(ops, cs, weak)
&& (!vert_seqno_incr || t_BlkPrevInfo_0.validate_skip_ref(ops, cs, weak)); && (!vert_seqno_incr || t_BlkPrevInfo_0.validate_skip_ref(ops, cs, weak));
@ -10736,6 +10742,7 @@ bool BlockInfo::unpack(vm::CellSlice& cs, BlockInfo::Record& data) const {
&& cs.fetch_bool_to(data.key_block) && cs.fetch_bool_to(data.key_block)
&& cs.fetch_bool_to(data.vert_seqno_incr) && cs.fetch_bool_to(data.vert_seqno_incr)
&& cs.fetch_uint_to(8, data.flags) && cs.fetch_uint_to(8, data.flags)
&& data.flags <= 1
&& cs.fetch_uint_to(32, data.seq_no) && cs.fetch_uint_to(32, data.seq_no)
&& cs.fetch_uint_to(32, data.vert_seq_no) && cs.fetch_uint_to(32, data.vert_seq_no)
&& data.vert_seqno_incr <= data.vert_seq_no && data.vert_seqno_incr <= data.vert_seq_no
@ -10748,6 +10755,7 @@ bool BlockInfo::unpack(vm::CellSlice& cs, BlockInfo::Record& data) const {
&& cs.fetch_uint_to(32, data.gen_catchain_seqno) && cs.fetch_uint_to(32, data.gen_catchain_seqno)
&& cs.fetch_uint_to(32, data.min_ref_mc_seqno) && cs.fetch_uint_to(32, data.min_ref_mc_seqno)
&& cs.fetch_uint_to(32, data.prev_key_block_seqno) && cs.fetch_uint_to(32, data.prev_key_block_seqno)
&& (!(data.flags & 1) || cs.fetch_subslice_to(104, data.gen_software))
&& (!data.not_master || cs.fetch_ref_to(data.master_ref)) && (!data.not_master || cs.fetch_ref_to(data.master_ref))
&& cs.fetch_ref_to(data.prev_ref) && cs.fetch_ref_to(data.prev_ref)
&& (!data.vert_seqno_incr || cs.fetch_ref_to(data.prev_vert_ref)); && (!data.vert_seqno_incr || cs.fetch_ref_to(data.prev_vert_ref));
@ -10772,6 +10780,7 @@ bool BlockInfo::pack(vm::CellBuilder& cb, const BlockInfo::Record& data) const {
&& cb.store_ulong_rchk_bool(data.key_block, 1) && cb.store_ulong_rchk_bool(data.key_block, 1)
&& cb.store_ulong_rchk_bool(data.vert_seqno_incr, 1) && cb.store_ulong_rchk_bool(data.vert_seqno_incr, 1)
&& cb.store_ulong_rchk_bool(data.flags, 8) && cb.store_ulong_rchk_bool(data.flags, 8)
&& data.flags <= 1
&& cb.store_ulong_rchk_bool(data.seq_no, 32) && cb.store_ulong_rchk_bool(data.seq_no, 32)
&& cb.store_ulong_rchk_bool(data.vert_seq_no, 32) && cb.store_ulong_rchk_bool(data.vert_seq_no, 32)
&& data.vert_seqno_incr <= data.vert_seq_no && data.vert_seqno_incr <= data.vert_seq_no
@ -10784,6 +10793,7 @@ bool BlockInfo::pack(vm::CellBuilder& cb, const BlockInfo::Record& data) const {
&& cb.store_ulong_rchk_bool(data.gen_catchain_seqno, 32) && cb.store_ulong_rchk_bool(data.gen_catchain_seqno, 32)
&& cb.store_ulong_rchk_bool(data.min_ref_mc_seqno, 32) && cb.store_ulong_rchk_bool(data.min_ref_mc_seqno, 32)
&& cb.store_ulong_rchk_bool(data.prev_key_block_seqno, 32) && cb.store_ulong_rchk_bool(data.prev_key_block_seqno, 32)
&& (!(data.flags & 1) || cb.append_cellslice_chk(data.gen_software, 104))
&& (!data.not_master || cb.store_ref_bool(data.master_ref)) && (!data.not_master || cb.store_ref_bool(data.master_ref))
&& cb.store_ref_bool(data.prev_ref) && cb.store_ref_bool(data.prev_ref)
&& (!data.vert_seqno_incr || cb.store_ref_bool(data.prev_vert_ref)); && (!data.vert_seqno_incr || cb.store_ref_bool(data.prev_vert_ref));
@ -10814,6 +10824,7 @@ bool BlockInfo::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
&& pp.field_int(vert_seqno_incr, "vert_seqno_incr") && pp.field_int(vert_seqno_incr, "vert_seqno_incr")
&& cs.fetch_uint_to(8, flags) && cs.fetch_uint_to(8, flags)
&& pp.field_int(flags, "flags") && pp.field_int(flags, "flags")
&& flags <= 1
&& cs.fetch_uint_to(32, seq_no) && cs.fetch_uint_to(32, seq_no)
&& pp.field_int(seq_no, "seq_no") && pp.field_int(seq_no, "seq_no")
&& cs.fetch_uint_to(32, vert_seq_no) && cs.fetch_uint_to(32, vert_seq_no)
@ -10829,6 +10840,7 @@ bool BlockInfo::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
&& pp.fetch_uint_field(cs, 32, "gen_catchain_seqno") && pp.fetch_uint_field(cs, 32, "gen_catchain_seqno")
&& pp.fetch_uint_field(cs, 32, "min_ref_mc_seqno") && pp.fetch_uint_field(cs, 32, "min_ref_mc_seqno")
&& pp.fetch_uint_field(cs, 32, "prev_key_block_seqno") && pp.fetch_uint_field(cs, 32, "prev_key_block_seqno")
&& (!(flags & 1) || (pp.field("gen_software") && t_GlobalVersion.print_skip(pp, cs)))
&& (!not_master || (pp.field("master_ref") && t_BlkMasterInfo.print_ref(pp, cs.fetch_ref()))) && (!not_master || (pp.field("master_ref") && t_BlkMasterInfo.print_ref(pp, cs.fetch_ref())))
&& pp.field("prev_ref") && pp.field("prev_ref")
&& BlkPrevInfo{after_merge}.print_ref(pp, cs.fetch_ref()) && BlkPrevInfo{after_merge}.print_ref(pp, cs.fetch_ref())
@ -14057,6 +14069,309 @@ bool GlobalVersion::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
const GlobalVersion t_GlobalVersion; const GlobalVersion t_GlobalVersion;
//
// code for type `ConfigProposalSetup`
//
constexpr unsigned char ConfigProposalSetup::cons_tag[1];
int ConfigProposalSetup::check_tag(const vm::CellSlice& cs) const {
return cs.prefetch_ulong(8) == 0x36 ? cfg_vote_cfg : -1;
}
bool ConfigProposalSetup::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
return cs.fetch_ulong(8) == 0x36
&& cs.advance(160);
}
bool ConfigProposalSetup::unpack(vm::CellSlice& cs, ConfigProposalSetup::Record& data) const {
return cs.fetch_ulong(8) == 0x36
&& cs.fetch_uint_to(8, data.min_tot_rounds)
&& cs.fetch_uint_to(8, data.max_tot_rounds)
&& cs.fetch_uint_to(8, data.min_wins)
&& cs.fetch_uint_to(8, data.max_losses)
&& cs.fetch_uint_to(32, data.min_store_sec)
&& cs.fetch_uint_to(32, data.max_store_sec)
&& cs.fetch_uint_to(32, data.bit_price)
&& cs.fetch_uint_to(32, data.cell_price);
}
bool ConfigProposalSetup::cell_unpack(Ref<vm::Cell> cell_ref, ConfigProposalSetup::Record& data) const {
if (cell_ref.is_null()) { return false; }
auto cs = load_cell_slice(std::move(cell_ref));
return unpack(cs, data) && cs.empty_ext();
}
bool ConfigProposalSetup::pack(vm::CellBuilder& cb, const ConfigProposalSetup::Record& data) const {
return cb.store_long_bool(0x36, 8)
&& cb.store_ulong_rchk_bool(data.min_tot_rounds, 8)
&& cb.store_ulong_rchk_bool(data.max_tot_rounds, 8)
&& cb.store_ulong_rchk_bool(data.min_wins, 8)
&& cb.store_ulong_rchk_bool(data.max_losses, 8)
&& cb.store_ulong_rchk_bool(data.min_store_sec, 32)
&& cb.store_ulong_rchk_bool(data.max_store_sec, 32)
&& cb.store_ulong_rchk_bool(data.bit_price, 32)
&& cb.store_ulong_rchk_bool(data.cell_price, 32);
}
bool ConfigProposalSetup::cell_pack(Ref<vm::Cell>& cell_ref, const ConfigProposalSetup::Record& data) const {
vm::CellBuilder cb;
return pack(cb, data) && std::move(cb).finalize_to(cell_ref);
}
bool ConfigProposalSetup::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
return cs.fetch_ulong(8) == 0x36
&& pp.open("cfg_vote_cfg")
&& pp.fetch_uint_field(cs, 8, "min_tot_rounds")
&& pp.fetch_uint_field(cs, 8, "max_tot_rounds")
&& pp.fetch_uint_field(cs, 8, "min_wins")
&& pp.fetch_uint_field(cs, 8, "max_losses")
&& pp.fetch_uint_field(cs, 32, "min_store_sec")
&& pp.fetch_uint_field(cs, 32, "max_store_sec")
&& pp.fetch_uint_field(cs, 32, "bit_price")
&& pp.fetch_uint_field(cs, 32, "cell_price")
&& pp.close();
}
const ConfigProposalSetup t_ConfigProposalSetup;
//
// code for type `ConfigVotingSetup`
//
constexpr unsigned char ConfigVotingSetup::cons_tag[1];
int ConfigVotingSetup::check_tag(const vm::CellSlice& cs) const {
return cs.prefetch_ulong(8) == 0x91 ? cfg_vote_setup : -1;
}
bool ConfigVotingSetup::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
return cs.fetch_ulong(8) == 0x91
&& t_ConfigProposalSetup.validate_skip_ref(ops, cs, weak)
&& t_ConfigProposalSetup.validate_skip_ref(ops, cs, weak);
}
bool ConfigVotingSetup::unpack(vm::CellSlice& cs, ConfigVotingSetup::Record& data) const {
return cs.fetch_ulong(8) == 0x91
&& cs.fetch_ref_to(data.normal_params)
&& cs.fetch_ref_to(data.critical_params);
}
bool ConfigVotingSetup::unpack_cfg_vote_setup(vm::CellSlice& cs, Ref<Cell>& normal_params, Ref<Cell>& critical_params) const {
return cs.fetch_ulong(8) == 0x91
&& cs.fetch_ref_to(normal_params)
&& cs.fetch_ref_to(critical_params);
}
bool ConfigVotingSetup::cell_unpack(Ref<vm::Cell> cell_ref, ConfigVotingSetup::Record& data) const {
if (cell_ref.is_null()) { return false; }
auto cs = load_cell_slice(std::move(cell_ref));
return unpack(cs, data) && cs.empty_ext();
}
bool ConfigVotingSetup::cell_unpack_cfg_vote_setup(Ref<vm::Cell> cell_ref, Ref<Cell>& normal_params, Ref<Cell>& critical_params) const {
if (cell_ref.is_null()) { return false; }
auto cs = load_cell_slice(std::move(cell_ref));
return unpack_cfg_vote_setup(cs, normal_params, critical_params) && cs.empty_ext();
}
bool ConfigVotingSetup::pack(vm::CellBuilder& cb, const ConfigVotingSetup::Record& data) const {
return cb.store_long_bool(0x91, 8)
&& cb.store_ref_bool(data.normal_params)
&& cb.store_ref_bool(data.critical_params);
}
bool ConfigVotingSetup::pack_cfg_vote_setup(vm::CellBuilder& cb, Ref<Cell> normal_params, Ref<Cell> critical_params) const {
return cb.store_long_bool(0x91, 8)
&& cb.store_ref_bool(normal_params)
&& cb.store_ref_bool(critical_params);
}
bool ConfigVotingSetup::cell_pack(Ref<vm::Cell>& cell_ref, const ConfigVotingSetup::Record& data) const {
vm::CellBuilder cb;
return pack(cb, data) && std::move(cb).finalize_to(cell_ref);
}
bool ConfigVotingSetup::cell_pack_cfg_vote_setup(Ref<vm::Cell>& cell_ref, Ref<Cell> normal_params, Ref<Cell> critical_params) const {
vm::CellBuilder cb;
return pack_cfg_vote_setup(cb, std::move(normal_params), std::move(critical_params)) && std::move(cb).finalize_to(cell_ref);
}
bool ConfigVotingSetup::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
return cs.fetch_ulong(8) == 0x91
&& pp.open("cfg_vote_setup")
&& pp.field("normal_params")
&& t_ConfigProposalSetup.print_ref(pp, cs.fetch_ref())
&& pp.field("critical_params")
&& t_ConfigProposalSetup.print_ref(pp, cs.fetch_ref())
&& pp.close();
}
const ConfigVotingSetup t_ConfigVotingSetup;
//
// code for type `ConfigProposal`
//
constexpr unsigned char ConfigProposal::cons_tag[1];
int ConfigProposal::check_tag(const vm::CellSlice& cs) const {
return cs.prefetch_ulong(8) == 0xf3 ? cfg_proposal : -1;
}
bool ConfigProposal::skip(vm::CellSlice& cs) const {
return cs.advance(40)
&& t_Maybe_Ref_Cell.skip(cs)
&& t_Maybe_uint256.skip(cs);
}
bool ConfigProposal::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
return cs.fetch_ulong(8) == 0xf3
&& cs.advance(32)
&& t_Maybe_Ref_Cell.validate_skip(ops, cs, weak)
&& t_Maybe_uint256.validate_skip(ops, cs, weak);
}
bool ConfigProposal::unpack(vm::CellSlice& cs, ConfigProposal::Record& data) const {
return cs.fetch_ulong(8) == 0xf3
&& cs.fetch_int_to(32, data.param_id)
&& t_Maybe_Ref_Cell.fetch_to(cs, data.param_value)
&& t_Maybe_uint256.fetch_to(cs, data.if_hash_equal);
}
bool ConfigProposal::unpack_cfg_proposal(vm::CellSlice& cs, int& param_id, Ref<CellSlice>& param_value, Ref<CellSlice>& if_hash_equal) const {
return cs.fetch_ulong(8) == 0xf3
&& cs.fetch_int_to(32, param_id)
&& t_Maybe_Ref_Cell.fetch_to(cs, param_value)
&& t_Maybe_uint256.fetch_to(cs, if_hash_equal);
}
bool ConfigProposal::cell_unpack(Ref<vm::Cell> cell_ref, ConfigProposal::Record& data) const {
if (cell_ref.is_null()) { return false; }
auto cs = load_cell_slice(std::move(cell_ref));
return unpack(cs, data) && cs.empty_ext();
}
bool ConfigProposal::cell_unpack_cfg_proposal(Ref<vm::Cell> cell_ref, int& param_id, Ref<CellSlice>& param_value, Ref<CellSlice>& if_hash_equal) const {
if (cell_ref.is_null()) { return false; }
auto cs = load_cell_slice(std::move(cell_ref));
return unpack_cfg_proposal(cs, param_id, param_value, if_hash_equal) && cs.empty_ext();
}
bool ConfigProposal::pack(vm::CellBuilder& cb, const ConfigProposal::Record& data) const {
return cb.store_long_bool(0xf3, 8)
&& cb.store_long_rchk_bool(data.param_id, 32)
&& t_Maybe_Ref_Cell.store_from(cb, data.param_value)
&& t_Maybe_uint256.store_from(cb, data.if_hash_equal);
}
bool ConfigProposal::pack_cfg_proposal(vm::CellBuilder& cb, int param_id, Ref<CellSlice> param_value, Ref<CellSlice> if_hash_equal) const {
return cb.store_long_bool(0xf3, 8)
&& cb.store_long_rchk_bool(param_id, 32)
&& t_Maybe_Ref_Cell.store_from(cb, param_value)
&& t_Maybe_uint256.store_from(cb, if_hash_equal);
}
bool ConfigProposal::cell_pack(Ref<vm::Cell>& cell_ref, const ConfigProposal::Record& data) const {
vm::CellBuilder cb;
return pack(cb, data) && std::move(cb).finalize_to(cell_ref);
}
bool ConfigProposal::cell_pack_cfg_proposal(Ref<vm::Cell>& cell_ref, int param_id, Ref<CellSlice> param_value, Ref<CellSlice> if_hash_equal) const {
vm::CellBuilder cb;
return pack_cfg_proposal(cb, param_id, std::move(param_value), std::move(if_hash_equal)) && std::move(cb).finalize_to(cell_ref);
}
bool ConfigProposal::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
return cs.fetch_ulong(8) == 0xf3
&& pp.open("cfg_proposal")
&& pp.fetch_int_field(cs, 32, "param_id")
&& pp.field("param_value")
&& t_Maybe_Ref_Cell.print_skip(pp, cs)
&& pp.field("if_hash_equal")
&& t_Maybe_uint256.print_skip(pp, cs)
&& pp.close();
}
const ConfigProposal t_ConfigProposal;
//
// code for type `ConfigProposalStatus`
//
constexpr unsigned char ConfigProposalStatus::cons_tag[1];
int ConfigProposalStatus::check_tag(const vm::CellSlice& cs) const {
return cs.prefetch_ulong(8) == 0xce ? cfg_proposal_status : -1;
}
bool ConfigProposalStatus::skip(vm::CellSlice& cs) const {
return cs.advance_ext(0x10029)
&& t_HashmapE_16_True.skip(cs)
&& cs.advance(344);
}
bool ConfigProposalStatus::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
return cs.fetch_ulong(8) == 0xce
&& cs.advance(32)
&& t_ConfigProposal.validate_skip_ref(ops, cs, weak)
&& cs.advance(1)
&& t_HashmapE_16_True.validate_skip(ops, cs, weak)
&& cs.advance(344);
}
bool ConfigProposalStatus::unpack(vm::CellSlice& cs, ConfigProposalStatus::Record& data) const {
return cs.fetch_ulong(8) == 0xce
&& cs.fetch_uint_to(32, data.expires)
&& cs.fetch_ref_to(data.proposal)
&& cs.fetch_bool_to(data.is_critical)
&& t_HashmapE_16_True.fetch_to(cs, data.voters)
&& cs.fetch_int_to(64, data.remaining_weight)
&& cs.fetch_uint256_to(256, data.validator_set_id)
&& cs.fetch_uint_to(8, data.rounds_remaining)
&& cs.fetch_uint_to(8, data.wins)
&& cs.fetch_uint_to(8, data.losses);
}
bool ConfigProposalStatus::cell_unpack(Ref<vm::Cell> cell_ref, ConfigProposalStatus::Record& data) const {
if (cell_ref.is_null()) { return false; }
auto cs = load_cell_slice(std::move(cell_ref));
return unpack(cs, data) && cs.empty_ext();
}
bool ConfigProposalStatus::pack(vm::CellBuilder& cb, const ConfigProposalStatus::Record& data) const {
return cb.store_long_bool(0xce, 8)
&& cb.store_ulong_rchk_bool(data.expires, 32)
&& cb.store_ref_bool(data.proposal)
&& cb.store_ulong_rchk_bool(data.is_critical, 1)
&& t_HashmapE_16_True.store_from(cb, data.voters)
&& cb.store_long_rchk_bool(data.remaining_weight, 64)
&& cb.store_int256_bool(data.validator_set_id, 256, false)
&& cb.store_ulong_rchk_bool(data.rounds_remaining, 8)
&& cb.store_ulong_rchk_bool(data.wins, 8)
&& cb.store_ulong_rchk_bool(data.losses, 8);
}
bool ConfigProposalStatus::cell_pack(Ref<vm::Cell>& cell_ref, const ConfigProposalStatus::Record& data) const {
vm::CellBuilder cb;
return pack(cb, data) && std::move(cb).finalize_to(cell_ref);
}
bool ConfigProposalStatus::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
return cs.fetch_ulong(8) == 0xce
&& pp.open("cfg_proposal_status")
&& pp.fetch_uint_field(cs, 32, "expires")
&& pp.field("proposal")
&& t_ConfigProposal.print_ref(pp, cs.fetch_ref())
&& pp.fetch_uint_field(cs, 1, "is_critical")
&& pp.field("voters")
&& t_HashmapE_16_True.print_skip(pp, cs)
&& pp.fetch_int_field(cs, 64, "remaining_weight")
&& pp.fetch_uint256_field(cs, 256, "validator_set_id")
&& pp.fetch_uint_field(cs, 8, "rounds_remaining")
&& pp.fetch_uint_field(cs, 8, "wins")
&& pp.fetch_uint_field(cs, 8, "losses")
&& pp.close();
}
const ConfigProposalStatus t_ConfigProposalStatus;
// //
// code for type `WorkchainFormat` // code for type `WorkchainFormat`
// //
@ -15219,6 +15534,10 @@ int ConfigParam::get_tag(const vm::CellSlice& cs) const {
return cons8; return cons8;
case 9: case 9:
return cons9; return cons9;
case 10:
return cons10;
case 11:
return cons11;
case 12: case 12:
return cons12; return cons12;
case 14: case 14:
@ -15288,6 +15607,10 @@ int ConfigParam::check_tag(const vm::CellSlice& cs) const {
return cons8; return cons8;
case cons9: case cons9:
return cons9; return cons9;
case cons10:
return cons10;
case cons11:
return cons11;
case cons12: case cons12:
return cons12; return cons12;
case cons14: case cons14:
@ -15366,6 +15689,12 @@ bool ConfigParam::skip(vm::CellSlice& cs) const {
case cons9: case cons9:
return t_Hashmap_32_True.skip(cs) return t_Hashmap_32_True.skip(cs)
&& m_ == 9; && m_ == 9;
case cons10:
return t_Hashmap_32_True.skip(cs)
&& m_ == 10;
case cons11:
return cs.advance_ext(0x20008)
&& m_ == 11;
case cons12: case cons12:
return t_HashmapE_32_WorkchainDescr.skip(cs) return t_HashmapE_32_WorkchainDescr.skip(cs)
&& m_ == 12; && m_ == 12;
@ -15476,6 +15805,12 @@ bool ConfigParam::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
case cons9: case cons9:
return t_Hashmap_32_True.validate_skip(ops, cs, weak) return t_Hashmap_32_True.validate_skip(ops, cs, weak)
&& m_ == 9; && m_ == 9;
case cons10:
return t_Hashmap_32_True.validate_skip(ops, cs, weak)
&& m_ == 10;
case cons11:
return t_ConfigVotingSetup.validate_skip(ops, cs, weak)
&& m_ == 11;
case cons12: case cons12:
return t_HashmapE_32_WorkchainDescr.validate_skip(ops, cs, weak) return t_HashmapE_32_WorkchainDescr.validate_skip(ops, cs, weak)
&& m_ == 12; && m_ == 12;
@ -15756,6 +16091,50 @@ bool ConfigParam::cell_unpack_cons9(Ref<vm::Cell> cell_ref, Ref<CellSlice>& mand
return unpack_cons9(cs, mandatory_params) && cs.empty_ext(); return unpack_cons9(cs, mandatory_params) && cs.empty_ext();
} }
bool ConfigParam::unpack(vm::CellSlice& cs, ConfigParam::Record_cons10& data) const {
return t_Hashmap_32_True.fetch_to(cs, data.critical_params)
&& m_ == 10;
}
bool ConfigParam::unpack_cons10(vm::CellSlice& cs, Ref<CellSlice>& critical_params) const {
return t_Hashmap_32_True.fetch_to(cs, critical_params)
&& m_ == 10;
}
bool ConfigParam::cell_unpack(Ref<vm::Cell> cell_ref, ConfigParam::Record_cons10& data) const {
if (cell_ref.is_null()) { return false; }
auto cs = load_cell_slice(std::move(cell_ref));
return unpack(cs, data) && cs.empty_ext();
}
bool ConfigParam::cell_unpack_cons10(Ref<vm::Cell> cell_ref, Ref<CellSlice>& critical_params) const {
if (cell_ref.is_null()) { return false; }
auto cs = load_cell_slice(std::move(cell_ref));
return unpack_cons10(cs, critical_params) && cs.empty_ext();
}
bool ConfigParam::unpack(vm::CellSlice& cs, ConfigParam::Record_cons11& data) const {
return cs.fetch_subslice_ext_to(0x20008, data.x)
&& m_ == 11;
}
bool ConfigParam::unpack_cons11(vm::CellSlice& cs, Ref<CellSlice>& x) const {
return cs.fetch_subslice_ext_to(0x20008, x)
&& m_ == 11;
}
bool ConfigParam::cell_unpack(Ref<vm::Cell> cell_ref, ConfigParam::Record_cons11& data) const {
if (cell_ref.is_null()) { return false; }
auto cs = load_cell_slice(std::move(cell_ref));
return unpack(cs, data) && cs.empty_ext();
}
bool ConfigParam::cell_unpack_cons11(Ref<vm::Cell> cell_ref, Ref<CellSlice>& x) const {
if (cell_ref.is_null()) { return false; }
auto cs = load_cell_slice(std::move(cell_ref));
return unpack_cons11(cs, x) && cs.empty_ext();
}
bool ConfigParam::unpack(vm::CellSlice& cs, ConfigParam::Record_cons12& data) const { bool ConfigParam::unpack(vm::CellSlice& cs, ConfigParam::Record_cons12& data) const {
return t_HashmapE_32_WorkchainDescr.fetch_to(cs, data.workchains) return t_HashmapE_32_WorkchainDescr.fetch_to(cs, data.workchains)
&& m_ == 12; && m_ == 12;
@ -16416,6 +16795,46 @@ bool ConfigParam::cell_pack_cons9(Ref<vm::Cell>& cell_ref, Ref<CellSlice> mandat
return pack_cons9(cb, std::move(mandatory_params)) && std::move(cb).finalize_to(cell_ref); return pack_cons9(cb, std::move(mandatory_params)) && std::move(cb).finalize_to(cell_ref);
} }
bool ConfigParam::pack(vm::CellBuilder& cb, const ConfigParam::Record_cons10& data) const {
return t_Hashmap_32_True.store_from(cb, data.critical_params)
&& m_ == 10;
}
bool ConfigParam::pack_cons10(vm::CellBuilder& cb, Ref<CellSlice> critical_params) const {
return t_Hashmap_32_True.store_from(cb, critical_params)
&& m_ == 10;
}
bool ConfigParam::cell_pack(Ref<vm::Cell>& cell_ref, const ConfigParam::Record_cons10& data) const {
vm::CellBuilder cb;
return pack(cb, data) && std::move(cb).finalize_to(cell_ref);
}
bool ConfigParam::cell_pack_cons10(Ref<vm::Cell>& cell_ref, Ref<CellSlice> critical_params) const {
vm::CellBuilder cb;
return pack_cons10(cb, std::move(critical_params)) && std::move(cb).finalize_to(cell_ref);
}
bool ConfigParam::pack(vm::CellBuilder& cb, const ConfigParam::Record_cons11& data) const {
return cb.append_cellslice_chk(data.x, 0x20008)
&& m_ == 11;
}
bool ConfigParam::pack_cons11(vm::CellBuilder& cb, Ref<CellSlice> x) const {
return cb.append_cellslice_chk(x, 0x20008)
&& m_ == 11;
}
bool ConfigParam::cell_pack(Ref<vm::Cell>& cell_ref, const ConfigParam::Record_cons11& data) const {
vm::CellBuilder cb;
return pack(cb, data) && std::move(cb).finalize_to(cell_ref);
}
bool ConfigParam::cell_pack_cons11(Ref<vm::Cell>& cell_ref, Ref<CellSlice> x) const {
vm::CellBuilder cb;
return pack_cons11(cb, std::move(x)) && std::move(cb).finalize_to(cell_ref);
}
bool ConfigParam::pack(vm::CellBuilder& cb, const ConfigParam::Record_cons12& data) const { bool ConfigParam::pack(vm::CellBuilder& cb, const ConfigParam::Record_cons12& data) const {
return t_HashmapE_32_WorkchainDescr.store_from(cb, data.workchains) return t_HashmapE_32_WorkchainDescr.store_from(cb, data.workchains)
&& m_ == 12; && m_ == 12;
@ -16905,6 +17324,18 @@ bool ConfigParam::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
&& t_Hashmap_32_True.print_skip(pp, cs) && t_Hashmap_32_True.print_skip(pp, cs)
&& m_ == 9 && m_ == 9
&& pp.close(); && pp.close();
case cons10:
return pp.open()
&& pp.field("critical_params")
&& t_Hashmap_32_True.print_skip(pp, cs)
&& m_ == 10
&& pp.close();
case cons11:
return pp.open()
&& pp.field()
&& t_ConfigVotingSetup.print_skip(pp, cs)
&& m_ == 11
&& pp.close();
case cons12: case cons12:
return pp.open() return pp.open()
&& pp.field("workchains") && pp.field("workchains")
@ -21128,8 +21559,8 @@ const RefT t_Ref_OutMsgDescr{t_OutMsgDescr};
const RefT t_Ref_ShardAccountBlocks{t_ShardAccountBlocks}; const RefT t_Ref_ShardAccountBlocks{t_ShardAccountBlocks};
const RefT t_Ref_McBlockExtra{t_McBlockExtra}; const RefT t_Ref_McBlockExtra{t_McBlockExtra};
const Maybe t_Maybe_Ref_McBlockExtra{t_Ref_McBlockExtra}; const Maybe t_Maybe_Ref_McBlockExtra{t_Ref_McBlockExtra};
const RefT t_Ref_TYPE_1648{t_ValueFlow_aux}; const RefT t_Ref_TYPE_1649{t_ValueFlow_aux};
const RefT t_Ref_TYPE_1649{t_ValueFlow_aux1}; const RefT t_Ref_TYPE_1650{t_ValueFlow_aux1};
const NatWidth t_natwidth_3{3}; const NatWidth t_natwidth_3{3};
const BinTree t_BinTree_ShardDescr{t_ShardDescr}; const BinTree t_BinTree_ShardDescr{t_ShardDescr};
const RefT t_Ref_BinTree_ShardDescr{t_BinTree_ShardDescr}; const RefT t_Ref_BinTree_ShardDescr{t_BinTree_ShardDescr};
@ -21142,14 +21573,21 @@ const HashmapE t_HashmapE_256_CreatorStats{256, t_CreatorStats};
const HashmapAugE t_HashmapAugE_256_CreatorStats_uint32{256, t_CreatorStats, t_uint32}; const HashmapAugE t_HashmapAugE_256_CreatorStats_uint32{256, t_CreatorStats, t_uint32};
const NatWidth t_natwidth_16{16}; const NatWidth t_natwidth_16{16};
const Maybe t_Maybe_ExtBlkRef{t_ExtBlkRef}; const Maybe t_Maybe_ExtBlkRef{t_ExtBlkRef};
const RefT t_Ref_TYPE_1666{t_McStateExtra_aux}; const RefT t_Ref_TYPE_1667{t_McStateExtra_aux};
const RefT t_Ref_SignedCertificate{t_SignedCertificate}; const RefT t_Ref_SignedCertificate{t_SignedCertificate};
const HashmapE t_HashmapE_16_CryptoSignaturePair{16, t_CryptoSignaturePair}; const HashmapE t_HashmapE_16_CryptoSignaturePair{16, t_CryptoSignaturePair};
const Maybe t_Maybe_Ref_InMsg{t_Ref_InMsg}; const Maybe t_Maybe_Ref_InMsg{t_Ref_InMsg};
const RefT t_Ref_TYPE_1674{t_McBlockExtra_aux}; const RefT t_Ref_TYPE_1675{t_McBlockExtra_aux};
const Hashmap t_Hashmap_16_ValidatorDescr{16, t_ValidatorDescr}; const Hashmap t_Hashmap_16_ValidatorDescr{16, t_ValidatorDescr};
const HashmapE t_HashmapE_16_ValidatorDescr{16, t_ValidatorDescr}; const HashmapE t_HashmapE_16_ValidatorDescr{16, t_ValidatorDescr};
const Hashmap t_Hashmap_32_True{32, t_True}; const Hashmap t_Hashmap_32_True{32, t_True};
const UInt t_uint8{8};
const RefT t_Ref_ConfigProposalSetup{t_ConfigProposalSetup};
const UInt t_uint256{256};
const Maybe t_Maybe_uint256{t_uint256};
const RefT t_Ref_ConfigProposal{t_ConfigProposal};
const HashmapE t_HashmapE_16_True{16, t_True};
const Int t_int64{64};
const NatWidth t_natwidth_12{12}; const NatWidth t_natwidth_12{12};
const NatWidth t_natwidth_32{32}; const NatWidth t_natwidth_32{32};
const NatWidth t_natwidth_13{13}; const NatWidth t_natwidth_13{13};
@ -21162,14 +21600,13 @@ const RefT t_Ref_BlockSignatures{t_BlockSignatures};
const Maybe t_Maybe_Ref_BlockSignatures{t_Ref_BlockSignatures}; const Maybe t_Maybe_Ref_BlockSignatures{t_Ref_BlockSignatures};
const RefT t_Ref_TopBlockDescr{t_TopBlockDescr}; const RefT t_Ref_TopBlockDescr{t_TopBlockDescr};
const HashmapE t_HashmapE_96_Ref_TopBlockDescr{96, t_Ref_TopBlockDescr}; const HashmapE t_HashmapE_96_Ref_TopBlockDescr{96, t_Ref_TopBlockDescr};
const Int t_int64{64};
const Int t_int257{257}; const Int t_int257{257};
const NatWidth t_natwidth_10{10}; const NatWidth t_natwidth_10{10};
const NatLeq t_natleq_4{4}; const NatLeq t_natleq_4{4};
const RefT t_Ref_VmStackValue{t_VmStackValue}; const RefT t_Ref_VmStackValue{t_VmStackValue};
const NatWidth t_natwidth_24{24}; const NatWidth t_natwidth_24{24};
const HashmapE t_HashmapE_4_VmStackValue{4, t_VmStackValue}; const HashmapE t_HashmapE_4_VmStackValue{4, t_VmStackValue};
const RefT t_Ref_TYPE_1705{t_VmGasLimits_aux}; const RefT t_Ref_TYPE_1709{t_VmGasLimits_aux};
const HashmapE t_HashmapE_256_Ref_Cell{256, t_RefCell}; const HashmapE t_HashmapE_256_Ref_Cell{256, t_RefCell};
const UInt t_uint13{13}; const UInt t_uint13{13};
const Maybe t_Maybe_uint13{t_uint13}; const Maybe t_Maybe_uint13{t_uint13};
@ -21250,6 +21687,7 @@ bool register_simple_types(std::function<bool(const char*, const TLB*)> func) {
&& func("McStateExtra", &t_McStateExtra) && func("McStateExtra", &t_McStateExtra)
&& func("ShardStateUnsplit", &t_ShardStateUnsplit) && func("ShardStateUnsplit", &t_ShardStateUnsplit)
&& func("ShardState", &t_ShardState) && func("ShardState", &t_ShardState)
&& func("GlobalVersion", &t_GlobalVersion)
&& func("BlockInfo", &t_BlockInfo) && func("BlockInfo", &t_BlockInfo)
&& func("ValueFlow", &t_ValueFlow) && func("ValueFlow", &t_ValueFlow)
&& func("BlockExtra", &t_BlockExtra) && func("BlockExtra", &t_BlockExtra)
@ -21278,7 +21716,10 @@ bool register_simple_types(std::function<bool(const char*, const TLB*)> func) {
&& func("SignedCertificate", &t_SignedCertificate) && func("SignedCertificate", &t_SignedCertificate)
&& func("ValidatorDescr", &t_ValidatorDescr) && func("ValidatorDescr", &t_ValidatorDescr)
&& func("ValidatorSet", &t_ValidatorSet) && func("ValidatorSet", &t_ValidatorSet)
&& func("GlobalVersion", &t_GlobalVersion) && func("ConfigProposalSetup", &t_ConfigProposalSetup)
&& func("ConfigVotingSetup", &t_ConfigVotingSetup)
&& func("ConfigProposal", &t_ConfigProposal)
&& func("ConfigProposalStatus", &t_ConfigProposalStatus)
&& func("WorkchainDescr", &t_WorkchainDescr) && func("WorkchainDescr", &t_WorkchainDescr)
&& func("BlockCreateFees", &t_BlockCreateFees) && func("BlockCreateFees", &t_BlockCreateFees)
&& func("StoragePrices", &t_StoragePrices) && func("StoragePrices", &t_StoragePrices)

View File

@ -15,6 +15,7 @@
// uses built-in type `uint` // uses built-in type `uint`
// uses built-in type `bits` // uses built-in type `bits`
// uses built-in type `int8` // uses built-in type `int8`
// uses built-in type `uint8`
// uses built-in type `uint13` // uses built-in type `uint13`
// uses built-in type `uint15` // uses built-in type `uint15`
// uses built-in type `int16` // uses built-in type `int16`
@ -24,6 +25,7 @@
// uses built-in type `uint63` // uses built-in type `uint63`
// uses built-in type `int64` // uses built-in type `int64`
// uses built-in type `uint64` // uses built-in type `uint64`
// uses built-in type `uint256`
// uses built-in type `int257` // uses built-in type `int257`
// uses built-in type `bits256` // uses built-in type `bits256`
@ -4533,11 +4535,12 @@ struct BlockInfo::Record {
unsigned gen_catchain_seqno; // gen_catchain_seqno : uint32 unsigned gen_catchain_seqno; // gen_catchain_seqno : uint32
unsigned min_ref_mc_seqno; // min_ref_mc_seqno : uint32 unsigned min_ref_mc_seqno; // min_ref_mc_seqno : uint32
unsigned prev_key_block_seqno; // prev_key_block_seqno : uint32 unsigned prev_key_block_seqno; // prev_key_block_seqno : uint32
Ref<CellSlice> gen_software; // gen_software : flags.0?GlobalVersion
Ref<Cell> master_ref; // master_ref : not_master?^BlkMasterInfo Ref<Cell> master_ref; // master_ref : not_master?^BlkMasterInfo
Ref<Cell> prev_ref; // prev_ref : ^(BlkPrevInfo after_merge) Ref<Cell> prev_ref; // prev_ref : ^(BlkPrevInfo after_merge)
Ref<Cell> prev_vert_ref; // prev_vert_ref : vert_seqno_incr?^(BlkPrevInfo 0) Ref<Cell> prev_vert_ref; // prev_vert_ref : vert_seqno_incr?^(BlkPrevInfo 0)
Record() = default; Record() = default;
Record(unsigned _version, bool _not_master, bool _after_merge, bool _before_split, bool _after_split, bool _want_split, bool _want_merge, bool _key_block, bool _vert_seqno_incr, int _flags, int _seq_no, int _vert_seq_no, Ref<CellSlice> _shard, unsigned _gen_utime, unsigned long long _start_lt, unsigned long long _end_lt, unsigned _gen_validator_list_hash_short, unsigned _gen_catchain_seqno, unsigned _min_ref_mc_seqno, unsigned _prev_key_block_seqno, Ref<Cell> _master_ref, Ref<Cell> _prev_ref, Ref<Cell> _prev_vert_ref) : version(_version), not_master(_not_master), after_merge(_after_merge), before_split(_before_split), after_split(_after_split), want_split(_want_split), want_merge(_want_merge), key_block(_key_block), vert_seqno_incr(_vert_seqno_incr), flags(_flags), seq_no(_seq_no), vert_seq_no(_vert_seq_no), shard(std::move(_shard)), gen_utime(_gen_utime), start_lt(_start_lt), end_lt(_end_lt), gen_validator_list_hash_short(_gen_validator_list_hash_short), gen_catchain_seqno(_gen_catchain_seqno), min_ref_mc_seqno(_min_ref_mc_seqno), prev_key_block_seqno(_prev_key_block_seqno), master_ref(std::move(_master_ref)), prev_ref(std::move(_prev_ref)), prev_vert_ref(std::move(_prev_vert_ref)) {} Record(unsigned _version, bool _not_master, bool _after_merge, bool _before_split, bool _after_split, bool _want_split, bool _want_merge, bool _key_block, bool _vert_seqno_incr, int _flags, int _seq_no, int _vert_seq_no, Ref<CellSlice> _shard, unsigned _gen_utime, unsigned long long _start_lt, unsigned long long _end_lt, unsigned _gen_validator_list_hash_short, unsigned _gen_catchain_seqno, unsigned _min_ref_mc_seqno, unsigned _prev_key_block_seqno, Ref<CellSlice> _gen_software, Ref<Cell> _master_ref, Ref<Cell> _prev_ref, Ref<Cell> _prev_vert_ref) : version(_version), not_master(_not_master), after_merge(_after_merge), before_split(_before_split), after_split(_after_split), want_split(_want_split), want_merge(_want_merge), key_block(_key_block), vert_seqno_incr(_vert_seqno_incr), flags(_flags), seq_no(_seq_no), vert_seq_no(_vert_seq_no), shard(std::move(_shard)), gen_utime(_gen_utime), start_lt(_start_lt), end_lt(_end_lt), gen_validator_list_hash_short(_gen_validator_list_hash_short), gen_catchain_seqno(_gen_catchain_seqno), min_ref_mc_seqno(_min_ref_mc_seqno), prev_key_block_seqno(_prev_key_block_seqno), gen_software(std::move(_gen_software)), master_ref(std::move(_master_ref)), prev_ref(std::move(_prev_ref)), prev_vert_ref(std::move(_prev_vert_ref)) {}
}; };
extern const BlockInfo t_BlockInfo; extern const BlockInfo t_BlockInfo;
@ -6085,6 +6088,176 @@ struct GlobalVersion final : TLB_Complex {
extern const GlobalVersion t_GlobalVersion; extern const GlobalVersion t_GlobalVersion;
//
// headers for type `ConfigProposalSetup`
//
struct ConfigProposalSetup final : TLB_Complex {
enum { cfg_vote_cfg };
static constexpr int cons_len_exact = 8;
static constexpr unsigned char cons_tag[1] = { 0x36 };
struct Record;
int get_size(const vm::CellSlice& cs) const override {
return 168;
}
bool skip(vm::CellSlice& cs) const override {
return cs.advance(168);
}
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 << "ConfigProposalSetup";
}
int check_tag(const vm::CellSlice& cs) const override;
int get_tag(const vm::CellSlice& cs) const override {
return 0;
}
};
struct ConfigProposalSetup::Record {
typedef ConfigProposalSetup type_class;
int min_tot_rounds; // min_tot_rounds : uint8
int max_tot_rounds; // max_tot_rounds : uint8
int min_wins; // min_wins : uint8
int max_losses; // max_losses : uint8
unsigned min_store_sec; // min_store_sec : uint32
unsigned max_store_sec; // max_store_sec : uint32
unsigned bit_price; // bit_price : uint32
unsigned cell_price; // cell_price : uint32
Record() = default;
Record(int _min_tot_rounds, int _max_tot_rounds, int _min_wins, int _max_losses, unsigned _min_store_sec, unsigned _max_store_sec, unsigned _bit_price, unsigned _cell_price) : min_tot_rounds(_min_tot_rounds), max_tot_rounds(_max_tot_rounds), min_wins(_min_wins), max_losses(_max_losses), min_store_sec(_min_store_sec), max_store_sec(_max_store_sec), bit_price(_bit_price), cell_price(_cell_price) {}
};
extern const ConfigProposalSetup t_ConfigProposalSetup;
//
// headers for type `ConfigVotingSetup`
//
struct ConfigVotingSetup final : TLB_Complex {
enum { cfg_vote_setup };
static constexpr int cons_len_exact = 8;
static constexpr unsigned char cons_tag[1] = { 0x91 };
struct Record {
typedef ConfigVotingSetup type_class;
Ref<Cell> normal_params; // normal_params : ^ConfigProposalSetup
Ref<Cell> critical_params; // critical_params : ^ConfigProposalSetup
Record() = default;
Record(Ref<Cell> _normal_params, Ref<Cell> _critical_params) : normal_params(std::move(_normal_params)), critical_params(std::move(_critical_params)) {}
};
int get_size(const vm::CellSlice& cs) const override {
return 0x20008;
}
bool skip(vm::CellSlice& cs) const override {
return cs.advance_ext(0x20008);
}
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
bool unpack(vm::CellSlice& cs, Record& data) const;
bool unpack_cfg_vote_setup(vm::CellSlice& cs, Ref<Cell>& normal_params, Ref<Cell>& critical_params) const;
bool cell_unpack(Ref<vm::Cell> cell_ref, Record& data) const;
bool cell_unpack_cfg_vote_setup(Ref<vm::Cell> cell_ref, Ref<Cell>& normal_params, Ref<Cell>& critical_params) const;
bool pack(vm::CellBuilder& cb, const Record& data) const;
bool pack_cfg_vote_setup(vm::CellBuilder& cb, Ref<Cell> normal_params, Ref<Cell> critical_params) const;
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record& data) const;
bool cell_pack_cfg_vote_setup(Ref<vm::Cell>& cell_ref, Ref<Cell> normal_params, Ref<Cell> critical_params) const;
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
std::ostream& print_type(std::ostream& os) const override {
return os << "ConfigVotingSetup";
}
int check_tag(const vm::CellSlice& cs) const override;
int get_tag(const vm::CellSlice& cs) const override {
return 0;
}
};
extern const ConfigVotingSetup t_ConfigVotingSetup;
//
// headers for type `ConfigProposal`
//
struct ConfigProposal final : TLB_Complex {
enum { cfg_proposal };
static constexpr int cons_len_exact = 8;
static constexpr unsigned char cons_tag[1] = { 0xf3 };
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_cfg_proposal(vm::CellSlice& cs, int& param_id, Ref<CellSlice>& param_value, Ref<CellSlice>& if_hash_equal) const;
bool cell_unpack(Ref<vm::Cell> cell_ref, Record& data) const;
bool cell_unpack_cfg_proposal(Ref<vm::Cell> cell_ref, int& param_id, Ref<CellSlice>& param_value, Ref<CellSlice>& if_hash_equal) const;
bool pack(vm::CellBuilder& cb, const Record& data) const;
bool pack_cfg_proposal(vm::CellBuilder& cb, int param_id, Ref<CellSlice> param_value, Ref<CellSlice> if_hash_equal) const;
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record& data) const;
bool cell_pack_cfg_proposal(Ref<vm::Cell>& cell_ref, int param_id, Ref<CellSlice> param_value, Ref<CellSlice> if_hash_equal) const;
bool print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const override;
std::ostream& print_type(std::ostream& os) const override {
return os << "ConfigProposal";
}
int check_tag(const vm::CellSlice& cs) const override;
int get_tag(const vm::CellSlice& cs) const override {
return 0;
}
};
struct ConfigProposal::Record {
typedef ConfigProposal type_class;
int param_id; // param_id : int32
Ref<CellSlice> param_value; // param_value : Maybe ^Cell
Ref<CellSlice> if_hash_equal; // if_hash_equal : Maybe uint256
Record() = default;
Record(int _param_id, Ref<CellSlice> _param_value, Ref<CellSlice> _if_hash_equal) : param_id(_param_id), param_value(std::move(_param_value)), if_hash_equal(std::move(_if_hash_equal)) {}
};
extern const ConfigProposal t_ConfigProposal;
//
// headers for type `ConfigProposalStatus`
//
struct ConfigProposalStatus final : TLB_Complex {
enum { cfg_proposal_status };
static constexpr int cons_len_exact = 8;
static constexpr unsigned char cons_tag[1] = { 0xce };
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 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 << "ConfigProposalStatus";
}
int check_tag(const vm::CellSlice& cs) const override;
int get_tag(const vm::CellSlice& cs) const override {
return 0;
}
};
struct ConfigProposalStatus::Record {
typedef ConfigProposalStatus type_class;
unsigned expires; // expires : uint32
Ref<Cell> proposal; // proposal : ^ConfigProposal
bool is_critical; // is_critical : Bool
Ref<CellSlice> voters; // voters : HashmapE 16 True
long long remaining_weight; // remaining_weight : int64
RefInt256 validator_set_id; // validator_set_id : uint256
int rounds_remaining; // rounds_remaining : uint8
int wins; // wins : uint8
int losses; // losses : uint8
Record() = default;
Record(unsigned _expires, Ref<Cell> _proposal, bool _is_critical, Ref<CellSlice> _voters, long long _remaining_weight, RefInt256 _validator_set_id, int _rounds_remaining, int _wins, int _losses) : expires(_expires), proposal(std::move(_proposal)), is_critical(_is_critical), voters(std::move(_voters)), remaining_weight(_remaining_weight), validator_set_id(std::move(_validator_set_id)), rounds_remaining(_rounds_remaining), wins(_wins), losses(_losses) {}
};
extern const ConfigProposalStatus t_ConfigProposalStatus;
// //
// headers for type `WorkchainFormat` // headers for type `WorkchainFormat`
// //
@ -6640,7 +6813,7 @@ extern const ValidatorSignedTempKey t_ValidatorSignedTempKey;
// //
struct ConfigParam final : TLB_Complex { struct ConfigParam final : TLB_Complex {
enum { cons32, cons33, cons34, cons35, cons36, cons37, config_mc_block_limits, config_block_limits, cons14, cons0, cons1, cons2, cons3, cons4, cons6, cons7, cons9, cons12, cons15, cons16, cons17, cons18, cons31, cons39, cons28, cons8, config_mc_gas_prices, config_gas_prices, cons29, config_mc_fwd_prices, config_fwd_prices }; enum { cons32, cons33, cons34, cons35, cons36, cons37, config_mc_block_limits, config_block_limits, cons14, cons0, cons1, cons2, cons3, cons4, cons6, cons7, cons9, cons10, cons12, cons15, cons16, cons17, cons18, cons31, cons39, cons11, cons28, cons8, config_mc_gas_prices, config_gas_prices, cons29, config_mc_fwd_prices, config_fwd_prices };
static constexpr int cons_len_exact = 0; static constexpr int cons_len_exact = 0;
int m_; int m_;
ConfigParam(int m) : m_(m) {} ConfigParam(int m) : m_(m) {}
@ -6699,6 +6872,18 @@ struct ConfigParam final : TLB_Complex {
Record_cons9() = default; Record_cons9() = default;
Record_cons9(Ref<CellSlice> _mandatory_params) : mandatory_params(std::move(_mandatory_params)) {} Record_cons9(Ref<CellSlice> _mandatory_params) : mandatory_params(std::move(_mandatory_params)) {}
}; };
struct Record_cons10 {
typedef ConfigParam type_class;
Ref<CellSlice> critical_params; // critical_params : Hashmap 32 True
Record_cons10() = default;
Record_cons10(Ref<CellSlice> _critical_params) : critical_params(std::move(_critical_params)) {}
};
struct Record_cons11 {
typedef ConfigParam type_class;
Ref<CellSlice> x; // ConfigVotingSetup
Record_cons11() = default;
Record_cons11(Ref<CellSlice> _x) : x(std::move(_x)) {}
};
struct Record_cons12 { struct Record_cons12 {
typedef ConfigParam type_class; typedef ConfigParam type_class;
Ref<CellSlice> workchains; // workchains : HashmapE 32 WorkchainDescr Ref<CellSlice> workchains; // workchains : HashmapE 32 WorkchainDescr
@ -6890,6 +7075,22 @@ struct ConfigParam final : TLB_Complex {
bool pack_cons9(vm::CellBuilder& cb, Ref<CellSlice> mandatory_params) const; bool pack_cons9(vm::CellBuilder& cb, Ref<CellSlice> mandatory_params) const;
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record_cons9& data) const; bool cell_pack(Ref<vm::Cell>& cell_ref, const Record_cons9& data) const;
bool cell_pack_cons9(Ref<vm::Cell>& cell_ref, Ref<CellSlice> mandatory_params) const; bool cell_pack_cons9(Ref<vm::Cell>& cell_ref, Ref<CellSlice> mandatory_params) const;
bool unpack(vm::CellSlice& cs, Record_cons10& data) const;
bool unpack_cons10(vm::CellSlice& cs, Ref<CellSlice>& critical_params) const;
bool cell_unpack(Ref<vm::Cell> cell_ref, Record_cons10& data) const;
bool cell_unpack_cons10(Ref<vm::Cell> cell_ref, Ref<CellSlice>& critical_params) const;
bool pack(vm::CellBuilder& cb, const Record_cons10& data) const;
bool pack_cons10(vm::CellBuilder& cb, Ref<CellSlice> critical_params) const;
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record_cons10& data) const;
bool cell_pack_cons10(Ref<vm::Cell>& cell_ref, Ref<CellSlice> critical_params) const;
bool unpack(vm::CellSlice& cs, Record_cons11& data) const;
bool unpack_cons11(vm::CellSlice& cs, Ref<CellSlice>& x) const;
bool cell_unpack(Ref<vm::Cell> cell_ref, Record_cons11& data) const;
bool cell_unpack_cons11(Ref<vm::Cell> cell_ref, Ref<CellSlice>& x) const;
bool pack(vm::CellBuilder& cb, const Record_cons11& data) const;
bool pack_cons11(vm::CellBuilder& cb, Ref<CellSlice> x) const;
bool cell_pack(Ref<vm::Cell>& cell_ref, const Record_cons11& data) const;
bool cell_pack_cons11(Ref<vm::Cell>& cell_ref, Ref<CellSlice> x) const;
bool unpack(vm::CellSlice& cs, Record_cons12& data) const; bool unpack(vm::CellSlice& cs, Record_cons12& data) const;
bool unpack_cons12(vm::CellSlice& cs, Ref<CellSlice>& workchains) const; bool unpack_cons12(vm::CellSlice& cs, Ref<CellSlice>& workchains) const;
bool cell_unpack(Ref<vm::Cell> cell_ref, Record_cons12& data) const; bool cell_unpack(Ref<vm::Cell> cell_ref, Record_cons12& data) const;
@ -8689,9 +8890,9 @@ extern const RefT t_Ref_McBlockExtra;
// Maybe ^McBlockExtra // Maybe ^McBlockExtra
extern const Maybe t_Maybe_Ref_McBlockExtra; extern const Maybe t_Maybe_Ref_McBlockExtra;
// ^[$_ from_prev_blk:CurrencyCollection to_next_blk:CurrencyCollection imported:CurrencyCollection exported:CurrencyCollection ] // ^[$_ from_prev_blk:CurrencyCollection to_next_blk:CurrencyCollection imported:CurrencyCollection exported:CurrencyCollection ]
extern const RefT t_Ref_TYPE_1648;
// ^[$_ fees_imported:CurrencyCollection recovered:CurrencyCollection created:CurrencyCollection minted:CurrencyCollection ]
extern const RefT t_Ref_TYPE_1649; extern const RefT t_Ref_TYPE_1649;
// ^[$_ fees_imported:CurrencyCollection recovered:CurrencyCollection created:CurrencyCollection minted:CurrencyCollection ]
extern const RefT t_Ref_TYPE_1650;
// ## 3 // ## 3
extern const NatWidth t_natwidth_3; extern const NatWidth t_natwidth_3;
// BinTree ShardDescr // BinTree ShardDescr
@ -8717,7 +8918,7 @@ extern const NatWidth t_natwidth_16;
// Maybe ExtBlkRef // Maybe ExtBlkRef
extern const Maybe t_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 ] // ^[$_ 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_1666; extern const RefT t_Ref_TYPE_1667;
// ^SignedCertificate // ^SignedCertificate
extern const RefT t_Ref_SignedCertificate; extern const RefT t_Ref_SignedCertificate;
// HashmapE 16 CryptoSignaturePair // HashmapE 16 CryptoSignaturePair
@ -8725,13 +8926,27 @@ extern const HashmapE t_HashmapE_16_CryptoSignaturePair;
// Maybe ^InMsg // Maybe ^InMsg
extern const Maybe t_Maybe_Ref_InMsg; extern const Maybe t_Maybe_Ref_InMsg;
// ^[$_ prev_blk_signatures:(HashmapE 16 CryptoSignaturePair) recover_create_msg:(Maybe ^InMsg) mint_msg:(Maybe ^InMsg) ] // ^[$_ prev_blk_signatures:(HashmapE 16 CryptoSignaturePair) recover_create_msg:(Maybe ^InMsg) mint_msg:(Maybe ^InMsg) ]
extern const RefT t_Ref_TYPE_1674; extern const RefT t_Ref_TYPE_1675;
// Hashmap 16 ValidatorDescr // Hashmap 16 ValidatorDescr
extern const Hashmap t_Hashmap_16_ValidatorDescr; extern const Hashmap t_Hashmap_16_ValidatorDescr;
// HashmapE 16 ValidatorDescr // HashmapE 16 ValidatorDescr
extern const HashmapE t_HashmapE_16_ValidatorDescr; extern const HashmapE t_HashmapE_16_ValidatorDescr;
// Hashmap 32 True // Hashmap 32 True
extern const Hashmap t_Hashmap_32_True; extern const Hashmap t_Hashmap_32_True;
// uint8
extern const UInt t_uint8;
// ^ConfigProposalSetup
extern const RefT t_Ref_ConfigProposalSetup;
// uint256
extern const UInt t_uint256;
// Maybe uint256
extern const Maybe t_Maybe_uint256;
// ^ConfigProposal
extern const RefT t_Ref_ConfigProposal;
// HashmapE 16 True
extern const HashmapE t_HashmapE_16_True;
// int64
extern const Int t_int64;
// ## 12 // ## 12
extern const NatWidth t_natwidth_12; extern const NatWidth t_natwidth_12;
// ## 32 // ## 32
@ -8756,8 +8971,6 @@ extern const Maybe t_Maybe_Ref_BlockSignatures;
extern const RefT t_Ref_TopBlockDescr; extern const RefT t_Ref_TopBlockDescr;
// HashmapE 96 ^TopBlockDescr // HashmapE 96 ^TopBlockDescr
extern const HashmapE t_HashmapE_96_Ref_TopBlockDescr; extern const HashmapE t_HashmapE_96_Ref_TopBlockDescr;
// int64
extern const Int t_int64;
// int257 // int257
extern const Int t_int257; extern const Int t_int257;
// ## 10 // ## 10
@ -8771,7 +8984,7 @@ extern const NatWidth t_natwidth_24;
// HashmapE 4 VmStackValue // HashmapE 4 VmStackValue
extern const HashmapE t_HashmapE_4_VmStackValue; extern const HashmapE t_HashmapE_4_VmStackValue;
// ^[$_ max_limit:int64 cur_limit:int64 credit:int64 ] // ^[$_ max_limit:int64 cur_limit:int64 credit:int64 ]
extern const RefT t_Ref_TYPE_1705; extern const RefT t_Ref_TYPE_1709;
// HashmapE 256 ^Cell // HashmapE 256 ^Cell
extern const HashmapE t_HashmapE_256_Ref_Cell; extern const HashmapE t_HashmapE_256_Ref_Cell;
// uint13 // uint13

View File

@ -344,11 +344,11 @@ unsigned long long VarUIntegerPos::as_uint(const vm::CellSlice& cs) const {
bool VarUIntegerPos::store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const { bool VarUIntegerPos::store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const {
int k = value.bit_size(false); int k = value.bit_size(false);
return k <= (n - 1) * 8 && value.sgn() > 0 && cb.store_long_bool((k + 7) >> 3, ln) && return k <= (n - 1) * 8 && value.sgn() >= (int)store_pos_only && cb.store_long_bool((k + 7) >> 3, ln) &&
cb.store_int256_bool(value, (k + 7) & -8, false); cb.store_int256_bool(value, (k + 7) & -8, false);
} }
const VarUIntegerPos t_VarUIntegerPos_16{16}, t_VarUIntegerPos_32{32}; const VarUIntegerPos t_VarUIntegerPos_16{16}, t_VarUIntegerPos_32{32}, t_VarUIntegerPosRelaxed_32{32, true};
static inline bool redundant_int(const vm::CellSlice& cs) { static inline bool redundant_int(const vm::CellSlice& cs) {
int t = (int)cs.prefetch_long(9); int t = (int)cs.prefetch_long(9);
@ -500,8 +500,8 @@ bool HashmapE::add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice
int n = root_type.n; int n = root_type.n;
vm::Dictionary dict1{vm::DictAdvance(), cs1, n}, dict2{vm::DictAdvance(), cs2, n}; vm::Dictionary dict1{vm::DictAdvance(), cs1, n}, dict2{vm::DictAdvance(), cs2, n};
const TLB& vt = root_type.value_type; const TLB& vt = root_type.value_type;
vm::Dictionary::simple_combine_func_t combine = [vt](vm::CellBuilder& cb, Ref<vm::CellSlice> cs1_ref, vm::Dictionary::simple_combine_func_t combine = [&vt](vm::CellBuilder& cb, Ref<vm::CellSlice> cs1_ref,
Ref<vm::CellSlice> cs2_ref) -> bool { Ref<vm::CellSlice> cs2_ref) -> bool {
if (!vt.add_values(cb, cs1_ref.write(), cs2_ref.write())) { if (!vt.add_values(cb, cs1_ref.write(), cs2_ref.write())) {
throw CombineError{}; throw CombineError{};
} }
@ -514,8 +514,8 @@ bool HashmapE::add_values_ref(Ref<vm::Cell>& res, Ref<vm::Cell> arg1, Ref<vm::Ce
int n = root_type.n; int n = root_type.n;
vm::Dictionary dict1{std::move(arg1), n}, dict2{std::move(arg2), n}; vm::Dictionary dict1{std::move(arg1), n}, dict2{std::move(arg2), n};
const TLB& vt = root_type.value_type; const TLB& vt = root_type.value_type;
vm::Dictionary::simple_combine_func_t combine = [vt](vm::CellBuilder& cb, Ref<vm::CellSlice> cs1_ref, vm::Dictionary::simple_combine_func_t combine = [&vt](vm::CellBuilder& cb, Ref<vm::CellSlice> cs1_ref,
Ref<vm::CellSlice> cs2_ref) -> bool { Ref<vm::CellSlice> cs2_ref) -> bool {
if (!vt.add_values(cb, cs1_ref.write(), cs2_ref.write())) { if (!vt.add_values(cb, cs1_ref.write(), cs2_ref.write())) {
throw CombineError{}; throw CombineError{};
} }
@ -535,8 +535,8 @@ int HashmapE::sub_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice&
int n = root_type.n; int n = root_type.n;
vm::Dictionary dict1{vm::DictAdvance(), cs1, n}, dict2{vm::DictAdvance(), cs2, n}; vm::Dictionary dict1{vm::DictAdvance(), cs1, n}, dict2{vm::DictAdvance(), cs2, n};
const TLB& vt = root_type.value_type; const TLB& vt = root_type.value_type;
vm::Dictionary::simple_combine_func_t combine = [vt](vm::CellBuilder& cb, Ref<vm::CellSlice> cs1_ref, vm::Dictionary::simple_combine_func_t combine = [&vt](vm::CellBuilder& cb, Ref<vm::CellSlice> cs1_ref,
Ref<vm::CellSlice> cs2_ref) -> bool { Ref<vm::CellSlice> cs2_ref) -> bool {
int r = vt.sub_values(cb, cs1_ref.write(), cs2_ref.write()); int r = vt.sub_values(cb, cs1_ref.write(), cs2_ref.write());
if (r < 0) { if (r < 0) {
throw CombineError{}; throw CombineError{};
@ -555,8 +555,8 @@ int HashmapE::sub_values_ref(Ref<vm::Cell>& res, Ref<vm::Cell> arg1, Ref<vm::Cel
int n = root_type.n; int n = root_type.n;
vm::Dictionary dict1{std::move(arg1), n}, dict2{std::move(arg2), n}; vm::Dictionary dict1{std::move(arg1), n}, dict2{std::move(arg2), n};
const TLB& vt = root_type.value_type; const TLB& vt = root_type.value_type;
vm::Dictionary::simple_combine_func_t combine = [vt](vm::CellBuilder& cb, Ref<vm::CellSlice> cs1_ref, vm::Dictionary::simple_combine_func_t combine = [&vt](vm::CellBuilder& cb, Ref<vm::CellSlice> cs1_ref,
Ref<vm::CellSlice> cs2_ref) -> bool { Ref<vm::CellSlice> cs2_ref) -> bool {
int r = vt.sub_values(cb, cs1_ref.write(), cs2_ref.write()); int r = vt.sub_values(cb, cs1_ref.write(), cs2_ref.write());
if (r < 0) { if (r < 0) {
throw CombineError{}; throw CombineError{};

View File

@ -68,13 +68,17 @@ struct VarUInteger final : TLB_Complex {
bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override; bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override;
unsigned precompute_integer_size(const td::BigInt256& value) const; unsigned precompute_integer_size(const td::BigInt256& value) const;
unsigned precompute_integer_size(td::RefInt256 value) const; unsigned precompute_integer_size(td::RefInt256 value) const;
std::ostream& print_type(std::ostream& os) const override {
return os << "(VarUInteger " << n << ")";
}
}; };
extern const VarUInteger t_VarUInteger_3, t_VarUInteger_7, t_VarUInteger_16, t_VarUInteger_32; extern const VarUInteger t_VarUInteger_3, t_VarUInteger_7, t_VarUInteger_16, t_VarUInteger_32;
struct VarUIntegerPos final : TLB_Complex { struct VarUIntegerPos final : TLB_Complex {
int n, ln; int n, ln;
VarUIntegerPos(int _n) : n(_n) { bool store_pos_only;
VarUIntegerPos(int _n, bool relaxed = false) : n(_n), store_pos_only(!relaxed) {
ln = 32 - td::count_leading_zeroes32(n - 1); ln = 32 - td::count_leading_zeroes32(n - 1);
} }
bool skip(vm::CellSlice& cs) const override; bool skip(vm::CellSlice& cs) const override;
@ -82,9 +86,12 @@ struct VarUIntegerPos final : TLB_Complex {
td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override; td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override;
unsigned long long as_uint(const vm::CellSlice& cs) const override; unsigned long long as_uint(const vm::CellSlice& cs) const override;
bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override; bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override;
std::ostream& print_type(std::ostream& os) const override {
return os << "(VarUIntegerPos " << n << ")";
}
}; };
extern const VarUIntegerPos t_VarUIntegerPos_16, t_VarUIntegerPos_32; extern const VarUIntegerPos t_VarUIntegerPos_16, t_VarUIntegerPos_32, t_VarUIntegerPosRelaxed_32;
struct VarInteger final : TLB_Complex { struct VarInteger final : TLB_Complex {
int n, ln; int n, ln;
@ -99,6 +106,9 @@ struct VarInteger final : TLB_Complex {
return cb.store_zeroes_bool(ln); return cb.store_zeroes_bool(ln);
} }
bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override; bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override;
std::ostream& print_type(std::ostream& os) const override {
return os << "(VarInteger " << n << ")";
}
}; };
struct VarIntegerNz final : TLB_Complex { struct VarIntegerNz final : TLB_Complex {
@ -111,6 +121,9 @@ struct VarIntegerNz final : TLB_Complex {
td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override; td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override;
long long as_int(const vm::CellSlice& cs) const override; long long as_int(const vm::CellSlice& cs) const override;
bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override; bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override;
std::ostream& print_type(std::ostream& os) const override {
return os << "(VarIntegerNz " << n << ")";
}
}; };
struct Unary final : TLB { struct Unary final : TLB {
@ -312,8 +325,8 @@ struct MsgAddress final : TLB_Complex {
extern const MsgAddress t_MsgAddress; extern const MsgAddress t_MsgAddress;
struct ExtraCurrencyCollection final : TLB { struct ExtraCurrencyCollection final : TLB {
HashmapE dict_type; HashmapE dict_type, dict_type2;
ExtraCurrencyCollection() : dict_type(32, t_VarUIntegerPos_32) { ExtraCurrencyCollection() : dict_type(32, t_VarUIntegerPos_32), dict_type2(32, t_VarUIntegerPosRelaxed_32) {
} }
int get_size(const vm::CellSlice& cs) const override { int get_size(const vm::CellSlice& cs) const override {
return dict_type.get_size(cs); return dict_type.get_size(cs);
@ -328,13 +341,13 @@ struct ExtraCurrencyCollection final : TLB {
return dict_type.add_values(cb, cs1, cs2); return dict_type.add_values(cb, cs1, cs2);
} }
int sub_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const override { int sub_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const override {
return dict_type.sub_values(cb, cs1, cs2); return dict_type2.sub_values(cb, cs1, cs2);
} }
bool add_values_ref(Ref<vm::Cell>& res, Ref<vm::Cell> arg1, Ref<vm::Cell> arg2) const { bool add_values_ref(Ref<vm::Cell>& res, Ref<vm::Cell> arg1, Ref<vm::Cell> arg2) const {
return dict_type.add_values_ref(res, std::move(arg1), std::move(arg2)); return dict_type.add_values_ref(res, std::move(arg1), std::move(arg2));
} }
int sub_values_ref(Ref<vm::Cell>& res, Ref<vm::Cell> arg1, Ref<vm::Cell> arg2) const { int sub_values_ref(Ref<vm::Cell>& res, Ref<vm::Cell> arg1, Ref<vm::Cell> arg2) const {
return dict_type.sub_values_ref(res, std::move(arg1), std::move(arg2)); return dict_type2.sub_values_ref(res, std::move(arg1), std::move(arg2));
} }
bool store_ref(vm::CellBuilder& cb, Ref<vm::Cell> arg) const { bool store_ref(vm::CellBuilder& cb, Ref<vm::Cell> arg) const {
return dict_type.store_ref(cb, std::move(arg)); return dict_type.store_ref(cb, std::move(arg));

View File

@ -20,6 +20,7 @@
#include "block/block.h" #include "block/block.h"
#include "block/block-auto.h" #include "block/block-auto.h"
#include "block/block-parse.h" #include "block/block-parse.h"
#include "block/mc-config.h"
#include "ton/ton-shard.h" #include "ton/ton-shard.h"
#include "common/bigexp.h" #include "common/bigexp.h"
#include "common/util.h" #include "common/util.h"
@ -1602,33 +1603,50 @@ bool check_one_config_param(Ref<vm::CellSlice> cs_ref, td::ConstBitPtr key, td::
const int mandatory_config_params[] = {18, 20, 21, 22, 23, 24, 25, 28, 34}; const int mandatory_config_params[] = {18, 20, 21, 22, 23, 24, 25, 28, 34};
bool valid_config_data(Ref<vm::Cell> cell, const td::BitArray<256>& addr, bool catch_errors, bool relax_par0) { bool valid_config_data(Ref<vm::Cell> cell, const td::BitArray<256>& addr, bool catch_errors, bool relax_par0,
Ref<vm::Cell> old_mparams) {
using namespace std::placeholders; using namespace std::placeholders;
if (cell.is_null()) { if (cell.is_null()) {
return false; return false;
} }
if (!catch_errors) { if (catch_errors) {
vm::Dictionary dict{std::move(cell), 32}; try {
for (int x : mandatory_config_params) { return valid_config_data(std::move(cell), addr, false, relax_par0, std::move(old_mparams));
if (!dict.int_key_exists(x)) { } catch (vm::VmError&) {
LOG(ERROR) << "mandatory configuration parameter #" << x << " is missing"; return false;
return false;
}
} }
return dict.check_for_each(std::bind(check_one_config_param, _1, _2, addr.cbits(), relax_par0));
} }
try { vm::Dictionary dict{std::move(cell), 32};
vm::Dictionary dict{std::move(cell), 32}; if (!dict.check_for_each(std::bind(check_one_config_param, _1, _2, addr.cbits(), relax_par0))) {
for (int x : mandatory_config_params) {
if (!dict.int_key_exists(x)) {
LOG(ERROR) << "mandatory configuration parameter #" << x << " is missing";
return false;
}
}
return dict.check_for_each(std::bind(check_one_config_param, _1, _2, addr.cbits(), relax_par0));
} catch (vm::VmError&) {
return false; return false;
} }
for (int x : mandatory_config_params) {
if (!dict.int_key_exists(x)) {
LOG(ERROR) << "mandatory configuration parameter #" << x << " is missing";
return false;
}
}
return config_params_present(dict, dict.lookup_ref(td::BitArray<32>{9})) &&
config_params_present(dict, std::move(old_mparams));
}
bool config_params_present(vm::Dictionary& dict, Ref<vm::Cell> param_dict_root) {
auto res = block::Config::unpack_param_dict(std::move(param_dict_root));
if (res.is_error()) {
LOG(ERROR)
<< "invalid mandatory parameters dictionary while checking existence of all mandatory configuration parameters";
return false;
}
for (int x : res.move_as_ok()) {
// LOG(DEBUG) << "checking whether mandatory configuration parameter #" << x << " exists";
if (!dict.int_key_exists(x)) {
LOG(ERROR) << "configuration parameter #" << x
<< " (declared as mandatory in configuration parameter #9) is missing";
return false;
}
}
// LOG(DEBUG) << "all mandatory configuration parameters present";
return true;
} }
bool add_extra_currency(Ref<vm::Cell> extra1, Ref<vm::Cell> extra2, Ref<vm::Cell>& res) { bool add_extra_currency(Ref<vm::Cell> extra1, Ref<vm::Cell> extra2, Ref<vm::Cell>& res) {
@ -1651,7 +1669,7 @@ bool sub_extra_currency(Ref<vm::Cell> extra1, Ref<vm::Cell> extra2, Ref<vm::Cell
res.clear(); res.clear();
return false; return false;
} else { } else {
return block::tlb::t_ExtraCurrencyCollection.sub_values_ref(res, std::move(extra1), std::move(extra2)); return block::tlb::t_ExtraCurrencyCollection.sub_values_ref(res, std::move(extra1), std::move(extra2)) >= 0;
} }
} }

View File

@ -606,7 +606,8 @@ bool unpack_CurrencyCollection(Ref<vm::CellSlice> csr, td::RefInt256& value, Ref
bool valid_library_collection(Ref<vm::Cell> cell, bool catch_errors = true); bool valid_library_collection(Ref<vm::Cell> cell, bool catch_errors = true);
bool valid_config_data(Ref<vm::Cell> cell, const td::BitArray<256>& addr, bool catch_errors = true, bool valid_config_data(Ref<vm::Cell> cell, const td::BitArray<256>& addr, bool catch_errors = true,
bool relax_par0 = false); bool relax_par0 = false, Ref<vm::Cell> old_mparams = {});
bool config_params_present(vm::Dictionary& dict, Ref<vm::Cell> param_dict_root);
bool add_extra_currency(Ref<vm::Cell> extra1, Ref<vm::Cell> extra2, Ref<vm::Cell>& res); bool add_extra_currency(Ref<vm::Cell> extra1, Ref<vm::Cell> extra2, Ref<vm::Cell>& res);
bool sub_extra_currency(Ref<vm::Cell> extra1, Ref<vm::Cell> extra2, Ref<vm::Cell>& res); bool sub_extra_currency(Ref<vm::Cell> extra1, Ref<vm::Cell> extra2, Ref<vm::Cell>& res);

View File

@ -414,7 +414,7 @@ block_info#9bc7a987 version:uint32
after_split:(## 1) after_split:(## 1)
want_split:Bool want_merge:Bool want_split:Bool want_merge:Bool
key_block:Bool vert_seqno_incr:(## 1) key_block:Bool vert_seqno_incr:(## 1)
flags:(## 8) flags:(## 8) { flags <= 1 }
seq_no:# vert_seq_no:# { vert_seq_no >= vert_seqno_incr } seq_no:# vert_seq_no:# { vert_seq_no >= vert_seqno_incr }
{ prev_seq_no:# } { ~prev_seq_no + 1 = seq_no } { prev_seq_no:# } { ~prev_seq_no + 1 = seq_no }
shard:ShardIdent gen_utime:uint32 shard:ShardIdent gen_utime:uint32
@ -423,6 +423,7 @@ block_info#9bc7a987 version:uint32
gen_catchain_seqno:uint32 gen_catchain_seqno:uint32
min_ref_mc_seqno:uint32 min_ref_mc_seqno:uint32
prev_key_block_seqno:uint32 prev_key_block_seqno:uint32
gen_software:flags . 0?GlobalVersion
master_ref:not_master?^BlkMasterInfo master_ref:not_master?^BlkMasterInfo
prev_ref:^(BlkPrevInfo after_merge) prev_ref:^(BlkPrevInfo after_merge)
prev_vert_ref:vert_seqno_incr?^(BlkPrevInfo 0) prev_vert_ref:vert_seqno_incr?^(BlkPrevInfo 0)
@ -572,6 +573,17 @@ _ to_mint:ExtraCurrencyCollection = ConfigParam 7;
capabilities#c4 version:uint32 capabilities:uint64 = GlobalVersion; capabilities#c4 version:uint32 capabilities:uint64 = GlobalVersion;
_ GlobalVersion = ConfigParam 8; // all zero if absent _ GlobalVersion = ConfigParam 8; // all zero if absent
_ mandatory_params:(Hashmap 32 True) = ConfigParam 9; _ mandatory_params:(Hashmap 32 True) = ConfigParam 9;
_ critical_params:(Hashmap 32 True) = ConfigParam 10;
cfg_vote_cfg#36 min_tot_rounds:uint8 max_tot_rounds:uint8 min_wins:uint8 max_losses:uint8 min_store_sec:uint32 max_store_sec:uint32 bit_price:uint32 cell_price:uint32 = ConfigProposalSetup;
cfg_vote_setup#91 normal_params:^ConfigProposalSetup critical_params:^ConfigProposalSetup = ConfigVotingSetup;
_ ConfigVotingSetup = ConfigParam 11;
cfg_proposal#f3 param_id:int32 param_value:(Maybe ^Cell) if_hash_equal:(Maybe uint256)
= ConfigProposal;
cfg_proposal_status#ce expires:uint32 proposal:^ConfigProposal is_critical:Bool
voters:(HashmapE 16 True) remaining_weight:int64 validator_set_id:uint256
rounds_remaining:uint8 wins:uint8 losses:uint8 = ConfigProposalStatus;
wfmt_basic#1 vm_version:int32 vm_mode:uint64 = WorkchainFormat 1; wfmt_basic#1 vm_version:int32 vm_mode:uint64 = WorkchainFormat 1;
wfmt_ext#0 min_addr_len:(## 12) max_addr_len:(## 12) addr_len_step:(## 12) wfmt_ext#0 min_addr_len:(## 12) max_addr_len:(## 12) addr_len_step:(## 12)

View File

@ -55,6 +55,8 @@
#include "td/utils/port/path.h" #include "td/utils/port/path.h"
#include "td/utils/port/signals.h" #include "td/utils/port/signals.h"
#include "tonlib/keys/Mnemonic.h"
#include "block.h" #include "block.h"
#include "block-parse.h" #include "block-parse.h"
#include "block-auto.h" #include "block-auto.h"
@ -616,7 +618,43 @@ void interpret_is_workchain_descr(vm::Stack& stack) {
stack.push_bool(block::gen::t_WorkchainDescr.validate_ref(std::move(cell))); stack.push_bool(block::gen::t_WorkchainDescr.validate_ref(std::move(cell)));
} }
void interpret_add_extra_currencies(vm::Stack& stack) {
Ref<vm::Cell> y = stack.pop_maybe_cell(), x = stack.pop_maybe_cell(), res;
bool ok = block::add_extra_currency(std::move(x), std::move(y), res);
if (ok) {
stack.push_maybe_cell(std::move(res));
}
stack.push_bool(ok);
}
void interpret_sub_extra_currencies(vm::Stack& stack) {
Ref<vm::Cell> y = stack.pop_maybe_cell(), x = stack.pop_maybe_cell(), res;
bool ok = block::sub_extra_currency(std::move(x), std::move(y), res);
if (ok) {
stack.push_maybe_cell(std::move(res));
}
stack.push_bool(ok);
}
void interpret_mnemonic_to_privkey(vm::Stack& stack, int mode) {
td::SecureString str{td::Slice{stack.pop_string()}};
auto res = tonlib::Mnemonic::create(std::move(str), td::SecureString());
if (res.is_error()) {
throw fift::IntError{res.move_as_error().to_string()};
}
auto privkey = res.move_as_ok().to_private_key();
td::SecureString key;
if (mode & 1) {
auto pub = privkey.get_public_key();
key = pub.move_as_ok().as_octet_string();
} else {
key = privkey.as_octet_string();
}
stack.push_bytes(key.as_slice());
}
void init_words_custom(fift::Dictionary& d) { void init_words_custom(fift::Dictionary& d) {
using namespace std::placeholders;
d.def_stack_word("verb@ ", interpret_get_verbosity); d.def_stack_word("verb@ ", interpret_get_verbosity);
d.def_stack_word("verb! ", interpret_set_verbosity); d.def_stack_word("verb! ", interpret_set_verbosity);
d.def_stack_word("wcid@ ", interpret_get_workchain); d.def_stack_word("wcid@ ", interpret_get_workchain);
@ -631,6 +669,10 @@ void init_words_custom(fift::Dictionary& d) {
d.def_stack_word("create_state ", interpret_create_state); d.def_stack_word("create_state ", interpret_create_state);
d.def_stack_word("isShardState? ", interpret_is_shard_state); d.def_stack_word("isShardState? ", interpret_is_shard_state);
d.def_stack_word("isWorkchainDescr? ", interpret_is_workchain_descr); d.def_stack_word("isWorkchainDescr? ", interpret_is_workchain_descr);
d.def_stack_word("CC+? ", interpret_add_extra_currencies);
d.def_stack_word("CC-? ", interpret_sub_extra_currencies);
d.def_stack_word("mnemo>priv ", std::bind(interpret_mnemonic_to_privkey, _1, 0));
d.def_stack_word("mnemo>pub ", std::bind(interpret_mnemonic_to_privkey, _1, 1));
} }
tlb::TypenameLookup tlb_dict; tlb::TypenameLookup tlb_dict;
@ -704,7 +746,12 @@ void interpret_tlb_validate_skip(vm::Stack& stack) {
stack.push_bool(ok); stack.push_bool(ok);
} }
void interpret_tlb_type_const(vm::Stack& stack, const tlb::TLB* ptr) {
stack.push_make_object<tlb::TlbTypeHolder>(ptr);
}
void init_words_tlb(fift::Dictionary& d) { void init_words_tlb(fift::Dictionary& d) {
using namespace std::placeholders;
tlb_dict.register_types(block::gen::register_simple_types); tlb_dict.register_types(block::gen::register_simple_types);
d.def_stack_word("tlb-type-lookup ", interpret_tlb_type_lookup); d.def_stack_word("tlb-type-lookup ", interpret_tlb_type_lookup);
d.def_stack_word("tlb-type-name ", interpret_tlb_type_name); d.def_stack_word("tlb-type-name ", interpret_tlb_type_name);
@ -713,6 +760,8 @@ void init_words_tlb(fift::Dictionary& d) {
d.def_stack_word("(tlb-dump-str?) ", interpret_tlb_dump_to_str); d.def_stack_word("(tlb-dump-str?) ", interpret_tlb_dump_to_str);
d.def_stack_word("tlb-skip ", interpret_tlb_skip); d.def_stack_word("tlb-skip ", interpret_tlb_skip);
d.def_stack_word("tlb-validate-skip ", interpret_tlb_validate_skip); d.def_stack_word("tlb-validate-skip ", interpret_tlb_validate_skip);
d.def_stack_word("ExtraCurrencyCollection",
std::bind(interpret_tlb_type_const, _1, &block::tlb::t_ExtraCurrencyCollection));
} }
void usage(const char* progname) { void usage(const char* progname) {

View File

@ -40,6 +40,7 @@
#include <algorithm> #include <algorithm>
namespace block { namespace block {
using namespace std::literals::string_literals;
using td::Ref; using td::Ref;
Config::Config(Ref<vm::Cell> config_root, const td::Bits256& config_addr, int _mode) Config::Config(Ref<vm::Cell> config_root, const td::Bits256& config_addr, int _mode)
@ -335,6 +336,59 @@ std::unique_ptr<vm::Dictionary> ShardConfig::extract_shard_hashes_dict(Ref<vm::C
} }
} }
td::Result<std::vector<int>> Config::unpack_param_dict(vm::Dictionary& dict) {
try {
std::vector<int> vect;
if (dict.check_for_each(
[&vect](Ref<vm::CellSlice> value, td::ConstBitPtr key, int key_len) {
bool ok = (key_len == 32 && value->empty_ext());
if (ok) {
vect.push_back((int)key.get_int(32));
}
return ok;
},
true)) {
return std::move(vect);
} else {
return td::Status::Error("invalid parameter list dictionary");
}
} catch (vm::VmError& vme) {
return td::Status::Error("error unpacking parameter list dictionary: "s + vme.get_msg());
}
}
td::Result<std::vector<int>> Config::unpack_param_dict(Ref<vm::Cell> dict_root) {
vm::Dictionary dict{std::move(dict_root), 32};
return unpack_param_dict(dict);
}
std::unique_ptr<vm::Dictionary> Config::get_param_dict(int idx) const {
return std::make_unique<vm::Dictionary>(get_config_param(idx), 32);
}
td::Result<std::vector<int>> Config::unpack_param_list(int idx) const {
return unpack_param_dict(*get_param_dict(idx));
}
bool Config::all_mandatory_params_defined(int* bad_idx_ptr) const {
auto res = get_mandatory_param_list();
if (res.is_error()) {
if (bad_idx_ptr) {
*bad_idx_ptr = -1;
}
return false;
}
for (int x : res.move_as_ok()) {
if (get_config_param(x).is_null()) {
if (bad_idx_ptr) {
*bad_idx_ptr = x;
}
return false;
}
}
return true;
}
std::unique_ptr<vm::AugmentedDictionary> ConfigInfo::create_accounts_dict() const { std::unique_ptr<vm::AugmentedDictionary> ConfigInfo::create_accounts_dict() const {
if (mode & needAccountsRoot) { if (mode & needAccountsRoot) {
return std::make_unique<vm::AugmentedDictionary>(accounts_root, 256, block::tlb::aug_ShardAccounts); return std::make_unique<vm::AugmentedDictionary>(accounts_root, 256, block::tlb::aug_ShardAccounts);

View File

@ -534,6 +534,21 @@ class Config {
bool create_stats_enabled() const { bool create_stats_enabled() const {
return has_capability(ton::capCreateStatsEnabled); return has_capability(ton::capCreateStatsEnabled);
} }
std::unique_ptr<vm::Dictionary> get_param_dict(int idx) const;
td::Result<std::vector<int>> unpack_param_list(int idx) const;
std::unique_ptr<vm::Dictionary> get_mandatory_param_dict() const {
return get_param_dict(9);
}
std::unique_ptr<vm::Dictionary> get_critical_param_dict() const {
return get_param_dict(10);
}
td::Result<std::vector<int>> get_mandatory_param_list() const {
return unpack_param_list(9);
}
td::Result<std::vector<int>> get_critical_param_list() const {
return unpack_param_list(10);
}
bool all_mandatory_params_defined(int* bad_idx_ptr = nullptr) const;
td::Result<ton::StdSmcAddress> get_dns_root_addr() const; td::Result<ton::StdSmcAddress> get_dns_root_addr() const;
bool set_block_id_ext(const ton::BlockIdExt& block_id_ext); bool set_block_id_ext(const ton::BlockIdExt& block_id_ext);
td::Result<std::vector<ton::StdSmcAddress>> get_special_smartcontracts(bool without_config = false) const; td::Result<std::vector<ton::StdSmcAddress>> get_special_smartcontracts(bool without_config = false) const;
@ -580,6 +595,8 @@ class Config {
static td::Result<std::unique_ptr<Config>> extract_from_state(Ref<vm::Cell> mc_state_root, int mode = 0); static td::Result<std::unique_ptr<Config>> extract_from_state(Ref<vm::Cell> mc_state_root, int mode = 0);
static td::Result<std::unique_ptr<Config>> extract_from_key_block(Ref<vm::Cell> key_block_root, int mode = 0); static td::Result<std::unique_ptr<Config>> extract_from_key_block(Ref<vm::Cell> key_block_root, int mode = 0);
static td::Result<std::pair<ton::UnixTime, ton::UnixTime>> unpack_validator_set_start_stop(Ref<vm::Cell> root); static td::Result<std::pair<ton::UnixTime, ton::UnixTime>> unpack_validator_set_start_stop(Ref<vm::Cell> root);
static td::Result<std::vector<int>> unpack_param_dict(vm::Dictionary& dict);
static td::Result<std::vector<int>> unpack_param_dict(Ref<vm::Cell> dict_root);
protected: protected:
Config(int _mode) : mode(_mode) { Config(int _mode) : mode(_mode) {

View File

@ -1555,9 +1555,17 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
Ref<vm::Cell> new_extra; Ref<vm::Cell> new_extra;
if (!block::sub_extra_currency(ap.remaining_balance.extra, req.extra, new_extra)) { if (!block::sub_extra_currency(ap.remaining_balance.extra, req.extra, new_extra)) {
LOG(DEBUG) << "not enough extra currency to send with the message"; LOG(DEBUG) << "not enough extra currency to send with the message: "
<< block::CurrencyCollection{0, req.extra}.to_str() << " required, only "
<< block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str() << " available";
return skip_invalid ? 0 : 38; // not enough (extra) funds return skip_invalid ? 0 : 38; // not enough (extra) funds
} }
if (ap.remaining_balance.extra.not_null() || req.extra.not_null()) {
LOG(DEBUG) << "subtracting extra currencies: "
<< block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str() << " minus "
<< block::CurrencyCollection{0, req.extra}.to_str() << " equals "
<< block::CurrencyCollection{0, new_extra}.to_str();
}
auto fwd_fee_mine = msg_prices.get_first_part(fwd_fee); auto fwd_fee_mine = msg_prices.get_first_part(fwd_fee);
auto fwd_fee_remain = fwd_fee - fwd_fee_mine; auto fwd_fee_remain = fwd_fee - fwd_fee_mine;
@ -1691,7 +1699,9 @@ int Transaction::try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap,
} }
} }
if (!block::sub_extra_currency(ap.remaining_balance.extra, reserve.extra, newc.extra)) { if (!block::sub_extra_currency(ap.remaining_balance.extra, reserve.extra, newc.extra)) {
LOG(DEBUG) << "not enough extra currency to reserve"; LOG(DEBUG) << "not enough extra currency to reserve: " << block::CurrencyCollection{0, reserve.extra}.to_str()
<< " required, only " << block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str()
<< " available";
if (mode & 2) { if (mode & 2) {
// TODO: process (mode & 2) correctly by setting res_extra := inf (reserve.extra, ap.remaining_balance.extra) // TODO: process (mode & 2) correctly by setting res_extra := inf (reserve.extra, ap.remaining_balance.extra)
} }
@ -1720,11 +1730,17 @@ bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) {
} }
bounce_phase = std::make_unique<BouncePhase>(); bounce_phase = std::make_unique<BouncePhase>();
BouncePhase& bp = *bounce_phase; BouncePhase& bp = *bounce_phase;
block::gen::Message::Record msg;
block::gen::CommonMsgInfo::Record_int_msg_info info; block::gen::CommonMsgInfo::Record_int_msg_info info;
if (!tlb::unpack_cell_inexact(in_msg, info)) { auto cs = vm::load_cell_slice(in_msg);
if (!(tlb::unpack(cs, info) && gen::t_Maybe_Either_StateInit_Ref_StateInit.skip(cs) && cs.have(1) &&
cs.have_refs((int)cs.prefetch_ulong(1)))) {
bounce_phase.reset(); bounce_phase.reset();
return false; return false;
} }
if (cs.fetch_ulong(1)) {
cs = vm::load_cell_slice(cs.prefetch_ref());
}
info.ihr_disabled = true; info.ihr_disabled = true;
info.bounce = false; info.bounce = false;
info.bounced = true; info.bounced = true;
@ -1776,10 +1792,26 @@ bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) {
&& block::tlb::t_Grams.store_long(cb, bp.fwd_fees) // fwd_fee:Grams && block::tlb::t_Grams.store_long(cb, bp.fwd_fees) // fwd_fee:Grams
&& cb.store_long_bool(info.created_lt, 64) // created_lt:uint64 && cb.store_long_bool(info.created_lt, 64) // created_lt:uint64
&& cb.store_long_bool(info.created_at, 32) // created_at:uint32 && cb.store_long_bool(info.created_at, 32) // created_at:uint32
&& cb.store_long_bool(0, 2) // init:(Maybe ...) state:(Either ..) && cb.store_bool_bool(false)); // init:(Maybe ...)
&& cb.finalize_to(bp.out_msg)); if (cfg.bounce_msg_body) {
int body_bits = std::min((int)cs.size(), cfg.bounce_msg_body);
if (cb.remaining_bits() >= body_bits + 33u) {
CHECK(cb.store_bool_bool(false) // body:(Either X ^X) -> left X
&& cb.store_long_bool(-1, 32) // int = -1 ("message type")
&& cb.append_bitslice(cs.prefetch_bits(body_bits))); // truncated message body
} else {
vm::CellBuilder cb2;
CHECK(cb.store_bool_bool(true) // body:(Either X ^X) -> right ^X
&& cb2.store_long_bool(-1, 32) // int = -1 ("message type")
&& cb2.append_bitslice(cs.prefetch_bits(body_bits)) // truncated message body
&& cb.store_builder_ref_bool(std::move(cb2))); // ^X
}
} else {
CHECK(cb.store_bool_bool(false)); // body:(Either ..)
}
CHECK(cb.finalize_to(bp.out_msg));
if (verbosity > 2) { if (verbosity > 2) {
std::cerr << "generated bounced message: "; LOG(INFO) << "generated bounced message: ";
block::gen::t_Message_Any.print_ref(std::cerr, bp.out_msg); block::gen::t_Message_Any.print_ref(std::cerr, bp.out_msg);
} }
out_msgs.push_back(bp.out_msg); out_msgs.push_back(bp.out_msg);

View File

@ -139,6 +139,7 @@ struct ComputePhaseConfig {
struct ActionPhaseConfig { struct ActionPhaseConfig {
int max_actions{255}; int max_actions{255};
int bounce_msg_body{0}; // usually 0 or 256 bits
MsgPrices fwd_std; MsgPrices fwd_std;
MsgPrices fwd_mc; // from/to masterchain MsgPrices fwd_mc; // from/to masterchain
const WorkchainSet* workchains{nullptr}; const WorkchainSet* workchains{nullptr};

View File

@ -0,0 +1,50 @@
/*
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
*/
namespace td {
class LinearAllocator {
std::size_t size;
char *ptr, *cur, *end;
public:
LinearAllocator(std::size_t _size) : size(_size) {
cur = ptr = (char*)malloc(size);
if (!ptr) {
throw std::bad_alloc();
}
end = ptr + size;
}
~LinearAllocator() {
free(ptr);
}
void* allocate(std::size_t count) {
char* t = cur;
cur += (count + 7) & -8;
if (cur > end) {
throw std::bad_alloc();
}
return (void*)t;
}
};
} // namespace td
inline void* operator new(std::size_t count, td::LinearAllocator& alloc) {
return alloc.allocate(count);
}

View File

@ -118,6 +118,24 @@ std::pair<RefInt256, RefInt256> divmod(RefInt256 x, RefInt256 y, int round_mode)
return std::make_pair(std::move(quot), std::move(x)); return std::make_pair(std::move(quot), std::move(x));
} }
RefInt256 muldiv(RefInt256 x, RefInt256 y, RefInt256 z, int round_mode) {
typename td::BigInt256::DoubleInt tmp{0};
tmp.add_mul(*x, *y);
RefInt256 quot{true};
tmp.mod_div(*z, quot.unique_write(), round_mode);
quot.write().normalize();
return quot;
}
std::pair<RefInt256, RefInt256> muldivmod(RefInt256 x, RefInt256 y, RefInt256 z, int round_mode) {
typename td::BigInt256::DoubleInt tmp{0};
tmp.add_mul(*x, *y);
RefInt256 quot{true};
tmp.mod_div(*z, quot.unique_write(), round_mode);
quot.write().normalize();
return std::make_pair(std::move(quot), td::make_refint(tmp));
}
RefInt256 operator&(RefInt256 x, RefInt256 y) { RefInt256 operator&(RefInt256 x, RefInt256 y) {
x.write() &= *y; x.write() &= *y;
return x; return x;

View File

@ -45,6 +45,8 @@ extern RefInt256 operator%(RefInt256 x, RefInt256 y);
extern RefInt256 div(RefInt256 x, RefInt256 y, int round_mode = -1); extern RefInt256 div(RefInt256 x, RefInt256 y, int round_mode = -1);
extern RefInt256 mod(RefInt256 x, RefInt256 y, int round_mode = -1); extern RefInt256 mod(RefInt256 x, RefInt256 y, int round_mode = -1);
extern std::pair<RefInt256, RefInt256> divmod(RefInt256 x, RefInt256 y, int round_mode = -1); extern std::pair<RefInt256, RefInt256> divmod(RefInt256 x, RefInt256 y, int round_mode = -1);
extern RefInt256 muldiv(RefInt256 x, RefInt256 y, RefInt256 z, int round_mode = -1);
extern std::pair<RefInt256, RefInt256> muldivmod(RefInt256 x, RefInt256 y, RefInt256 z, int round_mode = -1);
extern RefInt256 operator-(RefInt256 x); extern RefInt256 operator-(RefInt256 x);
extern RefInt256 operator&(RefInt256 x, RefInt256 y); extern RefInt256 operator&(RefInt256 x, RefInt256 y);
extern RefInt256 operator|(RefInt256 x, RefInt256 y); extern RefInt256 operator|(RefInt256 x, RefInt256 y);

View File

@ -1,7 +1,7 @@
library TVM_Asm library TVM_Asm
// simple TVM Assembler // simple TVM Assembler
variable @atend variable @atend
'nop @atend ! { "not in asm context" abort } @atend !
{ `normal eq? not abort"must be terminated by }>" } : @normal? { `normal eq? not abort"must be terminated by }>" } : @normal?
{ @atend @ 1 { @atend ! @normal? } does @atend ! } : @pushatend { @atend @ 1 { @atend ! @normal? } does @atend ! } : @pushatend
{ @pushatend <b } : <{ { @pushatend <b } : <{
@ -12,10 +12,11 @@ variable @atend
{ @atend @ 2 { @atend ! rot b> ref, swap @endblk } does @atend ! <b } : @| { @atend @ 2 { @atend ! rot b> ref, swap @endblk } does @atend ! <b } : @|
{ @atend @ 3 { @atend ! 2swap rot execute } does @atend ! <b } : @doafter<{ { @atend @ 3 { @atend ! 2swap rot execute } does @atend ! <b } : @doafter<{
{ over brembits <= } : @havebits { over brembits <= } : @havebits
{ rot + -rot + swap } : pair+
{ rot >= -rot <= and } : 2x<= { rot >= -rot <= and } : 2x<=
{ 2 pick brembitrefs 1- 2x<= } : @havebitrefs { 2 pick brembitrefs 1- 2x<= } : @havebitrefs
{ @havebits not ' @| if } : @ensurebits { @havebits ' @| ifnot } : @ensurebits
{ @havebitrefs not ' @| if } : @ensurebitrefs { @havebitrefs ' @| ifnot } : @ensurebitrefs
{ rot over @ensurebits -rot u, } : @simpleuop { rot over @ensurebits -rot u, } : @simpleuop
{ tuck sbitrefs @ensurebitrefs swap s, } : @addop { tuck sbitrefs @ensurebitrefs swap s, } : @addop
{ tuck bbitrefs @ensurebitrefs swap b+ } : @addopb { tuck bbitrefs @ensurebitrefs swap b+ } : @addopb
@ -27,6 +28,7 @@ variable @atend
{ 1 { <b swap s, swap 4 u, @addopb } does create } : @Defop(4u) { 1 { <b swap s, swap 4 u, @addopb } does create } : @Defop(4u)
{ 1 { <b swap s, rot 4 u, swap 4 u, @addopb } does create } : @Defop(4u,4u) { 1 { <b swap s, rot 4 u, swap 4 u, @addopb } does create } : @Defop(4u,4u)
{ 1 { <b swap s, swap ref, @addopb } does create } : @Defop(ref) { 1 { <b swap s, swap ref, @addopb } does create } : @Defop(ref)
{ 1 { <b swap s, rot ref, swap ref, @addopb } does create } : @Defop(ref*2)
{ <b 0xef 8 u, swap 12 i, b> } : si() { <b 0xef 8 u, swap 12 i, b> } : si()
// x mi ma -- ? // x mi ma -- ?
{ rot tuck >= -rot <= and } : @range { rot tuck >= -rot <= and } : @range
@ -272,10 +274,27 @@ x{8A} @Defop(ref) PUSHREFCONT
} cond } cond
} cond } cond
} dup : PUSHSLICE : SLICE } dup : PUSHSLICE : SLICE
{ tuck bbitrefs swap 16 + dup 7 and 3 -roll swap @havebitrefs // ( b' -- ? )
not rot or { bbitrefs or 0= } : @cont-empty?
{ swap b> PUSHREFCONT } { bbits 7 and 0= } : @cont-aligned?
{ over bbitrefs 2dup 120 0 2x<= // ( b b' -- ? )
{ bbitrefs over 7 and { 2drop drop false } {
swap 16 + swap @havebitrefs nip
} cond
} : @cont-fits?
// ( b b' -- ? )
{ bbitrefs over 7 and { 2drop drop false } {
32 1 pair+ @havebitrefs nip
} cond
} : @cont-ref-fit?
// ( b b' b'' -- ? )
{ over @cont-aligned? over @cont-aligned? and not { 2drop drop false } {
bbitrefs rot bbitrefs pair+ swap 32 + swap @havebitrefs nip
} cond
} : @two-cont-fit?
{ 2dup @cont-fits? not
{ b> PUSHREFCONT }
{ swap over bbitrefs 2dup 120 0 2x<=
{ drop swap x{9} s, swap 3 >> 4 u, swap b+ } { drop swap x{9} s, swap 3 >> 4 u, swap b+ }
{ rot x{8F_} s, swap 2 u, swap 3 >> 7 u, swap b+ } cond { rot x{8F_} s, swap 2 u, swap 3 >> 7 u, swap b+ } cond
} cond } cond
@ -320,12 +339,16 @@ x{A985} @Defop MULDIVR
x{A98C} @Defop MULDIVMOD x{A98C} @Defop MULDIVMOD
x{A9A4} @Defop MULRSHIFT x{A9A4} @Defop MULRSHIFT
x{A9A5} @Defop MULRSHIFTR x{A9A5} @Defop MULRSHIFTR
x{A9A6} @Defop MULRSHIFTC
x{A9B4} @Defop(8u+1) MULRSHIFT# x{A9B4} @Defop(8u+1) MULRSHIFT#
x{A9B5} @Defop(8u+1) MULRSHIFTR# x{A9B5} @Defop(8u+1) MULRSHIFTR#
x{A9B6} @Defop(8u+1) MULRSHIFTC#
x{A9C4} @Defop LSHIFTDIV x{A9C4} @Defop LSHIFTDIV
x{A9C5} @Defop LSHIFTDIVR x{A9C5} @Defop LSHIFTDIVR
x{A9C6} @Defop LSHIFTDIVC
x{A9D4} @Defop(8u+1) LSHIFT#DIV x{A9D4} @Defop(8u+1) LSHIFT#DIV
x{A9D5} @Defop(8u+1) LSHIFT#DIVR x{A9D5} @Defop(8u+1) LSHIFT#DIVR
x{A9D6} @Defop(8u+1) LSHIFT#DIVC
x{AA} @Defop(8u+1) LSHIFT# x{AA} @Defop(8u+1) LSHIFT#
x{AB} @Defop(8u+1) RSHIFT# x{AB} @Defop(8u+1) RSHIFT#
x{AC} @Defop LSHIFT x{AC} @Defop LSHIFT
@ -628,46 +651,80 @@ x{DB3F} @Defop RETDATA
x{DC} @Defop IFRET x{DC} @Defop IFRET
x{DD} @Defop IFNOTRET x{DD} @Defop IFNOTRET
x{DE} @Defop IF x{DE} @Defop IF
{ }> PUSHCONT IF } : }>IF
x{DF} @Defop IFNOT x{DF} @Defop IFNOT
{ }> PUSHCONT IFNOT } : }>IFNOT
' IFNOTRET : IF: ' IFNOTRET : IF:
' IFRET : IFNOT: ' IFRET : IFNOT:
x{E0} @Defop IFJMP x{E0} @Defop IFJMP
{ }> PUSHCONT IFJMP } : }>IFJMP
{ { @normal? PUSHCONT IFJMP } @doafter<{ } : IFJMP:<{
x{E1} @Defop IFNOTJMP x{E1} @Defop IFNOTJMP
{ }> PUSHCONT IFNOTJMP } : }>IFNOTJMP
{ { @normal? PUSHCONT IFNOTJMP } @doafter<{ } : IFNOTJMP:<{
x{E2} @Defop IFELSE x{E2} @Defop IFELSE
{ `else @endblk } : }>ELSE<{
{ `else: @endblk } : }>ELSE:
{ PUSHCONT { @normal? PUSHCONT IFELSE } @doafter<{ } : @doifelse
{ 1 { swap @normal? -rot PUSHCONT swap PUSHCONT IFELSE } does @doafter<{ } : @doifnotelse
{
{ dup `else eq?
{ drop @doifelse }
{ dup `else: eq?
{ drop PUSHCONT IFJMP }
{ @normal? PUSHCONT IF
} cond
} cond
} @doafter<{
} : IF:<{
{
{ dup `else eq?
{ drop @doifnotelse }
{ dup `else: eq?
{ drop PUSHCONT IFNOTJMP }
{ @normal? PUSHCONT IFNOT
} cond
} cond
} @doafter<{
} : IFNOT:<{
x{E300} @Defop(ref) IFREF x{E300} @Defop(ref) IFREF
x{E301} @Defop(ref) IFNOTREF x{E301} @Defop(ref) IFNOTREF
x{E302} @Defop(ref) IFJMPREF x{E302} @Defop(ref) IFJMPREF
x{E303} @Defop(ref) IFNOTJMPREF x{E303} @Defop(ref) IFNOTJMPREF
x{E30D} @Defop(ref) IFREFELSE
x{E30E} @Defop(ref) IFELSEREF
x{E30F} @Defop(ref*2) IFREFELSEREF
{ 16 1 @havebitrefs nip } : @refop-fits?
// b b1 [e0 e1 e2] -- b'
{ -rot dup @cont-empty? { drop swap 0 } {
2dup @cont-fits? { rot 1 } {
over @refop-fits? { b> rot 2 } {
swap @| swap 2dup @cont-fits? { rot 1 } {
b> rot 2
} cond } cond } cond } cond
[] execute
} : @run-cont-op
{ triple 1 ' @run-cont-op does create } : @def-cont-op
{ } { PUSHCONT IF } { IFREF } @def-cont-op IF-cont
{ IFRET } { PUSHCONT IFJMP } { IFJMPREF } @def-cont-op IFJMP-cont
{ } { PUSHCONT IFNOT } { IFNOTREF } @def-cont-op IFNOT-cont
{ IFNOTRET } { PUSHCONT IFNOTJMP } { IFNOTJMPREF } @def-cont-op IFNOTJMP-cont
{ dup 2over rot } : 3dup
recursive IFELSE-cont2 {
dup @cont-empty? { drop IF-cont } {
over @cont-empty? { nip IFNOT-cont } {
3dup @two-cont-fit? { -rot PUSHCONT swap PUSHCONT IFELSE } {
3dup nip @cont-ref-fit? { rot swap PUSHCONT swap b> IFREFELSE } {
3dup drop @cont-ref-fit? { -rot PUSHCONT swap b> IFELSEREF } {
rot 32 2 @havebitrefs { rot b> rot b> IFREFELSEREF } {
@| -rot IFELSE-cont2
} cond } cond } cond } cond } cond } cond
} swap !
{ }> IF-cont } : }>IF
{ }> IFNOT-cont } : }>IFNOT
{ }> IFJMP-cont } : }>IFJMP
{ }> IFNOTJMP-cont } : }>IFNOTJMP
{ { @normal? IFJMP-cont } @doafter<{ } : IFJMP:<{
{ { @normal? IFNOTJMP-cont } @doafter<{ } : IFNOTJMP:<{
{ `else @endblk } : }>ELSE<{
{ `else: @endblk } : }>ELSE:
{ 1 { swap @normal? swap IFELSE-cont2 } does @doafter<{ } : @doifelse
{ 1 { swap @normal? IFELSE-cont2 } does @doafter<{ } : @doifnotelse
{
{ dup `else eq?
{ drop @doifelse }
{ dup `else: eq?
{ drop IFJMP-cont }
{ @normal? IF-cont
} cond
} cond
} @doafter<{
} : IF:<{
{
{ dup `else eq?
{ drop @doifnotelse }
{ dup `else: eq?
{ drop IFNOTJMP-cont }
{ @normal? IFNOT-cont
} cond
} cond
} @doafter<{
} : IFNOT:<{
x{E304} @Defop CONDSEL x{E304} @Defop CONDSEL
x{E305} @Defop CONDSELCHK x{E305} @Defop CONDSELCHK
x{E308} @Defop IFRETALT x{E308} @Defop IFRETALT
@ -676,18 +733,22 @@ x{E309} @Defop IFNOTRETALT
{ <b x{E3B_} swap 5 u, @addopb } : IFNBITJMP { <b x{E3B_} swap 5 u, @addopb } : IFNBITJMP
{ <b x{E3D_} swap 5 u, swap ref, @addopb } : IFBITJMPREF { <b x{E3D_} swap 5 u, swap ref, @addopb } : IFBITJMPREF
{ <b x{E3F_} swap 5 u, swap ref, @addopb } : IFNBITJMPREF { <b x{E3F_} swap 5 u, swap ref, @addopb } : IFNBITJMPREF
x{E4} @Defop REPEAT x{E4} @Defop REPEAT
{ }> PUSHCONT REPEAT } : }>REPEAT
{ { @normal? PUSHCONT REPEAT } @doafter<{ } : REPEAT:<{
x{E5} dup @Defop REPEATEND @Defop REPEAT: x{E5} dup @Defop REPEATEND @Defop REPEAT:
x{E6} @Defop UNTIL x{E6} @Defop UNTIL
{ }> PUSHCONT UNTIL } : }>UNTIL
{ { @normal? PUSHCONT UNTIL } @doafter<{ } : UNTIL:<{
x{E7} dup @Defop UNTILEND @Defop UNTIL: x{E7} dup @Defop UNTILEND @Defop UNTIL:
x{E8} @Defop WHILE x{E8} @Defop WHILE
x{E9} @Defop WHILEEND x{E9} @Defop WHILEEND
x{EA} @Defop AGAIN
x{EB} dup @Defop AGAINEND @Defop AGAIN:
{ `do @endblk } : }>DO<{ { `do @endblk } : }>DO<{
{ `do: @endblk } : }>DO: { `do: @endblk } : }>DO:
{ }> PUSHCONT REPEAT } : }>REPEAT
{ { @normal? PUSHCONT REPEAT } @doafter<{ } : REPEAT:<{
{ }> PUSHCONT UNTIL } : }>UNTIL
{ { @normal? PUSHCONT UNTIL } @doafter<{ } : UNTIL:<{
{ PUSHCONT { @normal? PUSHCONT WHILE } @doafter<{ } : @dowhile { PUSHCONT { @normal? PUSHCONT WHILE } @doafter<{ } : @dowhile
{ {
{ dup `do eq? { dup `do eq?
@ -696,10 +757,34 @@ x{E9} @Defop WHILEEND
} cond } cond
} @doafter<{ } @doafter<{
} : WHILE:<{ } : WHILE:<{
x{EA} @Defop AGAIN
{ }> PUSHCONT AGAIN } : }>AGAIN { }> PUSHCONT AGAIN } : }>AGAIN
{ { @normal? PUSHCONT AGAIN } @doafter<{ } : AGAIN:<{ { { @normal? PUSHCONT AGAIN } @doafter<{ } : AGAIN:<{
x{EB} dup @Defop AGAINEND @Defop AGAIN:
x{E314} @Defop REPEATBRK
x{E315} @Defop REPEATENDBRK
x{E316} @Defop UNTILBRK
x{E317} dup @Defop UNTILENDBRK @Defop UNTILBRK:
x{E318} @Defop WHILEBRK
x{E319} @Defop WHILEENDBRK
x{E31A} @Defop AGAINBRK
x{E31B} dup @Defop AGAINENDBRK @Defop AGAINBRK:
{ }> PUSHCONT REPEATBRK } : }>REPEATBRK
{ { @normal? PUSHCONT REPEATBRK } @doafter<{ } : REPEATBRK:<{
{ }> PUSHCONT UNTILBRK } : }>UNTILBRK
{ { @normal? PUSHCONT UNTILBRK } @doafter<{ } : UNTILBRK:<{
{ PUSHCONT { @normal? PUSHCONT WHILEBRK } @doafter<{ } : @dowhile
{
{ dup `do eq?
{ drop @dowhile }
{ `do: eq? not abort"`}>DO<{` expected" PUSHCONT WHILEENDBRK
} cond
} @doafter<{
} : WHILEBRK:<{
{ }> PUSHCONT AGAINBRK } : }>AGAINBRK
{ { @normal? PUSHCONT AGAINBRK } @doafter<{ } : AGAINBRK:<{
// //
// continuation stack manipulation and continuation creation // continuation stack manipulation and continuation creation
// //
@ -745,6 +830,8 @@ x{EDF6} @Defop THENRET
x{EDF7} @Defop THENRETALT x{EDF7} @Defop THENRETALT
x{EDF8} @Defop INVERT x{EDF8} @Defop INVERT
x{EDF9} @Defop BOOLEVAL x{EDF9} @Defop BOOLEVAL
x{EDFA} @Defop SAMEALT
x{EDFB} @Defop SAMEALTSAVE
// x{EE} is BLESSARGS // x{EE} is BLESSARGS
// //
// dictionary subroutine call/jump primitives // dictionary subroutine call/jump primitives

View File

@ -111,6 +111,8 @@ variable base
{ cdr cdr } : cddr { cdr cdr } : cddr
{ cdr cdr car } : caddr { cdr cdr car } : caddr
{ null ' cons rot times } : list { null ' cons rot times } : list
{ -rot pair swap ! } : 2!
{ @ unpair } : 2@
{ true (atom) drop } : atom { true (atom) drop } : atom
{ bl word atom 1 'nop } ::_ ` { bl word atom 1 'nop } ::_ `
{ hole dup 1 { @ execute } does create } : recursive { hole dup 1 { @ execute } does create } : recursive
@ -121,13 +123,18 @@ variable base
{ 0 word -trailing scan-until-word 1 'nop } ::_ $<< { 0 word -trailing scan-until-word 1 'nop } ::_ $<<
{ 0x40 runvmx } : runvmcode { 0x40 runvmx } : runvmcode
{ 0x48 runvmx } : gasrunvmcode { 0x48 runvmx } : gasrunvmcode
{ 0xc8 runvmx } : gas2runvmcode
{ 0x43 runvmx } : runvmdict { 0x43 runvmx } : runvmdict
{ 0x4b runvmx } : gasrunvmdict { 0x4b runvmx } : gasrunvmdict
{ 0xcb runvmx } : gas2runvmdict
{ 0x45 runvmx } : runvm { 0x45 runvmx } : runvm
{ 0x4d runvmx } : gasrunvm { 0x4d runvmx } : gasrunvm
{ 0xcd runvmx } : gas2runvm
{ 0x55 runvmx } : runvmctx { 0x55 runvmx } : runvmctx
{ 0x5d runvmx } : gasrunvmctx { 0x5d runvmx } : gasrunvmctx
{ 0xdd runvmx } : gas2runvmctx
{ 0x75 runvmx } : runvmctxact { 0x75 runvmx } : runvmctxact
{ 0x7d runvmx } : gasrunvmctxact { 0x7d runvmx } : gasrunvmctxact
{ 0xfd runvmx } : gas2runvmctxact
{ 0x35 runvmx } : runvmctxactq { 0x35 runvmx } : runvmctxactq
{ 0x3d runvmx } : gasrunvmctxactq { 0x3d runvmx } : gasrunvmctxactq

View File

@ -111,6 +111,42 @@ recursive list-map {
swap uncons -rot over execute -rot list-map cons swap uncons -rot over execute -rot list-map cons
} cond } cond
} swap ! } swap !
variable ctxdump variable curctx
// (a1 .. an) e -- executes e for a1, ..., an
{ ctxdump @ curctx @ ctxdump 2! curctx 2!
{ curctx 2@ over null? not } { swap uncons rot tuck curctx 2! execute }
while 2drop ctxdump 2@ curctx ! ctxdump !
} : list-foreach
forget ctxdump forget curctx
//
// Experimental implementation of `for` loops with index
//
variable loopdump variable curloop
{ curloop @ loopdump @ loopdump 2! } : push-loop-ctx
{ loopdump 2@ loopdump ! curloop ! } : pop-loop-ctx
// ilast i0 e -- executes e for i=i0,i0+1,...,ilast-1
{ -rot 2dup > {
push-loop-ctx {
triple dup curloop ! first execute curloop @ untriple 1+ 2dup <=
} until pop-loop-ctx
} if 2drop drop
} : for
// ilast i0 e -- same as 'for', but pushes current index i before executing e
{ -rot 2dup > {
push-loop-ctx {
triple dup curloop ! untriple nip swap execute curloop @ untriple 1+ 2dup <=
} until pop-loop-ctx
} if 2drop drop
} : for-i
// ( -- i ) Returns innermost loop index
{ curloop @ third } : i
// ( -- j ) Returns outer loop index
{ loopdump @ car third } : j
{ loopdump @ cadr third } : k
forget curloop forget loopdump
// //
// create Lisp-style lists using words "(" and ")" // create Lisp-style lists using words "(" and ")"
// //

View File

@ -77,15 +77,17 @@ library TonUtil // TON Blockchain Fift Library
1000000000 constant Gram 1000000000 constant Gram
{ Gram swap */r } : Gram*/ { Gram swap */r } : Gram*/
{ Gram * } : Gram* { Gram * } : Gram*
{ (number) dup { 1- ' Gram*/ ' Gram* cond true } if
} : $>GR?
// ( S -- nanograms ) // ( S -- nanograms )
{ (number) ?dup 0= abort"not a valid Gram amount" { $>GR? not abort"not a valid Gram amount"
1- ' Gram*/ ' Gram* cond
} : $>GR } : $>GR
{ bl word $>GR 1 'nop } ::_ GR$ { bl word $>GR 1 'nop } ::_ GR$
// ( nanograms -- S ) // ( nanograms -- S )
{ dup abs <# ' # 9 times char . hold #s rot sign #> { dup abs <# ' # 9 times char . hold #s rot sign #>
nip -trailing0 } : (.GR) nip -trailing0 } : (.GR)
{ (.GR) ."GR$" type space } : .GR { (.GR) ."GR$" type } : .GR_
{ .GR_ space } : .GR
// b x -- b' ( serializes a Gram amount ) // b x -- b' ( serializes a Gram amount )
{ -1 { 1+ 2dup 8 * ufits } until { -1 { 1+ 2dup 8 * ufits } until
@ -105,19 +107,66 @@ nip -trailing0 } : (.GR)
' VarUInt32, : val, ' VarUInt32, : val,
' VarUInt32@ : val@ ' VarUInt32@ : val@
// d k v -- d' // d k v -- d'
{ <b swap val, b> <s swap rot cc-key-bits idict! not abort"cannot add key-value to CurrencyCollection" } : +ccpair { <b swap val, b> <s swap rot cc-key-bits idict!+ not abort"cannot add key-value to CurrencyCollection"
} : +newccpair
{ dup { -rot tuck swap cc-key-bits idict@- { val@ 2swap -rot + } { swap rot } cond +newccpair
} { 2drop } cond
} : +ccpair
dictnew constant cc0 // zero currency collection dictnew constant cc0 // zero currency collection
// ( v k -- d ) Creates currency collection representing v units of currency k // ( v k -- d ) Creates currency collection representing v units of currency k
{ cc0 swap rot +ccpair } : of-cc { cc0 swap rot +ccpair } : of-cc
{ dictnew { over null? not } { swap uncons -rot unpair +ccpair } while nip } : list>cc { dictnew { over null? not } { swap uncons -rot unpair +ccpair } while nip } : list>cc
{ dup null? { ."(null) " drop } { val@ . } cond } dup : .maybeVarUInt32 : .val { dup null? { ."(null)" drop } { val@ ._ } cond } dup : .maybeVarUInt32 : .val
{ cc-key-bits { swap 32 1<< rmod . ."-> " .val ."; " true } dictforeach drop cr } : .cc { swap cc-key-bits { rot { ."+" } if .val ."*$" ._ true true } idictforeach drop } : (.cc)
{ false (.cc) { ."0" } ifnot } : .cc_
{ .cc_ space } : .cc
{ true (.cc) drop } : .+cc_
{ .+cc_ space } : .+cc
{ cc-key-bits { rot . ."-> " swap .val .val ."; " true } dictdiff drop cr } : show-cc-diff { cc-key-bits { rot . ."-> " swap .val .val ."; " true } dictdiff drop cr } : show-cc-diff
{ cc-key-bits { val@ swap val@ + val, true } dictmerge } : cc+ { cc-key-bits { val@ swap val@ + val, true } dictmerge } : cc+
{ null swap cc-key-bits { val@ pair swap cons true } dictforeach drop } : cc>list-rev { null swap cc-key-bits { val@ pair swap cons true } idictforeach drop } : cc>list-rev
{ cc>list-rev list-reverse } : cc>list { cc>list-rev list-reverse } : cc>list
forget val, forget val@ forget .val forget val, forget val@ forget .val
// ( S -- x -1 or 0 )
{ (number) dup 2 = { -rot 2drop } if 1 = } : int?
{ int? dup { drop dup 0< { drop false } { true } cond } if } : pos-int?
// ( S -- k v -1 or 0 ) Parses expression <value>*<currency> or <value>*$<currency>
{ dup "*" $pos dup 0< { 2drop false } {
$| dup $len 2 < { 2drop false } {
1 $| nip dup 1 $| swap "$" $= { swap } if drop
int? dup { over 32 fits { 2drop false } ifnot } if
not { drop false } {
swap pos-int? not { drop false } {
true
} cond } cond } cond } cond
} : cc-key-value?
// ( S -- D -1 or 0 ) Parses an extra currency collection
// e.g. "10000*$3+7777*$-11" means "10000 units of currency #3 and 7777 units of currency #-11"
{ dictnew { // S D
swap dup "+" $pos dup 0< { drop null -rot } { $| 1 $| nip -rot } cond
cc-key-value? { +ccpair over null? dup { rot drop true } if } { 2drop false true } cond
} until
} : $>xcc?
{ $>xcc? not abort"invalid extra currency collection" } : $>xcc
{ char } word dup $len { $>xcc } { drop dictnew } cond 1 'nop } ::_ CX{
// complete currency collections
{ $>xcc? { true } { drop false } cond } : end-parse-cc
// ( S -- x D -1 or 0 ) Parses a currency collection
// e.g. "1.2+300*$2" means "1200000000ng plus 300 units of currency #2"
{ 0 swap dup "+" $pos dup 0< { drop dup
$>GR? { nip nip dictnew true } { end-parse-cc } cond
} { over swap $| swap $>GR? { 2swap 2drop swap 1 $| nip } { drop
} cond end-parse-cc } cond
} : $>cc?
{ $>cc? not abort"invalid currency collection" } : $>cc
{ char } word dup $len { $>cc } { drop 0 dictnew } cond 2 'nop } ::_ CC{
// ( x D -- )
{ swap ?dup { .GR_ .+cc_ } { .cc_ } cond } : .GR+cc_
{ .GR+cc_ space } : .GR+cc
{ -rot Gram, swap dict, } : Gram+cc,
// Libraries // Libraries
// ( -- D ) New empty library collection // ( -- D ) New empty library collection
' dictnew : Libs{ ' dictnew : Libs{

View File

@ -177,28 +177,15 @@ void interpret_divmod(vm::Stack& stack, int round_mode) {
} }
void interpret_times_div(vm::Stack& stack, int round_mode) { void interpret_times_div(vm::Stack& stack, int round_mode) {
auto z = stack.pop_int(); auto z = stack.pop_int(), y = stack.pop_int(), x = stack.pop_int();
auto y = stack.pop_int(); stack.push_int(muldiv(std::move(x), std::move(y), std::move(z), round_mode));
auto x = stack.pop_int();
typename td::BigInt256::DoubleInt tmp{0};
tmp.add_mul(*x, *y);
auto q = td::make_refint();
tmp.mod_div(*z, q.unique_write(), round_mode);
q.unique_write().normalize();
stack.push_int(std::move(q));
} }
void interpret_times_divmod(vm::Stack& stack, int round_mode) { void interpret_times_divmod(vm::Stack& stack, int round_mode) {
auto z = stack.pop_int(); auto z = stack.pop_int(), y = stack.pop_int(), x = stack.pop_int();
auto y = stack.pop_int(); auto dm = muldivmod(std::move(x), std::move(y), std::move(z));
auto x = stack.pop_int(); stack.push_int(std::move(dm.first));
typename td::BigInt256::DoubleInt tmp{0}; stack.push_int(std::move(dm.second));
tmp.add_mul(*x, *y);
auto q = td::make_refint();
tmp.mod_div(*z, q.unique_write(), round_mode);
q.unique_write().normalize();
stack.push_int(std::move(q));
stack.push_int(td::make_refint(tmp));
} }
void interpret_times_mod(vm::Stack& stack, int round_mode) { void interpret_times_mod(vm::Stack& stack, int round_mode) {
@ -2242,6 +2229,7 @@ std::vector<Ref<vm::Cell>> get_vm_libraries() {
// +16 = load c7 (smart-contract context) // +16 = load c7 (smart-contract context)
// +32 = return c5 (actions) // +32 = return c5 (actions)
// +64 = log vm ops to stderr // +64 = log vm ops to stderr
// +128 = pop hard gas limit (enabled by ACCEPT) from stack as well
void interpret_run_vm(IntCtx& ctx, int mode) { void interpret_run_vm(IntCtx& ctx, int mode) {
if (mode < 0) { if (mode < 0) {
mode = ctx.stack.pop_smallint_range(0xff); mode = ctx.stack.pop_smallint_range(0xff);
@ -2249,7 +2237,13 @@ void interpret_run_vm(IntCtx& ctx, int mode) {
bool with_data = mode & 4; bool with_data = mode & 4;
Ref<vm::Tuple> c7; Ref<vm::Tuple> c7;
Ref<vm::Cell> data, actions; Ref<vm::Cell> data, actions;
long long gas_max = (mode & 128) ? ctx.stack.pop_long_range(vm::GasLimits::infty) : vm::GasLimits::infty;
long long gas_limit = (mode & 8) ? ctx.stack.pop_long_range(vm::GasLimits::infty) : vm::GasLimits::infty; long long gas_limit = (mode & 8) ? ctx.stack.pop_long_range(vm::GasLimits::infty) : vm::GasLimits::infty;
if (!(mode & 128)) {
gas_max = gas_limit;
} else {
gas_max = std::max(gas_max, gas_limit);
}
if (mode & 16) { if (mode & 16) {
c7 = ctx.stack.pop_tuple(); c7 = ctx.stack.pop_tuple();
} }
@ -2259,7 +2253,7 @@ void interpret_run_vm(IntCtx& ctx, int mode) {
auto cs = ctx.stack.pop_cellslice(); auto cs = ctx.stack.pop_cellslice();
OstreamLogger ostream_logger(ctx.error_stream); OstreamLogger ostream_logger(ctx.error_stream);
auto log = create_vm_log((mode & 64) && ctx.error_stream ? &ostream_logger : nullptr); auto log = create_vm_log((mode & 64) && ctx.error_stream ? &ostream_logger : nullptr);
vm::GasLimits gas{gas_limit}; vm::GasLimits gas{gas_limit, gas_max};
int res = int res =
vm::run_vm_code(cs, ctx.stack, mode & 3, &data, log, nullptr, &gas, get_vm_libraries(), std::move(c7), &actions); vm::run_vm_code(cs, ctx.stack, mode & 3, &data, log, nullptr, &gas, get_vm_libraries(), std::move(c7), &actions);
ctx.stack.push_smallint(res); ctx.stack.push_smallint(res);

View File

@ -427,9 +427,7 @@ AsmOp compile_negate(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
return exec_op("NEGATE", 1); return exec_op("NEGATE", 1);
} }
AsmOp compile_mul(std::vector<VarDescr>& res, std::vector<VarDescr>& args) { AsmOp compile_mul_internal(VarDescr& r, VarDescr& x, VarDescr& y) {
assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1];
if (x.is_int_const() && y.is_int_const()) { if (x.is_int_const() && y.is_int_const()) {
r.set_const(x.int_const * y.int_const); r.set_const(x.int_const * y.int_const);
x.unused(); x.unused();
@ -492,6 +490,11 @@ AsmOp compile_mul(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
return exec_op("MUL", 2); return exec_op("MUL", 2);
} }
AsmOp compile_mul(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
assert(res.size() == 1 && args.size() == 2);
return compile_mul_internal(res[0], args[0], args[1]);
}
AsmOp compile_lshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args) { AsmOp compile_lshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
assert(res.size() == 1 && args.size() == 2); assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1]; VarDescr &r = res[0], &x = args[0], &y = args[1];
@ -566,9 +569,7 @@ AsmOp compile_rshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args, in
return exec_op(rshift, 2); return exec_op(rshift, 2);
} }
AsmOp compile_div(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) { AsmOp compile_div_internal(VarDescr& r, VarDescr& x, VarDescr& y, int round_mode) {
assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1];
if (x.is_int_const() && y.is_int_const()) { if (x.is_int_const() && y.is_int_const()) {
r.set_const(div(x.int_const, y.int_const, round_mode)); r.set_const(div(x.int_const, y.int_const, round_mode));
x.unused(); x.unused();
@ -608,6 +609,11 @@ AsmOp compile_div(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int r
return exec_op(op, 2); return exec_op(op, 2);
} }
AsmOp compile_div(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) {
assert(res.size() == 1 && args.size() == 2);
return compile_div_internal(res[0], args[0], args[1], round_mode);
}
AsmOp compile_mod(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) { AsmOp compile_mod(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) {
assert(res.size() == 1 && args.size() == 2); assert(res.size() == 1 && args.size() == 2);
VarDescr &r = res[0], &x = args[0], &y = args[1]; VarDescr &r = res[0], &x = args[0], &y = args[1];
@ -648,6 +654,87 @@ AsmOp compile_mod(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int r
return exec_op(op, 2); return exec_op(op, 2);
} }
AsmOp compile_muldiv(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int round_mode) {
assert(res.size() == 1 && args.size() == 3);
VarDescr &r = res[0], &x = args[0], &y = args[1], &z = args[2];
if (x.is_int_const() && y.is_int_const() && z.is_int_const()) {
r.set_const(muldiv(x.int_const, y.int_const, z.int_const, round_mode));
x.unused();
y.unused();
z.unused();
return push_const(r.int_const);
}
if (x.always_zero() || y.always_zero()) {
// dubious optimization for z=0...
x.unused();
y.unused();
z.unused();
r.set_const(td::make_refint(0));
return push_const(r.int_const);
}
char c = (round_mode < 0) ? 0 : (round_mode > 0 ? 'C' : 'R');
r.val = emulate_div(emulate_mul(x.val, y.val), z.val);
if (z.is_int_const()) {
if (*z.int_const == 0) {
x.unused();
y.unused();
z.unused();
r.set_const(div(z.int_const, z.int_const));
return push_const(r.int_const);
}
if (*z.int_const == 1) {
z.unused();
return compile_mul_internal(r, x, y);
}
}
if (y.is_int_const() && *y.int_const == 1) {
y.unused();
return compile_div_internal(r, x, z, round_mode);
}
if (x.is_int_const() && *x.int_const == 1) {
x.unused();
return compile_div_internal(r, y, z, round_mode);
}
if (z.is_int_const()) {
int k = is_pos_pow2(z.int_const);
if (k > 0) {
z.unused();
std::string op = "MULRSHIFT";
if (c) {
op += c;
}
return exec_arg_op(op + '#', k, 2);
}
}
if (y.is_int_const()) {
int k = is_pos_pow2(y.int_const);
if (k > 0) {
y.unused();
std::string op = "LSHIFT#DIV";
if (c) {
op += c;
}
return exec_arg_op(op, k, 2);
}
}
if (x.is_int_const()) {
int k = is_pos_pow2(x.int_const);
if (k > 0) {
x.unused();
std::string op = "LSHIFT#DIV";
if (c) {
op += c;
}
return exec_arg_op(op, k, 2);
}
}
std::string op = "MULDIV";
if (c) {
op += c;
}
return exec_op(op, 3);
}
int compute_compare(td::RefInt256 x, td::RefInt256 y, int mode) { int compute_compare(td::RefInt256 x, td::RefInt256 y, int mode) {
int s = td::cmp(x, y); int s = td::cmp(x, y);
if (mode == 7) { if (mode == 7) {
@ -933,8 +1020,9 @@ void define_builtins() {
define_builtin_func("^_&=_", arith_bin_op, AsmOp::Custom("AND", 2)); define_builtin_func("^_&=_", arith_bin_op, AsmOp::Custom("AND", 2));
define_builtin_func("^_|=_", arith_bin_op, AsmOp::Custom("OR", 2)); define_builtin_func("^_|=_", arith_bin_op, AsmOp::Custom("OR", 2));
define_builtin_func("^_^=_", arith_bin_op, AsmOp::Custom("XOR", 2)); define_builtin_func("^_^=_", arith_bin_op, AsmOp::Custom("XOR", 2));
define_builtin_func("muldivr", TypeExpr::new_map(Int3, Int), AsmOp::Custom("MULDIVR", 3)); define_builtin_func("muldiv", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, -1));
define_builtin_func("muldiv", TypeExpr::new_map(Int3, Int), AsmOp::Custom("MULDIV", 3)); define_builtin_func("muldivr", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, 0));
define_builtin_func("muldivc", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, 1));
define_builtin_func("muldivmod", TypeExpr::new_map(Int3, Int2), AsmOp::Custom("MULDIVMOD", 3, 2)); define_builtin_func("muldivmod", TypeExpr::new_map(Int3, Int2), AsmOp::Custom("MULDIVMOD", 3, 2));
define_builtin_func("_==_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 2)); define_builtin_func("_==_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 2));
define_builtin_func("_!=_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 5)); define_builtin_func("_!=_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 5));

View File

@ -575,9 +575,9 @@ bool Optimizer::find_at_least(int pb) {
(is_push_rotrev(&i) && rewrite(AsmOp::Push(i), AsmOp::Custom("-ROT"))) || (is_push_rotrev(&i) && rewrite(AsmOp::Push(i), AsmOp::Custom("-ROT"))) ||
(is_push_xchg(&i, &j, &k) && rewrite(AsmOp::Push(i), AsmOp::Xchg(j, k))) || (is_push_xchg(&i, &j, &k) && rewrite(AsmOp::Push(i), AsmOp::Xchg(j, k))) ||
(is_reverse(&i, &j) && rewrite(AsmOp::BlkReverse(i, j))) || (is_reverse(&i, &j) && rewrite(AsmOp::BlkReverse(i, j))) ||
(is_blkdrop2(&i, &j) && rewrite(AsmOp::BlkDrop2(i, j))) ||
(is_nip_seq(&i, &j) && rewrite(AsmOp::Xchg(i, j), AsmOp::BlkDrop(i))) || (is_nip_seq(&i, &j) && rewrite(AsmOp::Xchg(i, j), AsmOp::BlkDrop(i))) ||
(is_pop_blkdrop(&i, &k) && rewrite(AsmOp::Pop(i), AsmOp::BlkDrop(k))) || (is_pop_blkdrop(&i, &k) && rewrite(AsmOp::Pop(i), AsmOp::BlkDrop(k))) ||
(is_blkdrop2(&i, &j) && rewrite(AsmOp::BlkDrop2(i, j))) ||
(is_2pop_blkdrop(&i, &j, &k) && (k >= 3 && k <= 13 && i != j + 1 && i <= 15 && j <= 14 (is_2pop_blkdrop(&i, &j, &k) && (k >= 3 && k <= 13 && i != j + 1 && i <= 15 && j <= 14
? rewrite(AsmOp::Xchg2(j + 1, i), AsmOp::BlkDrop(k + 2)) ? rewrite(AsmOp::Xchg2(j + 1, i), AsmOp::BlkDrop(k + 2))
: rewrite(AsmOp::Pop(i), AsmOp::Pop(j), AsmOp::BlkDrop(k)))) || : rewrite(AsmOp::Pop(i), AsmOp::Pop(j), AsmOp::BlkDrop(k)))) ||

View File

@ -1288,7 +1288,9 @@ void parse_func_def(Lexer& lex) {
sym::close_scope(lex); sym::close_scope(lex);
} }
bool parse_source(std::istream* is, const src::FileDescr* fdescr) { std::vector<const src::FileDescr*> source_fdescr;
bool parse_source(std::istream* is, src::FileDescr* fdescr) {
src::SourceReader reader{is, fdescr}; src::SourceReader reader{is, fdescr};
Lexer lex{reader, true, ";,()[] ~."}; Lexer lex{reader, true, ";,()[] ~."};
while (lex.tp() != _Eof) { while (lex.tp() != _Eof) {
@ -1306,6 +1308,7 @@ bool parse_source_file(const char* filename) {
throw src::Fatal{"source file name is an empty string"}; throw src::Fatal{"source file name is an empty string"};
} }
src::FileDescr* cur_source = new src::FileDescr{filename}; src::FileDescr* cur_source = new src::FileDescr{filename};
source_fdescr.push_back(cur_source);
std::ifstream ifs{filename}; std::ifstream ifs{filename};
if (ifs.fail()) { if (ifs.fail()) {
throw src::Fatal{std::string{"cannot open source file `"} + filename + "`"}; throw src::Fatal{std::string{"cannot open source file `"} + filename + "`"};
@ -1314,7 +1317,9 @@ bool parse_source_file(const char* filename) {
} }
bool parse_source_stdin() { bool parse_source_stdin() {
return parse_source(&std::cin, new src::FileDescr{"stdin", true}); src::FileDescr* cur_source = new src::FileDescr{"stdin", true};
source_fdescr.push_back(cur_source);
return parse_source(&std::cin, cur_source);
} }
} // namespace funC } // namespace funC

View File

@ -14,9 +14,10 @@
You should have received a copy of the GNU Lesser General Public License 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/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "srcread.h" #include "srcread.h"
#include <algorithm>
namespace src { namespace src {
@ -34,9 +35,47 @@ std::ostream& operator<<(std::ostream& os, const Fatal& fatal) {
return os << fatal.get_msg(); return os << fatal.get_msg();
} }
const char* FileDescr::convert_offset(long offset, long* line_no, long* line_pos, long* line_size) const {
long lno = 0, lpos = -1, lsize = 0;
const char* lstart = nullptr;
if (offset >= 0 && offset < (long)text.size()) {
auto it = std::upper_bound(line_offs.begin(), line_offs.end(), offset);
lno = it - line_offs.begin();
if (lno && it != line_offs.end()) {
lsize = it[0] - it[-1];
lpos = offset - it[-1];
lstart = text.data() + it[-1];
}
} else {
lno = (long)line_offs.size();
}
if (line_no) {
*line_no = lno;
}
if (line_pos) {
*line_pos = lpos;
}
if (line_size) {
*line_size = lsize;
}
return lstart;
}
const char* FileDescr::push_line(std::string new_line) {
if (line_offs.empty()) {
line_offs.push_back(0);
}
std::size_t cur_size = text.size();
text += new_line;
text += '\0';
line_offs.push_back((long)text.size());
return text.data() + cur_size;
}
void SrcLocation::show(std::ostream& os) const { void SrcLocation::show(std::ostream& os) const {
os << fdescr; os << fdescr;
if (line_no > 0) { long line_no, line_pos;
if (fdescr && convert_pos(&line_no, &line_pos)) {
os << ':' << line_no; os << ':' << line_no;
if (line_pos >= 0) { if (line_pos >= 0) {
os << ':' << (line_pos + 1); os << ':' << (line_pos + 1);
@ -45,13 +84,15 @@ void SrcLocation::show(std::ostream& os) const {
} }
bool SrcLocation::show_context(std::ostream& os) const { bool SrcLocation::show_context(std::ostream& os) const {
if (text.empty() || line_pos < 0 || (unsigned)line_pos > text.size()) { long line_no, line_pos, line_size;
if (!fdescr || !convert_pos(&line_no, &line_pos, &line_size)) {
return false; return false;
} }
bool skip_left = (line_pos > 200), skip_right = (line_pos + 200u < text.size()); bool skip_left = (line_pos > 200), skip_right = (line_pos + 200u < line_size);
const char* start = skip_left ? text.c_str() + line_pos - 100 : text.c_str(); const char* here = fdescr->text.data() + char_offs;
const char* end = skip_right ? text.c_str() + line_pos + 100 : text.c_str() + text.size(); const char* base = here - line_pos;
const char* here = text.c_str() + line_pos; const char* start = skip_left ? here - 100 : base;
const char* end = skip_right ? here + 100 : base + line_size;
os << " "; os << " ";
if (skip_left) { if (skip_left) {
os << "... "; os << "... ";
@ -99,8 +140,8 @@ void ParseError::show(std::ostream& os) const {
where.show_context(os); where.show_context(os);
} }
SourceReader::SourceReader(std::istream* _is, const FileDescr* _fdescr) SourceReader::SourceReader(std::istream* _is, FileDescr* _fdescr)
: ifs(_is), loc(_fdescr), eof(false), cur_line_len(0), start(0), cur(0), end(0) { : ifs(_is), fdescr(_fdescr), loc(_fdescr), eof(false), cur_line_len(0), start(0), cur(0), end(0) {
load_line(); load_line();
} }
@ -139,7 +180,7 @@ const char* SourceReader::set_ptr(const char* ptr) {
if (ptr < cur || ptr > end) { if (ptr < cur || ptr > end) {
error("parsing position went outside of line"); error("parsing position went outside of line");
} }
loc.line_pos = (int)(ptr - start); loc.char_offs += ptr - cur;
cur = ptr; cur = ptr;
} }
return ptr; return ptr;
@ -149,12 +190,11 @@ bool SourceReader::load_line() {
if (eof) { if (eof) {
return false; return false;
} }
loc.set_eof();
if (ifs->eof()) { if (ifs->eof()) {
set_eof(); set_eof();
return false; return false;
} }
++loc.line_no;
loc.line_pos = -1;
std::getline(*ifs, cur_line); std::getline(*ifs, cur_line);
if (ifs->fail()) { if (ifs->fail()) {
set_eof(); set_eof();
@ -174,11 +214,16 @@ bool SourceReader::load_line() {
cur_line.pop_back(); cur_line.pop_back();
--len; --len;
} }
loc.text = cur_line;
cur_line_len = (int)len; cur_line_len = (int)len;
loc.line_pos = 0; if (fdescr) {
cur = start = cur_line.c_str(); cur = start = fdescr->push_line(std::move(cur_line));
end = start + cur_line_len; end = start + len;
loc.char_offs = (std::size_t)(cur - fdescr->text.data());
cur_line.clear();
} else {
cur = start = cur_line.c_str();
end = start + cur_line_len;
}
return true; return true;
} }

View File

@ -14,11 +14,12 @@
You should have received a copy of the GNU Lesser General Public License 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/>. along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#pragma once #pragma once
#include <string> #include <string>
#include <vector>
#include <iostream> #include <iostream>
namespace src { namespace src {
@ -31,9 +32,13 @@ namespace src {
struct FileDescr { struct FileDescr {
std::string filename; std::string filename;
std::string text;
std::vector<long> line_offs;
bool is_stdin; bool is_stdin;
FileDescr(std::string _fname, bool _stdin = false) : filename(std::move(_fname)), is_stdin(_stdin) { FileDescr(std::string _fname, bool _stdin = false) : filename(std::move(_fname)), is_stdin(_stdin) {
} }
const char* push_line(std::string new_line);
const char* convert_offset(long offset, long* line_no, long* line_pos, long* line_size = nullptr) const;
}; };
struct Fatal { struct Fatal {
@ -49,16 +54,23 @@ std::ostream& operator<<(std::ostream& os, const Fatal& fatal);
struct SrcLocation { struct SrcLocation {
const FileDescr* fdescr; const FileDescr* fdescr;
int line_no; long char_offs;
int line_pos; SrcLocation() : fdescr(nullptr), char_offs(-1) {
std::string text;
SrcLocation() : fdescr(nullptr), line_no(0), line_pos(-1) {
} }
SrcLocation(const FileDescr* _fdescr, int line = 0, int pos = -1) : fdescr(_fdescr), line_no(line), line_pos(pos) { SrcLocation(const FileDescr* _fdescr, long offs = -1) : fdescr(_fdescr), char_offs(-1) {
} }
bool defined() const { bool defined() const {
return fdescr; return fdescr;
} }
bool eof() const {
return char_offs == -1;
}
void set_eof() {
char_offs = -1;
}
const char* convert_pos(long* line_no, long* line_pos, long* line_size = nullptr) const {
return defined() ? fdescr->convert_offset(char_offs, line_no, line_pos, line_size) : nullptr;
}
void show(std::ostream& os) const; void show(std::ostream& os) const;
bool show_context(std::ostream& os) const; bool show_context(std::ostream& os) const;
void show_gen_error(std::ostream& os, std::string message, std::string err_type = "") const; void show_gen_error(std::ostream& os, std::string message, std::string err_type = "") const;
@ -98,6 +110,7 @@ struct ParseError : Error {
class SourceReader { class SourceReader {
std::istream* ifs; std::istream* ifs;
FileDescr* fdescr;
SrcLocation loc; SrcLocation loc;
bool eof; bool eof;
std::string cur_line; std::string cur_line;
@ -106,7 +119,7 @@ class SourceReader {
const char *start, *cur, *end; const char *start, *cur, *end;
public: public:
SourceReader(std::istream* _is, const FileDescr* _fdescr); SourceReader(std::istream* _is, FileDescr* _fdescr);
bool load_line(); bool load_line();
bool is_eof() const { bool is_eof() const {
return eof; return eof;

View File

@ -52,43 +52,56 @@
// elected-for elections-begin-before elections-end-before stakes-frozen // elected-for elections-begin-before elections-end-before stakes-frozen
{ 4 0 reverse <b { swap 32 u, } 4 times b> 15 config! } : config.election_params! { 4 0 reverse <b { swap 32 u, } 4 times b> 15 config! } : config.election_params!
dictnew 0 2constant validator-dict variable validator-dict
{ @' validator-dict } : validator-dict@ dictnew 0 validator-dict 2!
{ validator-dict@ nip } : validator# { validator-dict @ second } : validator#
// val-pubkey weight -- // val-pubkey weight --
{ dup 0<= abort"validator weight must be non-negative" { dup 0<= abort"validator weight must be non-negative"
dup 64 ufits not abort"validator weight must fit into 64 bits" dup 64 ufits not abort"validator weight must fit into 64 bits"
over Blen 32 <> abort"validator public key must be 32 bytes long" over Blen 32 <> abort"validator public key must be 32 bytes long"
<b x{538e81278a} s, rot B, swap 64 u, b> <s <b x{538e81278a} s, rot B, swap 64 u, b> <s
validator-dict@ dup 1+ 3 -roll swap validator-dict 2@ dup 1+ 3 -roll swap
16 udict!+ 0= abort"cannot add validator" 16 udict!+ 0= abort"cannot add validator"
swap 2 'nop does : validator-dict swap validator-dict 2!
} : add-validator } : add-validator
// since-ut until-ut main-val-cnt-or-0 -- // since-ut until-ut main-val-cnt-or-0 --
{ ?dup 0= { validator# } if { ?dup 0= { validator# } if
validator# 0= abort"no initial validators defined" validator# 0= abort"no initial validators defined"
rot <b x{11} s, swap 32 u, rot 32 u, validator# 16 u, swap 16 u, rot <b x{11} s, swap 32 u, rot 32 u, validator# 16 u, swap 16 u,
validator-dict@ drop <s s, b> validator-dict @ first <s s, b>
34 config! 34 config!
} : config.validators! } : config.validators!
dictnew constant workchain-dict variable workchain-dict
// root-hash file-hash enable-utime actual-min-split min-split max-split workchain-id -- // root-hash file-hash enable-utime actual-min-split min-split max-split workchain-id --
{ <b x{a6} s, 5 roll 32 u, 4 roll 8 u, 3 roll 8 u, rot 8 u, x{e000} s, { <b x{a6} s, 5 roll 32 u, 4 roll 8 u, 3 roll 8 u, rot 8 u, x{e000} s,
3 roll 256 u, rot 256 u, 0 32 u, x{1} s, -1 32 i, 0 64 u, b> 3 roll 256 u, rot 256 u, 0 32 u, x{1} s, -1 32 i, 0 64 u, b>
dup isWorkchainDescr? not abort"invalid WorkchainDescr created" dup isWorkchainDescr? not abort"invalid WorkchainDescr created"
<s swap @' workchain-dict 32 idict!+ 0= abort"cannot add workchain" <s swap workchain-dict @ 32 idict!+ 0= abort"cannot add workchain"
=: workchain-dict workchain-dict !
} : add-std-workchain } : add-std-workchain
// -- // --
{ @' workchain-dict dict>s s>c 12 config! } : config.workchains! { workchain-dict @ dict>s s>c 12 config! } : config.workchains!
dictnew constant special-dict variable special-dict
// special-smc-addr -- // special-smc-addr --
{ x{} swap @' special-dict 256 udict! not abort"cannot add a new special smart contract" { x{} swap special-dict @ 256 udict! not abort"cannot add a new special smart contract"
=: special-dict special-dict !
} : make_special } : make_special
{ @' special-dict dict>s s>c 31 config! } : config.special! { special-dict @ dict>s s>c 31 config! } : config.special!
// ( l -- D ) Converts a list of parameter indices into a dictionary
{ dictnew { swap uncons -rot <b swap rot 32 b>idict! not abort"cannot add parameter index" over null?
} until nip
} : param-list-to-dict
{ param-list-to-dict 9 config! } : config.mandatory_params!
{ param-list-to-dict 10 config! } : config.critical_params!
// min_tot_rounds max_tot_rounds min_wins max_losses min_store_sec max_store_sec bit_price cell_price --
{ 8 untuple 8 0 reverse <b x{36} s, { swap 8 u, } 4 times { swap 32 u, } 4 times b> } : cfg-prop-setup
// normal-prop-params critical-prop-params --
{ swap cfg-prop-setup swap cfg-prop-setup <b x{91} s, rot ref, swap ref, b> } : make-proposals-setup
{ make-proposals-setup 11 config! } : config.param_proposals_setup!
// bit-pps cell-pps mc-bit-pps mc-cell-pps -- // bit-pps cell-pps mc-bit-pps mc-cell-pps --
{ <b x{cc} s, 0 32 u, 4 roll 64 u, 3 roll 64 u, rot 64 u, swap 64 u, { <b x{cc} s, 0 32 u, 4 roll 64 u, 3 roll 64 u, rot 64 u, swap 64 u,

View File

@ -1 +1 @@
with_tvm_code("config", "te6ccgECHQEAA5oAART/APSkE/S88sgLAQIBIAIDAgFIBAUCAvEYGQICxQYHABGgmS/aiaGuFj8CAc0ICQAGqoJbAgEgCgsCASATFAIBSAwNAgEgDg8A6wB0NMD+kAwIPpEAaQDcbATsSPHALGSXwPgAtMf0z8ighBOVlNUuo4+bBLU0XH4MyBukjB/lNDXC//iA3AEup0yIfAE+CNSILwCvLAC3gKdgCRY8AGCEO52T0vwBuAxghDudk9v8AfgECRfBCDAAAGDHrCx8qWAAJTtRNDUUDOAIPQVyMwBzxbJ7VSACASAQEQIBIBISADM0NMHAcAS8onTH9Mf0w/TDzAgwgDyib7yiYAArHCAGMjLBVAFzxYUy27LH8s/yQH7AIAAJIBA8AWACAUgVFgHh8CuNhNkfyAqYNBg/oHN9DPkeuF/6mDQYP6BzfQkHlVcUwagnoCaZ/p/8wYNqoKgzggCfEojF7KmLaZOADvKalACHoHN9CYya+ENvBAEGR8EeeAoDHACHohgdAQU4GBVQAJXk0ttgkBQYP6LZgA8C0KQXAFscfgz0NcL//gjghBOQ29kcIIAxP/IyxAUy/+DHfoCE8tqEssfyz8BzxbJcPsAgAKcIYIQQ2ZQIbqcMdMf1NFAE4Ag9BUB4CGCEE5Db2S6jhMx1CH7BO1DAtDtHu1TAfEGgvIA4CGCEFBiSyG6lWwh0//R4CGCEE5D7wW6kzHwCOAw8mCAAJAPI9AASyz/L/wHPFgKDB/RDbQChDDtRNDUgCCAJFMx9GogbpFbjjMg0CDXScInjibTB9cLH/gjuwHAErCOFYAiWFFE9G5UUyH0bjCAJEAT9FowAZFb4pJfA+LiAcjMAc8Wye1UgAccgwjXGCDTH9Mf0x/4IxK58mPtRNDU0x/T//QE0VFSuvKhJYIQVm90ZaF+sIrhBvkBVBB2+RDyovgABaRUdQQlA8jMEssfy//0AMntVPgPEDVEVfAJQwMDyMwSyx/L//QAye1UgGgLWA9MPIds8AdMHgCCzErDAU/Kp0x8BghCOgSeKuvKp0//TPzAK+QFAu/kQ8qL4AAKkVHMEKAPIzBLLH8v/9ADJ7VT4D4Ai+DP5ABBXEDQQI0iQ8A9Uc0IkA8jMEssfy//0AMntVCBukl8FiuIbHABOgCL4MyBuk1ttcODQ0wcBwBLyqIBg1yHTP8gBzxbJEoAQ9A5voTABAC7THxA0ECTwCUMDA8jMEssfy//0AMntVA=="); with_tvm_code("config", "te6ccgECJAEABcUAART/APSkE/S88sgLAQIBIAIDAgFIBAUCAvEeHwICxQYHABGgmS/aiaGuFj8CAcsICQAGqoJbAgEgCgsB46KCuNhNkfyAqYNBg/oHN9DPkeuF/6mDQYP6BzfQkHlVcUwagnoCaZ/p/8wYNqoKgzggCfEojF7KmLaZOADvKalACHoHN9CYya+ENvBAEGR8EeeAoDHACHohgdAQU4GBVQAJXk0ttgkBQYP6LZgA8C0KQB0CASAMDQIBZhscAgFIDg8CAVgZGgL3AHQ0wP6QCH6RAGkBHGwFLEkxwCxkl8F4APTH9M/IoIQTlZTVLqORDI0NAPU0XH4MyBukjB/lNDXC//iAnADup0xIPAG+CNSILwCvLAB3gGfgCQB8AGCEO52T0uAQPAH4DCCEO52T2+AQPAH4DAzIIIQblZQUrrjAmxBIIBARACU7UTQ1FAzgCD0FcjMAc8Wye1UgATwwUCPbPIBAIaMiwv+cW3T7AoIQ7lZQUoMGkTLi8AcSABLAAAGDHrCx8qUC9gHTH9TSADAiqx2V+CMToQLeIds8IML/jhci+DMgbpIwcJL5AOIhvZcwghcdm5yq3o4VefgzUjCAIPQMb6ExlzCCFzKvkZTe4iHXZYMHvpcwghc9npuq3iDB/5JsYeAjkTKOFHr4MxOAIPQMb6Exl4IXPI2WrDLe4iHB/xMUAC7Q0gcBwPPyrNIf9ATSAAGS0/+SfwHi0QTskxVfBeAxIds8byg0NDVSgLmYXwmCFzqHj5fgUHO2CAODCflBMoMJoBeoBqYCEqgVoFMBqPgjE6DtRNDU0x/T//QE0Sj5AFMBgwf0Dm+h4wIwNlGmoYMduZhfCoIXD56G3ODbPDBzqdQApHBtA/kAEFcQSxpDMBUWIxcAZoAL+DPQ0wcBgQCRuvKsAZLUMd7XTNDTBwHANvKs0wfTB9MH0wfTH9Mf0x/TH1VwbwgB0QHUODk5Bds8Uk29mF8Pghc8jZar4FNYvphfD4IXPpONu+BShqGDDaAZqFHdoYMduZhfDYIXD56G3OAQVkAUUHcDgM7IygcWyx8UzBLKAPQAyj/L/1AEzxZARYMH9EMTA8jMEssfy//0AMntVBgAWoDOyMoHFssfFMwSygD0AMo/y/8XywcUyw9AFoMH9EMSA8jMEssfy//0AMntVAAk0gcBwM7yrNMf1NIA9ATSP9P/ADM0NMHAcAS8onTH9Mf0w/TDzAgwgDyib7yiYAArHCAGMjLBVAFzxYUy27LH8s/yQH7AIABbHH4M9DXC//4I4IQTkNvZHCCAMT/yMsQFMv/gx36AhPLahLLH8s/Ac8WyXD7AIACnCGCEENmUCG6nDHSH9TRQBOAIPQVAeAhghBOQ29kuo4TMdQh+wTtQwLQ7R7tUwHxBoLyAOAhghBQYkshupVsIdP/0eAhghBOQ+8FupMx8ArgMPJggACQDyPQAEss/y/8BzxYCgwf0Q20AoQw7UTQ1IAggCRTMfRqIG6RW44zINAg10nCJ44m0wfXCx/4I7sBwBKwjhWAIlhRRPRuVFMh9G4wgCRAE/RaMAGRW+KSXwPi4gHIzAHPFsntVIAHVIMI1xgg0x/TH9Mf+CMSufJjINdkwkDyZ+1E0NTTH9P/9ATRUVK68qElghBWb3RloX6w4wMG+QFUEHb5EPKi+AAFpFR1BCUDyMwSyx/L//QAye1U+A8QNURV8AtDAwPIzBLLH8v/9ADJ7VSAgAuQD0w8h2zwB0weAILMSsMBT8qnTHwGCEI6BJ4q68qnT/9M/MAr5AUC7+RDyovgAAqRUcwQoA8jMEssfy//0AMntVPgPIoMJ+UNfA4Ai+DP5ABBXEDQQI0iQ8BVUc0IkA8jMEssfy//0AMntVCBukl8F4w4hIgEi2zwyyFjPFskSgBD0Dm+hMAEjAC7THxA0ECTwC0MDA8jMEssfy//0AMntVAAmgCL4MyDQ0wcBwBLyqIBg1yHTPw==");

Some files were not shown because too many files have changed in this diff Show More