|
| 1 | +- **TEP**: [503](https://github.com/ton-blockchain/TEPs/pull/503) |
| 2 | +- **title**: New Bounce Message Format |
| 3 | +- **status**: Draft |
| 4 | +- **type**: Core |
| 5 | +- **authors**: [SpyCheese](https://github.com/SpyCheese) |
| 6 | +- **created**: 25.07.2025 |
| 7 | +- **replaces**: [TEP-496](https://github.com/ton-blockchain/TEPs/pull/496) |
| 8 | +- **replaced by**: - |
| 9 | + |
| 10 | +# Summary |
| 11 | + |
| 12 | +This TEP introduces a new format for bounced messages to include the whole original message body and some information about |
| 13 | +the transaction. For compatibility, this new format is optional; it is enabled by special flags. |
| 14 | + |
| 15 | +# Motivation |
| 16 | + |
| 17 | +The motivation behind extending bounced messages is described in [TEP-496](https://github.com/ton-blockchain/TEPs/pull/496). |
| 18 | +In short, currently the bounced message returns only the first 256 bits of the original, which is not enough for some applications. |
| 19 | +Also, certain information about the transaction that bounced (such as TVM exit code) can be useful for the caller. |
| 20 | + |
| 21 | +However, the approach proposed in [TEP-496](https://github.com/ton-blockchain/TEPs/pull/496) will require substantial changes in offchain infrastructure, |
| 22 | +which may be too cumbersome (see Alternative Designs Considered below). This TEP suggests another option. |
| 23 | + |
| 24 | +# Guide |
| 25 | + |
| 26 | +Current message format for internal messages contains the field `ihr_fee:Coins`, which is always zero, as IHR is |
| 27 | +not implemented. This field will be renamed to `extra_flags` and repurposed for flags. |
| 28 | + |
| 29 | +`(extra_flags & 1) = 1` enables the new bounce format for the message. The bounced message contains information about the transaction. |
| 30 | +If `(extra_flags & 3) = 3`, the bounced message also contains the whole body of the original message. |
| 31 | +For compatibility, if `(extra_flags & 1) = 0` then the bounced message uses the old format. |
| 32 | + |
| 33 | +# Specification |
| 34 | + |
| 35 | +> The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. |
| 36 | +
|
| 37 | +## Extra flags |
| 38 | + |
| 39 | +The field `ihr_fee:Coins` in `CommonMsgInfo` MUST be renamed to `extra_flags` and treated differently. |
| 40 | +Note: this field is currently unused, as IHR is not implemented, and since global version 11 `ihr_fee` is always zero. |
| 41 | + |
| 42 | +`extra_flags` MUST still be `VarUInteger 16` (same as `Coins`). The first two bits of flags (`extra_flags & 3`) will be used to control the new bounce format. |
| 43 | +They can be set by contract sending the message, and they MUST remain in the message unchanged. |
| 44 | +All other bits of `extra_flags` MAY be used in the future for other purposes. |
| 45 | + |
| 46 | +For compatibility, this behavior MUST be enabled by `global_version` in `ConfigParam 8`. In the older versions, the field MUST be treated as IHR fee. |
| 47 | +In the newer versions, it MUST be treated as `extra_flags`, while IHR fee MUST be implicitly considered to be zero. |
| 48 | + |
| 49 | +## New bounced message format |
| 50 | + |
| 51 | +When the transaction bounces, it creates the bounce message depending on the `extra_flags` in the inbound message: |
| 52 | +- If `(extra_flags & 1) = 0`, the bounced message MUST have the old format. |
| 53 | +- If `(extra_flags & 3) = 1`, the bounced message MUST have the new format without the body of the original message (see below). |
| 54 | +- If `(extra_flags & 3) = 3`, the bounced message MUST have the new format with the body of the original message (see below). |
| 55 | + |
| 56 | +The bounced message (either old or new) SHOULD have `extra_flags = 0`. |
| 57 | +Note: here `extra_flags` is the integer obtained after deserializing `VarUInteger 16`. |
| 58 | + |
| 59 | +New bounced message body has the following TLB scheme: |
| 60 | + |
| 61 | +``` |
| 62 | +_ value:CurrencyCollection created_lt:uint64 created_at:uint32 = NewBounceOriginalInfo; |
| 63 | +_ gas_used:uint32 vm_steps:uint32 = NewBounceComputePhaseInfo; |
| 64 | +
|
| 65 | +new_bounce_body#fffffffe |
| 66 | + original_body:(Maybe ^Cell) |
| 67 | + original_info:^NewBounceOriginalInfo |
| 68 | + bounced_by_phase:uint8 exit_code:int32 |
| 69 | + compute_phase:(Maybe NewBounceComputePhaseInfo) |
| 70 | + = NewBounceBody; |
| 71 | +``` |
| 72 | +- `original_body` - cell that contains the body of the original message (if `extra_flags & 2`) or nothing (if not `extra_flags & 2`). |
| 73 | +- `original_info` - value, lt and unixtime of the original message. |
| 74 | +- `bounced_by_phase` - reason why the transaction bounced: |
| 75 | + - `0` - compute phase was skipped. `exit_code` denotes the skip reason: |
| 76 | + - `exit_code = -1` - no state (the account is uninit or frozen, and no state init is present in the message). |
| 77 | + - `exit_code = -2` - bad state (the account is uninit or frozen, and state init in the message has the wrong hash). |
| 78 | + - `exit_code = -3` - no gas. |
| 79 | + - `exit_code = -4` - account is suspended. |
| 80 | + - `1` - compute phase failed. `exit_code` is the value from the compute phase. |
| 81 | + - `2` - action phase failed. `exit_code` is the value from the action phase. |
| 82 | +- `exit_code` - 32-bit exit code, see above. |
| 83 | +- `compute_phase` - exists if it was not skipped (`bounced_by_phase > 0`): |
| 84 | + - `gas_used`, `vm_steps` - same as in `TrComputePhase` of the transaction. |
| 85 | + |
| 86 | +The forward fee of the bounce message SHOULD depend on its size (like ordinary messages). |
| 87 | + |
| 88 | +In the future, other extra flags MAY change the format of the bounced message. |
| 89 | +For compatibility, this format SHOULD NOT be changed if no other extra flags are set. |
| 90 | + |
| 91 | +# Drawbacks |
| 92 | + |
| 93 | +1. **Increased complexity**: Implementing logic for managing flags and building new bounced messages is required. |
| 94 | +2. **IHR fee reuse**: Reusing `ihr_fee` field makes it more difficult to implement IHR in the future if the need arises. |
| 95 | +3. **Fees**: The new bounced messages have larger forward fees, especially when the body of the original message is included and it is big. |
| 96 | + |
| 97 | +# Rationale and alternatives |
| 98 | + |
| 99 | +## Why This Design? |
| 100 | + |
| 101 | +1. **Backward compatibility**: Behavior of existing contracts does not change. |
| 102 | +2. **Opt-in Basis**: Only contracts that need larger bounce messages pay the additional costs. |
| 103 | +3. **Minimal changes**: This required only changing logic for managing message flags and creating bounce messages, without new TVM opcodes or configuration parameters. |
| 104 | +4. **Optional body**: The body of the original message can be big, so it can be omitted (e.g., when only exit code is required). |
| 105 | +5. **Extra flags**: Adding `extra_flags` field allows adding more message options in the future. |
| 106 | + |
| 107 | +## Alternative Designs Considered |
| 108 | + |
| 109 | +1. **Use metadata**: [TEP-496](https://github.com/ton-blockchain/TEPs/pull/496) suggests using message metadata for the new parameters. |
| 110 | +While it seems simple at first, it actually entails certain difficulties. Currently, the execution of the transaction does not depend on the metadata. |
| 111 | +Adding essential parameters to the metadata will change the interface of the transaction emulator, which will affect all its users, such as |
| 112 | +TVM retracer, blueprint and more. |
| 113 | +2. **Include the original message**: We could include the whole original message cell in the bounced message. |
| 114 | +This would make parsing harder, as the body of the original message is often needed, and reaching it would require |
| 115 | +parsing the whole `CommonMsgInfo`. Instead, we include the `original_body` and `original_info` (some parts of `CommonMsgInfo` that can be actually useful). |
| 116 | + |
| 117 | +# Prior art |
| 118 | + |
| 119 | +See [TEP-496 / Prior art](https://github.com/ton-blockchain/TEPs/blob/d4d094d419fcc8132d20e63338ad3986eb6b5937/text/0496-configurable-bounce-message-size.md#prior-art). |
| 120 | + |
| 121 | +# Unresolved questions |
| 122 | + |
| 123 | +1. What info about the transaction (other than what is suggested above) should we include? |
| 124 | +2. Should we truncate the original body if it is too big? The size could be controlled by the caller using special options. |
| 125 | +Or do we consider forward fees for the bounced message small enough so it doesn't matter? |
| 126 | + |
| 127 | +# Future possibilities |
| 128 | + |
| 129 | +The bounced message format may be extended in the future to include more data. |
0 commit comments