@@ -3049,3 +3049,134 @@ TEST_CASE_VERSIONS("soroban transaction validation", "[tx][envelope][soroban]")
30493049 }
30503050 });
30513051}
3052+
3053+ TEST_CASE (" XDR protocol 22 compatibility validation" , " [tx][envelope]" )
3054+ {
3055+ if (!isSorobanProtocolLinked (getTestConfig (), ProtocolVersion::V_21 ))
3056+ {
3057+ return ;
3058+ }
3059+ auto validateTx = [](ProtocolVersion protocolVersion) {
3060+ VirtualClock clock;
3061+ auto cfg = getTestConfig ();
3062+ cfg.TESTING_UPGRADE_LEDGER_PROTOCOL_VERSION =
3063+ static_cast <uint32_t >(protocolVersion);
3064+ auto app = createTestApplication (clock, cfg);
3065+ auto root = app->getRoot ();
3066+ Operation op;
3067+ op.body .type (INVOKE_HOST_FUNCTION );
3068+ op.body .invokeHostFunctionOp ().hostFunction .type (
3069+ HOST_FUNCTION_TYPE_CREATE_CONTRACT_V2 );
3070+
3071+ auto tx =
3072+ sorobanTransactionFrameFromOps (app->getNetworkID (), *root, {op}, {},
3073+ SorobanResources (), 1000 , 1'000'000 );
3074+ CheckValidLedgerViewWrapper ledgerView (*app);
3075+ return tx->checkValid (app->getAppConnector (), ledgerView, 0 , 0 , 0 );
3076+ };
3077+ SECTION (" not valid in protocol 21" )
3078+ {
3079+ auto res = validateTx (ProtocolVersion::V_21 );
3080+ REQUIRE (res->getResultCode () == txMALFORMED);
3081+ }
3082+ SECTION (" valid in protocol 22" )
3083+ {
3084+ auto res = validateTx (ProtocolVersion::V_22 );
3085+ REQUIRE (res->isSuccess ());
3086+ }
3087+ }
3088+
3089+ TEST_CASE (" XDR protocol 23 compatibility validation" , " [tx][envelope]" )
3090+ {
3091+ if (!isSorobanProtocolLinked (getTestConfig (), ProtocolVersion::V_22 ))
3092+ {
3093+ return ;
3094+ }
3095+ auto runTest = [](ProtocolVersion protocolVersion, bool expectSuccess) {
3096+ VirtualClock clock;
3097+ auto cfg = getTestConfig ();
3098+ cfg.TESTING_UPGRADE_LEDGER_PROTOCOL_VERSION =
3099+ static_cast <uint32_t >(protocolVersion);
3100+ auto app = createTestApplication (clock, cfg);
3101+ auto root = app->getRoot ();
3102+ Operation op;
3103+ op.body .type (INVOKE_HOST_FUNCTION );
3104+ op.body .invokeHostFunctionOp ().hostFunction .type (
3105+ HOST_FUNCTION_TYPE_INVOKE_CONTRACT );
3106+
3107+ CheckValidLedgerViewWrapper ledgerView (*app);
3108+ SECTION (" muxed account ScAddress in function args" )
3109+ {
3110+ auto & val = op.body .invokeHostFunctionOp ()
3111+ .hostFunction .invokeContract ()
3112+ .args .emplace_back ();
3113+ val.type (SCV_ADDRESS );
3114+ val.address ().type (SC_ADDRESS_TYPE_MUXED_ACCOUNT );
3115+ val.address ().muxedAccount ().id = 123 ;
3116+ auto tx = sorobanTransactionFrameFromOps (
3117+ app->getNetworkID (), *root, {op}, {}, SorobanResources (), 1000 ,
3118+ 1'000'000 );
3119+
3120+ auto res =
3121+ tx->checkValid (app->getAppConnector (), ledgerView, 0 , 0 , 0 );
3122+ REQUIRE (res->isSuccess () == expectSuccess);
3123+ if (!expectSuccess)
3124+ {
3125+ REQUIRE (res->getResultCode () == txMALFORMED);
3126+ }
3127+ }
3128+ SECTION (" claimable balance ScAddress in auth" )
3129+ {
3130+ auto & authEntry =
3131+ op.body .invokeHostFunctionOp ().auth .emplace_back ();
3132+ authEntry.rootInvocation .function .type (
3133+ SOROBAN_AUTHORIZED_FUNCTION_TYPE_CONTRACT_FN );
3134+ auto & address =
3135+ authEntry.rootInvocation .function .contractFn ().contractAddress ;
3136+ address.type (SC_ADDRESS_TYPE_CLAIMABLE_BALANCE );
3137+ address.claimableBalanceId ().v0 ()[0 ] = 1 ;
3138+ auto tx = sorobanTransactionFrameFromOps (
3139+ app->getNetworkID (), *root, {op}, {}, SorobanResources (), 1000 ,
3140+ 1'000'000 );
3141+ auto res =
3142+ tx->checkValid (app->getAppConnector (), ledgerView, 0 , 0 , 0 );
3143+ REQUIRE (res->isSuccess () == expectSuccess);
3144+ if (!expectSuccess)
3145+ {
3146+ REQUIRE (res->getResultCode () == txMALFORMED);
3147+ }
3148+ }
3149+ SECTION (" liquidity pool ScAddress in footprint" )
3150+ {
3151+ Operation ttlOp;
3152+ ttlOp.body .type (EXTEND_FOOTPRINT_TTL );
3153+
3154+ SorobanResources resources;
3155+ auto & key = resources.footprint .readOnly .emplace_back ();
3156+ key.type (CONTRACT_DATA );
3157+ auto & address = key.contractData ().contract ;
3158+
3159+ address.type (SC_ADDRESS_TYPE_LIQUIDITY_POOL );
3160+ address.liquidityPoolId ()[1 ] = 10 ;
3161+ auto tx = sorobanTransactionFrameFromOps (app->getNetworkID (), *root,
3162+ {ttlOp}, {}, resources,
3163+ 1000 , 1'000'000 );
3164+ auto res =
3165+ tx->checkValid (app->getAppConnector (), ledgerView, 0 , 0 , 0 );
3166+ REQUIRE (res->isSuccess () == expectSuccess);
3167+ if (!expectSuccess)
3168+ {
3169+ REQUIRE (res->getResultCode () == txMALFORMED);
3170+ }
3171+ }
3172+ };
3173+
3174+ SECTION (" not valid in protocol 22" )
3175+ {
3176+ runTest (ProtocolVersion::V_22 , false );
3177+ }
3178+ SECTION (" valid in protocol 23" )
3179+ {
3180+ runTest (ProtocolVersion::V_23 , true );
3181+ }
3182+ }
0 commit comments