Search Apps Documentation Source Content File Folder Download Copy Actions Download

z9a_recover_client_filetest.gno

10.70 Kb · 258 lines
  1// PKGPATH: gno.land/r/aib/main
  2package main
  3
  4import (
  5	"time"
  6
  7	"gno.land/p/aib/ibc/lightclient/tendermint"
  8	tmtesting "gno.land/p/aib/ibc/lightclient/tendermint/testing"
  9	"gno.land/p/aib/ibc/types"
 10	"gno.land/r/aib/ibc/core"
 11)
 12
 13// RecoverClient success: a Frozen subject client is recovered using an Active
 14// substitute client that tracks the same counterparty chain.
 15func main(cur realm) {
 16	core.SetAdmin(cross(cur), "g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm")
 17
 18	// Subject client setup: create + freeze via misbehaviour (pattern from z8a).
 19	var (
 20		chainID     = "atomone-1"
 21		height      = uint64(2)
 22		clientState = tmtesting.NewClientState(chainID, types.NewHeight(1, height))
 23		apphash     = tmtesting.Hash("apphash-2")
 24		// priv=8a6cAbQSpDbebmcTEhCMPhhr/SkL/2pizo60yzHRkN9Uyk7RHOZm7g4xW+yeJh147/Z4/6HXF6gBwcFNkLsZ/A==
 25		val1 = tendermint.NewValidator("9DIBYr64rywKO3Kk6+743xDHcEU=",
 26			"VMpO0RzmZu4OMVvsniYdeO/2eP+h1xeoAcHBTZC7Gfw=", 1)
 27		// priv=nWg6ETc62tyxd94lh8fFaQnZKaAW6vlS0L/4lfseJuI14ZXUKp7AZROkflLFVF+SBg4wJVfzgzIKyWq3D066+g==
 28		val2 = tendermint.NewValidator("y+naL3ubs9q1bXrY9+uRxY9c+J8=",
 29			"NeGV1CqewGUTpH5SxVRfkgYOMCVX84MyCslqtw9Ouvo=", 1)
 30		trustedValset  = tendermint.NewValset(val1, val2)
 31		consensusState = tmtesting.GenConsensusState(time.Now(), apphash, trustedValset.Hash())
 32	)
 33	subjectID := core.CreateClient(cross(cur), clientState, consensusState)
 34
 35	// Build valid misbehavior to freeze the subject.
 36	var header1, header2 *tendermint.MsgHeader
 37	{
 38		var (
 39			apphash         = tmtesting.Hash("apphash-4")
 40			val1            = tendermint.NewValidator("9DIBYr64rywKO3Kk6+743xDHcEU=", "VMpO0RzmZu4OMVvsniYdeO/2eP+h1xeoAcHBTZC7Gfw=", 10)
 41			val2            = tendermint.NewValidator("y+naL3ubs9q1bXrY9+uRxY9c+J8=", "NeGV1CqewGUTpH5SxVRfkgYOMCVX84MyCslqtw9Ouvo=", 10)
 42			valset          = tendermint.NewValset(val1, val2)
 43			commitTimestamp = tmtesting.ToTime("2025-09-25T07:55:57.306746166Z")
 44			newHeight       = uint64(4)
 45			newTimestamp    = consensusState.Timestamp.Add(time.Minute * time.Duration(0))
 46			nextValset      = tendermint.NewValset(val1, val2)
 47			trustedHeight   = clientState.LatestHeight
 48
 49			signatures = []tendermint.CommitSig{
 50				{
 51					BlockIDFlag:      tendermint.BlockIDFlagCommit,
 52					ValidatorAddress: valset.Validators[0].Address,
 53					Timestamp:        commitTimestamp,
 54					Signature:        []byte("\x2e\xba\x21\xb0\x2f\xd2\x85\xb9\xef\x82\x68\xdc\xef\xd1\xd1\x12\x70\x88\x94\x10\x7e\x4d\x49\xac\x46\x3d\x86\xe2\xf2\xae\x38\xb4\xa5\xab\x0c\xc1\x8f\x8a\x59\xda\x36\x17\x01\xe4\x16\x49\xbf\x03\x86\xf0\x31\x3f\x30\x37\x9e\x47\x28\x72\x3b\x0c\x89\xb9\x94\x05"),
 55				},
 56				{
 57					BlockIDFlag:      tendermint.BlockIDFlagCommit,
 58					ValidatorAddress: valset.Validators[1].Address,
 59					Timestamp:        commitTimestamp,
 60					Signature:        []byte("\x67\xcc\xc6\xc4\x20\xa0\xcb\x36\xaf\x33\x5c\xf8\xe4\xad\x47\x49\x38\x9d\x9e\xa3\x7c\xe6\x88\x81\x62\x51\x7f\xcc\xa5\x92\x0d\x98\xe9\xbe\x71\x2d\x22\xcd\x41\x30\x28\x83\x03\xcb\xf5\xd7\x28\xde\x7b\x92\x85\x9e\xa6\xe5\xde\x50\x89\x2d\x2b\xc5\x9d\x9a\x33\x00"),
 61				},
 62			}
 63		)
 64		header1 = tmtesting.NewMsgHeader(chainID, newTimestamp, apphash, newHeight,
 65			trustedHeight, valset, nextValset, trustedValset, signatures)
 66	}
 67	{
 68		var (
 69			apphash         = tmtesting.Hash("apphash-3")
 70			val1            = tendermint.NewValidator("9DIBYr64rywKO3Kk6+743xDHcEU=", "VMpO0RzmZu4OMVvsniYdeO/2eP+h1xeoAcHBTZC7Gfw=", 10)
 71			val2            = tendermint.NewValidator("y+naL3ubs9q1bXrY9+uRxY9c+J8=", "NeGV1CqewGUTpH5SxVRfkgYOMCVX84MyCslqtw9Ouvo=", 10)
 72			valset          = tendermint.NewValset(val1, val2)
 73			commitTimestamp = tmtesting.ToTime("2025-09-25T07:55:57.306746166Z")
 74			newHeight       = uint64(3)
 75			newTimestamp    = consensusState.Timestamp.Add(time.Minute * time.Duration(0))
 76			nextValset      = tendermint.NewValset(val1, val2)
 77			trustedHeight   = clientState.LatestHeight
 78
 79			signatures = []tendermint.CommitSig{
 80				{
 81					BlockIDFlag:      tendermint.BlockIDFlagCommit,
 82					ValidatorAddress: valset.Validators[0].Address,
 83					Timestamp:        commitTimestamp,
 84					Signature:        []byte("\x51\xa4\x8f\x78\x42\x4e\x6e\x0d\xc3\x2b\xe6\xcb\x09\x5c\xe5\x7d\x35\x84\xcf\xb1\x0f\x53\x72\x0c\x41\xde\xd3\x6d\xbc\x81\x28\x64\x41\xf7\xe9\x1e\xa9\x93\xd0\xa4\x84\x16\xca\xa8\xa3\x8e\x56\x45\xec\xae\x1d\x24\xb4\xa8\xf4\x29\x85\x04\x06\xe4\x18\x6b\x7d\x08"),
 85				},
 86				{
 87					BlockIDFlag:      tendermint.BlockIDFlagCommit,
 88					ValidatorAddress: valset.Validators[1].Address,
 89					Timestamp:        commitTimestamp,
 90					Signature:        []byte("\xd9\xd6\x82\x83\x78\x75\xfa\x2e\xd7\x1b\xa5\x3d\xfe\xb3\x80\xb6\xc7\x59\x20\x45\x10\xdf\x0c\x19\xd1\xcc\xfc\x37\xd5\x59\x79\x95\x93\x60\x08\xfb\x5f\xa0\x87\x95\x51\x1e\x29\xed\x94\xd1\x31\x5e\xda\x90\x86\x11\xbe\xb2\x88\x68\xe1\xba\xa7\x31\xc7\xa2\xda\x07"),
 91				},
 92			}
 93		)
 94		header2 = tmtesting.NewMsgHeader(chainID, newTimestamp, apphash, newHeight,
 95			trustedHeight, valset, nextValset, trustedValset, signatures)
 96	}
 97	core.UpdateClient(cross(cur), subjectID, &tendermint.Misbehaviour{Header1: header1, Header2: header2})
 98
 99	// Substitute client: fresh Active client with matching parameters (same
100	// chainID for IBC correctness, but the implementation also supports a
101	// different one — the subject will adopt the substitute's chainID).
102	substituteConsState := tmtesting.GenConsensusState(time.Now(), tmtesting.Hash("apphash-5"), trustedValset.Hash())
103	substituteID := core.CreateClient(cross(cur), clientState, substituteConsState)
104
105	// Advance the substitute to height (1,3) so recovery must actually adopt
106	// the substitute's LatestHeight (the subject starts at (1,2)). Signatures
107	// reused verbatim from z2a (chainID=atomone-1, height=3, apphash-3,
108	// trusted=(1,2), time-shift=1m).
109	{
110		var (
111			apphash         = tmtesting.Hash("apphash-3")
112			commitTimestamp = tmtesting.ToTime("2025-09-25T07:55:57.306746166Z")
113			newHeight       = uint64(3)
114			newTimestamp    = substituteConsState.Timestamp.Add(time.Minute * time.Duration(1))
115			valset          = tendermint.NewValset(val1, val2)
116			nextValset      = tendermint.NewValset(val1, val2)
117			trustedHeight   = clientState.LatestHeight
118
119			signatures = []tendermint.CommitSig{
120				{
121					BlockIDFlag:      tendermint.BlockIDFlagCommit,
122					ValidatorAddress: valset.Validators[0].Address,
123					Timestamp:        commitTimestamp,
124					Signature:        []byte("\x5c\xd2\x8b\xe3\x4b\x60\x3e\xaa\x75\x3c\xce\x24\xfe\x15\x75\x55\x84\xd4\xa3\xce\xbe\x0f\x94\xe9\xf7\x27\xb3\x7a\xdd\x02\x2d\xa0\x0b\xa7\x83\x7f\x50\xc3\xde\x3d\x95\x59\xb3\xad\xed\xd0\xdd\x23\x1d\x39\x9a\x8e\x1f\xc3\xcf\xdb\x1d\xa9\x93\xf5\x9a\xc0\x2b\x05"),
125				},
126				{
127					BlockIDFlag:      tendermint.BlockIDFlagCommit,
128					ValidatorAddress: valset.Validators[1].Address,
129					Timestamp:        commitTimestamp,
130					Signature:        []byte("\x34\x41\x2e\x78\x7f\xbf\x70\xef\x14\x48\xe3\x14\xd5\x83\xdc\x42\xff\x40\xf6\x5b\x71\x62\x09\xf9\x6f\x54\x63\x3e\xdb\xc5\x98\xc0\x9e\xa7\xde\x33\xac\xa7\x5f\xbb\xd6\x63\x49\xe1\xe9\x98\x86\x03\x46\x6a\x7e\xb6\x5d\xe5\x71\xe5\x1e\x5d\x4d\xd8\x8d\xbe\x2f\x01"),
131				},
132			}
133
134			msgHeader = tmtesting.NewMsgHeader(
135				"atomone-1", newTimestamp, apphash, newHeight, trustedHeight, valset,
136				nextValset, trustedValset, signatures,
137			)
138		)
139		core.UpdateClient(cross(cur), substituteID, msgHeader)
140	}
141
142	println("----------- before recover: subject status")
143	println(core.Render("clients/" + subjectID + "/status"))
144	println("----------- before recover: substitute status")
145	println(core.Render("clients/" + substituteID + "/status"))
146
147	core.RecoverClient(cross(cur), subjectID, substituteID)
148
149	println("----------- after recover: subject status")
150	println(core.Render("clients/" + subjectID + "/status"))
151	println("----------- after recover: substitute status")
152	println(core.Render("clients/" + substituteID + "/status"))
153	println("----------- after recover: subject frozen_height (must be 0/0)")
154	println(core.Render("clients/" + subjectID))
155}
156
157// Output:
158// ----------- before recover: subject status
159// {"status":"Frozen"}
160// ----------- before recover: substitute status
161// {"status":"Active"}
162// ----------- after recover: subject status
163// {"status":"Active"}
164// ----------- after recover: substitute status
165// {"status":"Active"}
166// ----------- after recover: subject frozen_height (must be 0/0)
167// {"id":"07-tendermint-1","type":"07-tendermint","creator":"g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm","status":"Active","counterparty_client_id":"","counterparty_merke_prefix":[],"client_state":{"chain_id":"atomone-1","latest_height":{"revision_number":1,"revision_height":3},"frozen_height":{"revision_number":0,"revision_height":0},"trust_level":{"numerator":1,"denominator":3},"trusting_period":3600,"unbonding_period":10800,"max_clock_drift":3600,"upgrade_path":[]},"last_consensus_state":{"height":{"revision_number":1,"revision_height":3},"timestamp":1234567950,"root":"m9afpc+PXaYRHdGC7FkrzuzRNn8ONC1xRCzYYAPRCU8=","next_validators_hash":"OJfJuH6dfiZI2d0uAxqamqfIVqV4c4oEAZigvJ8UqFQ="}}
168
169// Events:
170// [
171//   {
172//     "type": "create_client",
173//     "attrs": [
174//       {
175//         "key": "client_id",
176//         "value": "07-tendermint-1"
177//       },
178//       {
179//         "key": "client_type",
180//         "value": "07-tendermint"
181//       },
182//       {
183//         "key": "consensus_heights",
184//         "value": "1/2"
185//       }
186//     ],
187//     "pkg_path": "gno.land/r/aib/ibc/core"
188//   },
189//   {
190//     "type": "client_misbehaviour",
191//     "attrs": [
192//       {
193//         "key": "client_id",
194//         "value": "07-tendermint-1"
195//       },
196//       {
197//         "key": "client_type",
198//         "value": "07-tendermint"
199//       }
200//     ],
201//     "pkg_path": "gno.land/r/aib/ibc/core"
202//   },
203//   {
204//     "type": "create_client",
205//     "attrs": [
206//       {
207//         "key": "client_id",
208//         "value": "07-tendermint-2"
209//       },
210//       {
211//         "key": "client_type",
212//         "value": "07-tendermint"
213//       },
214//       {
215//         "key": "consensus_heights",
216//         "value": "1/2"
217//       }
218//     ],
219//     "pkg_path": "gno.land/r/aib/ibc/core"
220//   },
221//   {
222//     "type": "update_client",
223//     "attrs": [
224//       {
225//         "key": "client_id",
226//         "value": "07-tendermint-2"
227//       },
228//       {
229//         "key": "client_type",
230//         "value": "07-tendermint"
231//       },
232//       {
233//         "key": "consensus_heights",
234//         "value": "1/3"
235//       }
236//     ],
237//     "pkg_path": "gno.land/r/aib/ibc/core"
238//   },
239//   {
240//     "type": "recover_client",
241//     "attrs": [
242//       {
243//         "key": "subject_client_id",
244//         "value": "07-tendermint-1"
245//       },
246//       {
247//         "key": "substitute_client_id",
248//         "value": "07-tendermint-2"
249//       },
250//       {
251//         "key": "client_type",
252//         "value": "07-tendermint"
253//       }
254//     ],
255//     "pkg_path": "gno.land/r/aib/ibc/core"
256//   }
257// ]
258