Search Apps Documentation Source Content File Folder Download Copy Actions Download

ulnbase.gno

6.72 Kb · 227 lines
  1package ulnbase
  2
  3import (
  4	"gno.land/p/samcrew/deps/onbloc/json"
  5	"gno.land/p/nt/ufmt/v0"
  6)
  7
  8// XXX: not sure having the counts will be an opti on gno, need to benchmark
  9
 10type UlnConfig struct {
 11	Confirmations        uint64
 12	RequiredDVNCount     uint8
 13	OptionalDVNCount     uint8
 14	OptionalDVNThreshold uint8
 15	RequiredDVNs         []address
 16	OptionalDVNs         []address
 17}
 18
 19type SetDefaultUlnConfigParam struct {
 20	Eid    uint32
 21	Config *UlnConfig
 22}
 23
 24// Error types
 25var (
 26	ErrULNUnsorted                    = "LZ_ULN_Unsorted"
 27	ErrULNInvalidRequiredDVNCount     = "LZ_ULN_InvalidRequiredDVNCount"
 28	ErrULNInvalidOptionalDVNCount     = "LZ_ULN_InvalidOptionalDVNCount"
 29	ErrULNAtLeastOneDVN               = "LZ_ULN_AtLeastOneDVN"
 30	ErrULNInvalidOptionalDVNThreshold = "LZ_ULN_InvalidOptionalDVNThreshold"
 31	ErrULNInvalidConfirmations        = "LZ_ULN_InvalidConfirmations"
 32	ErrULNUnsupportedEid              = "LZ_ULN_UnsupportedEid"
 33)
 34
 35// Constants
 36var (
 37	DEFAULT_CONFIG    = address("")
 38	DEFAULT           = uint8(0)
 39	NIL_DVN_COUNT     = ^uint8(0)  // max uint8
 40	NIL_CONFIRMATIONS = ^uint64(0) // max uint64
 41	MAX_COUNT         = (^uint8(0) - 1) / 2
 42)
 43
 44type UlnBase struct {
 45	ulnConfigs configStore
 46}
 47
 48func (u *UlnBase) SetDefaultUlnConfigs(params []SetDefaultUlnConfigParam) {
 49	for _, param := range params {
 50		// Must not use NIL values
 51		if param.Config.RequiredDVNCount == NIL_DVN_COUNT {
 52			panic(ErrULNInvalidRequiredDVNCount)
 53		}
 54		if param.Config.OptionalDVNCount == NIL_DVN_COUNT {
 55			panic(ErrULNInvalidOptionalDVNCount)
 56		}
 57		if param.Config.Confirmations == NIL_CONFIRMATIONS {
 58			panic(ErrULNInvalidConfirmations)
 59		}
 60
 61		// Must have at least one DVN
 62		assertAtLeastOneDVN(param.Config)
 63
 64		u.setConfig(DEFAULT_CONFIG, param.Eid, param.Config)
 65	}
 66
 67	// Emit event
 68	// chain.Emit(ufmt.Sprintf("DefaultUlnConfigsSet(%v)", params))
 69}
 70
 71func (u *UlnBase) GetUlnConfig(oapp address, remoteEid uint32) *UlnConfig {
 72	defaultConfig, _ := u.ulnConfigs.get(DEFAULT_CONFIG, remoteEid)
 73	customConfig, hasCustom := u.ulnConfigs.get(oapp, remoteEid)
 74
 75	rtnConfig := *defaultConfig
 76
 77	// Handle confirmations
 78	if hasCustom && customConfig.Confirmations == uint64(DEFAULT) {
 79		rtnConfig.Confirmations = defaultConfig.Confirmations
 80	} else if hasCustom && customConfig.Confirmations != NIL_CONFIRMATIONS {
 81		rtnConfig.Confirmations = customConfig.Confirmations
 82	}
 83
 84	// Handle required DVNs
 85	if hasCustom && customConfig.RequiredDVNCount == DEFAULT {
 86		if defaultConfig.RequiredDVNCount > 0 {
 87			rtnConfig.RequiredDVNs = defaultConfig.RequiredDVNs
 88			rtnConfig.RequiredDVNCount = defaultConfig.RequiredDVNCount
 89		}
 90	} else if hasCustom && customConfig.RequiredDVNCount != NIL_DVN_COUNT {
 91		rtnConfig.RequiredDVNs = customConfig.RequiredDVNs
 92		rtnConfig.RequiredDVNCount = customConfig.RequiredDVNCount
 93	}
 94
 95	// Handle optional DVNs
 96	if hasCustom && customConfig.OptionalDVNCount == DEFAULT {
 97		if defaultConfig.OptionalDVNCount > 0 {
 98			rtnConfig.OptionalDVNs = defaultConfig.OptionalDVNs
 99			rtnConfig.OptionalDVNCount = defaultConfig.OptionalDVNCount
100			rtnConfig.OptionalDVNThreshold = defaultConfig.OptionalDVNThreshold
101		}
102	} else if hasCustom && customConfig.OptionalDVNCount != NIL_DVN_COUNT {
103		rtnConfig.OptionalDVNs = customConfig.OptionalDVNs
104		rtnConfig.OptionalDVNCount = customConfig.OptionalDVNCount
105		rtnConfig.OptionalDVNThreshold = customConfig.OptionalDVNThreshold
106	}
107
108	// The final value must have at least one DVN
109	assertAtLeastOneDVN(&rtnConfig)
110
111	return &rtnConfig
112}
113
114func (u *UlnBase) GetAppUlnConfig(oapp address, remoteEid uint32) *UlnConfig {
115	val, _ := u.ulnConfigs.get(oapp, remoteEid)
116	return val
117}
118
119func (u *UlnBase) SetUlnConfig(remoteEid uint32, oapp address, param *UlnConfig) {
120	u.setConfig(oapp, remoteEid, param)
121
122	// Get ULN config again as a catch all to ensure the config is valid
123	u.GetUlnConfig(oapp, remoteEid)
124
125	// Emit event
126	// chain.Emit(ufmt.Sprintf("UlnConfigSet(%s, %d, %v)", oapp, remoteEid, param))
127}
128
129func (u *UlnBase) IsSupportedEid(remoteEid uint32) bool {
130	defaultConfig, exists := u.ulnConfigs.get(DEFAULT_CONFIG, remoteEid)
131	if !exists {
132		return false
133	}
134	return defaultConfig.RequiredDVNCount > 0 || defaultConfig.OptionalDVNThreshold > 0
135}
136
137func (u *UlnBase) AssertSupportedEid(remoteEid uint32) {
138	if !u.IsSupportedEid(remoteEid) {
139		panic(ufmt.Sprintf("%s: %d", ErrULNUnsupportedEid, remoteEid))
140	}
141}
142
143func assertAtLeastOneDVN(config *UlnConfig) {
144	if config.RequiredDVNCount == 0 && config.OptionalDVNThreshold == 0 {
145		panic(ErrULNAtLeastOneDVN)
146	}
147}
148
149func (u *UlnBase) setConfig(oapp address, eid uint32, param *UlnConfig) {
150	// Required DVNs validation
151	if param.RequiredDVNCount == NIL_DVN_COUNT || param.RequiredDVNCount == DEFAULT {
152		if len(param.RequiredDVNs) != 0 {
153			panic(ErrULNInvalidRequiredDVNCount)
154		}
155	} else {
156		if len(param.RequiredDVNs) != int(param.RequiredDVNCount) || param.RequiredDVNCount > MAX_COUNT {
157			panic(ErrULNInvalidRequiredDVNCount)
158		}
159		u.assertNoDuplicates(param.RequiredDVNs)
160	}
161
162	// Optional DVNs validation
163	if param.OptionalDVNCount == NIL_DVN_COUNT || param.OptionalDVNCount == DEFAULT {
164		if len(param.OptionalDVNs) != 0 {
165			panic(ErrULNInvalidOptionalDVNCount)
166		}
167		if param.OptionalDVNThreshold != 0 {
168			panic(ErrULNInvalidOptionalDVNThreshold)
169		}
170	} else {
171		if len(param.OptionalDVNs) != int(param.OptionalDVNCount) || param.OptionalDVNCount > MAX_COUNT {
172			panic(ErrULNInvalidOptionalDVNCount)
173		}
174		if param.OptionalDVNThreshold == 0 || param.OptionalDVNThreshold > param.OptionalDVNCount {
175			panic(ErrULNInvalidOptionalDVNThreshold)
176		}
177		u.assertNoDuplicates(param.OptionalDVNs)
178	}
179	// Store the config
180	u.ulnConfigs.set(oapp, eid, param)
181}
182
183func (u *UlnBase) assertNoDuplicates(dvns []address) {
184	if len(dvns) == 0 {
185		return
186	}
187
188	lastDVN := dvns[0]
189	for i := 1; i < len(dvns); i++ {
190		if dvns[i] <= lastDVN {
191			panic(ErrULNUnsorted)
192		}
193		lastDVN = dvns[i]
194	}
195}
196
197// Render function for the contract
198func (u *UlnBase) Render(path string) string {
199	return "XXX: TODO"
200}
201
202func (ucfg *UlnConfig) MarshalJSONString() string {
203	if ucfg == nil {
204		return "{}"
205	}
206	node := json.ObjectNode("", map[string]*json.Node{
207		"confirmations":        json.NumberNode("", float64(ucfg.Confirmations)),
208		"requiredDVNCount":     json.NumberNode("", float64(ucfg.RequiredDVNCount)),
209		"optionalDVNCount":     json.NumberNode("", float64(ucfg.OptionalDVNCount)),
210		"optionalDVNThreshold": json.NumberNode("", float64(ucfg.OptionalDVNThreshold)),
211		"requiredDVNs":         json.ArrayNode("", addressSliceToJSON(ucfg.RequiredDVNs)),
212		"optionalDVNs":         json.ArrayNode("", addressSliceToJSON(ucfg.OptionalDVNs)),
213	})
214	res, err := json.Marshal(node)
215	if err != nil {
216		panic(err)
217	}
218	return string(res)
219}
220
221func addressSliceToJSON(s []address) []*json.Node {
222	res := make([]*json.Node, 0, len(s))
223	for _, elem := range s {
224		res = append(res, json.StringNode("", elem.String()))
225	}
226	return res
227}