fix(schema)!: fixes and key restrictions based on indexer testing (#21362)

This commit is contained in:
Aaron Craelius 2024-08-20 18:52:49 -04:00 committed by GitHub
parent 08a3da44b1
commit 95dcf845c3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 444 additions and 295 deletions

View File

@ -79,6 +79,8 @@ const (
// Go Encoding: string which matches the IntegerFormat regex
// JSON Encoding: base10 integer string
// Canonically encoded values should include no leading zeros.
// Equality comparison with integers should be done using numerical equality rather
// than string equality.
IntegerStringKind
// DecimalStringKind represents an arbitrary precision decimal or integer number.
@ -87,6 +89,8 @@ const (
// Canonically encoded values should include no leading zeros or trailing zeros,
// and exponential notation with a lowercase 'e' should be used for any numbers
// with an absolute value less than or equal to 1e-6 or greater than or equal to 1e6.
// Equality comparison with decimals should be done using numerical equality rather
// than string equality.
DecimalStringKind
// BoolKind represents a boolean true or false value.
@ -369,6 +373,18 @@ func (t Kind) ValidateValue(value interface{}) error {
return nil
}
// ValidKeyKind returns true if the kind is a valid key kind.
// All kinds except Float32Kind, Float64Kind, and JSONKind are valid key kinds
// because they do not define a strict form of equality.
func (t Kind) ValidKeyKind() bool {
switch t {
case Float32Kind, Float64Kind, JSONKind:
return false
default:
return true
}
}
var (
integerRegex = regexp.MustCompile(IntegerFormat)
decimalRegex = regexp.MustCompile(DecimalFormat)

View File

@ -11,7 +11,9 @@ type ObjectType struct {
// KeyFields is a list of fields that make up the primary key of the object.
// It can be empty in which case indexers should assume that this object is
// a singleton and only has one value. Field names must be unique within the
// object between both key and value fields. Key fields CANNOT be nullable.
// object between both key and value fields.
// Key fields CANNOT be nullable and Float32Kind, Float64Kind, and JSONKind types
// are not allowed.
KeyFields []Field
// ValueFields is a list of fields that are not part of the primary key of the object.
@ -53,6 +55,10 @@ func (o ObjectType) validate(types map[string]Type) error {
return fmt.Errorf("invalid key field %q: %v", field.Name, err) //nolint:errorlint // false positive due to using go1.12
}
if !field.Kind.ValidKeyKind() {
return fmt.Errorf("key field %q of kind %q uses an invalid key field kind", field.Name, field.Kind)
}
if field.Nullable {
return fmt.Errorf("key field %q cannot be nullable", field.Name)
}

View File

@ -189,6 +189,45 @@ func TestObjectType_Validate(t *testing.T) {
},
errContains: "enum \"enum1\" has different values",
},
{
name: "float32 key field",
objectType: ObjectType{
Name: "o1",
KeyFields: []Field{
{
Name: "field1",
Kind: Float32Kind,
},
},
},
errContains: "invalid key field kind",
},
{
name: "float64 key field",
objectType: ObjectType{
Name: "o1",
KeyFields: []Field{
{
Name: "field1",
Kind: Float64Kind,
},
},
},
errContains: "invalid key field kind",
},
{
name: "json key field",
objectType: ObjectType{
Name: "o1",
KeyFields: []Field{
{
Name: "field1",
Kind: JSONKind,
},
},
},
errContains: "invalid key field kind",
},
}
for _, tt := range tests {

View File

@ -8,6 +8,7 @@ import (
"cosmossdk.io/schema"
"cosmossdk.io/schema/appdata"
schematesting "cosmossdk.io/schema/testing"
"cosmossdk.io/schema/testing/statesim"
"cosmossdk.io/schema/view"
)
@ -92,10 +93,10 @@ func (a *Simulator) BlockDataGenN(minUpdatesPerBlock, maxUpdatesPerBlock int) *r
packets = append(packets, appdata.StartBlockData{Height: a.blockNum + 1})
updateSet := map[string]bool{}
// filter out any updates to the same key from this block, otherwise we can end up with weird errors
// filter out any updates to the same key from this block, otherwise we can end up with hard to debug errors
updateGen := a.state.UpdateGen().Filter(func(data appdata.ObjectUpdateData) bool {
for _, update := range data.Updates {
_, existing := updateSet[fmt.Sprintf("%s:%v", data.ModuleName, update.Key)]
_, existing := updateSet[a.formatUpdateKey(data.ModuleName, update)]
if existing {
return false
}
@ -106,7 +107,8 @@ func (a *Simulator) BlockDataGenN(minUpdatesPerBlock, maxUpdatesPerBlock int) *r
for i := 0; i < numUpdates; i++ {
data := updateGen.Draw(t, fmt.Sprintf("update[%d]", i))
for _, update := range data.Updates {
updateSet[fmt.Sprintf("%s:%v", data.ModuleName, update.Key)] = true
// we need to set the update here each time so that this is used to filter out duplicates in the next round
updateSet[a.formatUpdateKey(data.ModuleName, update)] = true
}
packets = append(packets, data)
}
@ -117,6 +119,21 @@ func (a *Simulator) BlockDataGenN(minUpdatesPerBlock, maxUpdatesPerBlock int) *r
})
}
func (a *Simulator) formatUpdateKey(moduleName string, update schema.ObjectUpdate) string {
mod, err := a.state.GetModule(moduleName)
if err != nil {
panic(err)
}
objColl, err := mod.GetObjectCollection(update.TypeName)
if err != nil {
panic(err)
}
ks := fmt.Sprintf("%s:%s:%s", moduleName, update.TypeName, schematesting.ObjectKeyString(objColl.ObjectType(), update.Key))
return ks
}
// ProcessBlockData processes the given block data, advancing the app state based on the object updates in the block
// and forwarding all packets to the attached listener. It is expected that the data passed came from BlockDataGen,
// however, other data can be passed as long as any StartBlockData packet has the height set to the current height + 1.

View File

@ -7,155 +7,155 @@ OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_integer","Key":"11598611","Value":["016807","-016339012"],"Delete":false},{"TypeName":"test_uint16","Key":9407,"Value":{"valNotNull":0,"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int16","Key":-4371,"Value":{"valNotNull":-3532,"valNullable":-15},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"\u000b𝜛࣢Ⱥ+\u001c","Value":{"Value1":-28,"Value2":"AAE5AAAAATgB"},"Delete":false},{"TypeName":"RetainDeletions","Key":".(","Value":[116120837,"/wwIyAAUciAC"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":[false,false],"Delete":false},{"TypeName":"test_float64","Key":0,"Value":[-0.819610595703125,0.08682777894820155],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"+!𐅫a⍦","Value":[36,"fi07",0.000005021243239880513,2],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["˖|󺪆𝅲鄖_.;ǀ⃣%;#~",16,512578],"Value":686,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int16","Key":-988,"Value":[6,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"?൙ဴ𑇑\".+AB","Value":{"Value1":-75,"Value2":"FdQcnKoeAAIB"},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int8","Key":6,"Value":[6,null],"Delete":false},{"TypeName":"test_int32","Key":-7573,"Value":[-57,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["\tA𐞙?\t",-5317218,1],"Value":6450,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AwMbGS8=","Value":["AwQA3EBwHgCEABQBAw==",null],"Delete":false},{"TypeName":"test_bool","Key":true,"Value":{"valNotNull":true,"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":[false,false],"Delete":false},{"TypeName":"test_float64","Key":2818,"Value":{"valNotNull":1.036618793083456e+225,"valNullable":-0.0006897732815340143},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"561415.19400226923121396E-2","Value":{"valNotNull":"-24080E11","valNullable":"192.3"},"Delete":false},{"TypeName":"test_int8","Key":-95,"Value":{"valNotNull":-101,"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"?Ⱥ","Value":{"Value1":2,"Value2":"2w==","Value3":0.05580937396734953,"Value4":16164100},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["৴ि𐞬a",-681,12863],"Value":1,"Delete":false},{"TypeName":"RetainDeletions","Key":"৯aࠤာAᬺaȺ£Ρᵧa󠁳|𝙮 A","Value":{"Value1":440,"Value2":"9Q=="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float32","Key":-874,"Value":[-0.8046875,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"CB4HBgJQBuoBFAIs4xcFRwfaoUJr4f4ACzQ5wX4qPkMAACsA1Ev/Fg==","Value":["xRQCHzcOCGqADAZNAQExHwAaBQISEagYGF4F5wEWFN/JGgHkAsYchgUCA2YRUneug+wEABUjRaAKBOoQAOATEg==","CUXz/xMEAP8BNw0PvPUBNF7rSPPDAQHTBg71MEsKHg=="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":-1168504079346,"Value":{"valNotNull":-9566526662547645,"valNullable":-1936738738498935},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"+","Value":[3,"A2k="],"Delete":false}]}
Commit: {}
StartBlock: {2 <nil> <nil>}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"ᾢ","Value":[3,"AQQF3LYA"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"_; ᾚDzA{˭҄\nA^$?ᾦ,:\u003c\"?_\u0014;|","Value":{"Value1":-15,"Value2":"PED/","Value3":7.997156312768529e-26,"Value4":33975920899014},"Delete":false},{"TypeName":"Simple","Key":"","Value":[-2,"FwY="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"AgDYbdMBAZ31DGsBs7UGnAp/BgX/BkQFAQ3Si9sd6x8Hrw==","Value":{"valNotNull":"/2ADvYQC/wATggAAAwYBLjQCAv8=","valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"GJQSAs0BGAILARUXAwIrnf8pBgIrRQOrSQNOEgfvA8ATAAEMVw8s/w==","Value":["GwADWP8AMB6z0AZCDgEDMv8DfQEQ","DAHaBAOt3g16AQAfNQEBeQYBAlv/AfgKUi0YAgg="],"Delete":false},{"TypeName":"test_duration","Key":468,"Value":[-52600,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":": Ⱥ","Value":[-14,"fmoD3wY="],"Delete":false},{"TypeName":"TwoKeys","Key":["Ⱥ꙱Lj",12],"Value":null,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"$","Value":[13,"Uf8VAgYltOwK"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["",-4],"Value":null,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":true,"Value":{"valNotNull":false,"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"\t;𞄱𑨁௺ⅦA×~ႂᛯaA","Value":{"Value1":2147483647,"Value2":"AAMBAgADGA4="},"Delete":false},{"TypeName":"RetainDeletions","Key":"\nȺ*|𑀾","Value":{"Value1":0,"Value2":"ChoCY0w="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Singleton","Key":null,"Value":["\u000b!","OQ=="],"Delete":false},{"TypeName":"Singleton","Key":null,"Value":["a",""],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"NACQYgAaAwcFAK/IAQEFWgcArAEpMAA=","Value":["Bz4X2gtkAw4DU4hgA72EAv8AE4IAAAMGAS40AgL/",null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"CB4HBgJQBuoBFAIs4xcFRwfaoUJr4f4ACzQ5wX4qPkMAACsA1Ev/Fg==","Value":null,"Delete":true},{"TypeName":"test_address","Key":"CB4HBgJQBuoBFAIs4xcFRwfaoUJr4f4ACzQ5wX4qPkMAACsA1Ev/Fg==","Value":{"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AA==","Value":{"valNotNull":"FRcD","valNullable":"K53/"},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Singleton","Key":null,"Value":{"Value":"℘A⤯","Value2":"ALZMCik="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["(弡𞥃",124],"Value":null,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":true,"Value":[false,null],"Delete":false},{"TypeName":"test_integer","Key":"64","Value":["-307711","-2"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"?Ⱥ","Value":[-278,"AgYltOwK",-6.0083863735198975,429016],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"-97E-70","Value":{"valNotNull":"-650530110","valNullable":null},"Delete":false},{"TypeName":"test_decimal","Key":"561415.19400226923121396E-2","Value":null,"Delete":true}]}
Commit: {}
StartBlock: {3 <nil> <nil>}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int32","Key":-103,"Value":{"valNotNull":-1887959808,"valNullable":2096073436},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":true,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"","Value":{"Value1":-4,"Value2":"","Value3":5.199354003997906e-290,"Value4":2703222758},"Delete":false},{"TypeName":"ThreeKeys","Key":["˖|󺪆𝅲鄖_.;ǀ⃣%;#~",16,512578],"Value":11281,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":7,"Value":{"valNotNull":1,"valNullable":150},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"?൙ဴ𑇑\".+AB","Value":[-1,"LP8="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_integer","Key":"72961530924372552","Value":["080207094","-598415299"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float64","Key":-1.7392669057403718e+166,"Value":[1.556643269146063e-16,-1.1920928955078125e-7],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["ऻॉ~$𒐈+Xʱ:²-~?ʳ~$ₜ\\",-787],"Value":null,"Delete":false},{"TypeName":"Singleton","Key":null,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"\u000b𝜛࣢Ⱥ+\u001c","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":14,"Value":[4,1],"Delete":false},{"TypeName":"test_address","Key":"AgDYbdMBAZ31DGsBs7UGnAp/BgX/BkQFAQ3Si9sd6x8Hrw==","Value":["BQEBAemXEjNqrx2kATMdGuUCESLnES4KAfAC//v/A9gJIaQNAQH/kcYdDw==","lMhHJAXnpQG+wgIzzAoNWjoAGTIABQ=="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["Ⱥ꙱Lj",12],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int32","Key":897,"Value":[454,-2],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float32","Key":-874,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":0,"Value":[1,null],"Delete":false},{"TypeName":"test_decimal","Key":"-97E-70","Value":["36141e01","50562961530924372552"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["৴ि𐞬a",-681,12863],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AAD/AAAFAAEAUQ==","Value":{"valNotNull":"Nw==","valNullable":"AABdSw=="},"Delete":false},{"TypeName":"test_enum","Key":"baz","Value":["bar",null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"CB4HBgJQBuoBFAIs4xcFRwfaoUJr4f4ACzQ5wX4qPkMAACsA1Ev/Fg==","Value":null,"Delete":true},{"TypeName":"test_uint16","Key":9407,"Value":[15,3],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_integer","Key":"433032","Value":{"valNotNull":"711","valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_string","Key":"~?ʳ~$ₜ\\","Value":["*¾",null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint32","Key":995,"Value":{"valNotNull":7,"valNullable":null},"Delete":false},{"TypeName":"test_time","Key":"1969-12-31T18:59:59.999999971-05:00","Value":{"valNotNull":"1969-12-31T18:59:59.999999994-05:00","valNullable":"1969-12-31T18:59:59.999580498-05:00"},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_string","Key":"aή⃢\t{ǁ","Value":{"valNotNull":"ሢ϶","valNullable":null},"Delete":false},{"TypeName":"test_uint8","Key":2,"Value":{"valNotNull":17,"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["A*۽~Dz₱ {",-8,2],"Value":{"Value1":1056454},"Delete":false},{"TypeName":"TwoKeys","Key":["mA৴pa_〩ãᛮDž𑣠ʰA%a",1],"Value":null,"Delete":false}]}
Commit: {}
StartBlock: {4 <nil> <nil>}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":-152,"Value":{"valNotNull":1476419818092,"valNullable":-163469},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"","Value":[-1,"GwE="],"Delete":false},{"TypeName":"ManyValues","Key":"","Value":[1,"",4.1017235364794545e-228,25],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":".(","Value":null,"Delete":true},{"TypeName":"Singleton","Key":null,"Value":{"Value":"ᾫ+=[฿́\u001b\u003cʰ+`𑱐@\u001b*Dž‮#₻\u0001῎ !a܏ῼ","Value2":"AgI="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"?൙ဴ𑇑\".+AB","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":" ","Value":[-1,""],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["",11,107],"Value":{"Value1":-31402597},"Delete":false},{"TypeName":"Simple","Key":"\t;𞄱𑨁௺ⅦA×~ႂᛯaA","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint16","Key":0,"Value":{"valNotNull":68,"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"PQYReIgDAAG/6fs+AVcXxgEGDXLQ30f0/w==","Value":["b+QAdJmb/0hGGAMzEoat/wYeAQcB/wO7Ae0BlgQFAP+i7A0rGA8ESIv+Oi+eFwIDHAMAygDjBogABwADAAC5Aw==",null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["\tA𐞙?\t",-5317218,1],"Value":{"Value1":-220},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_integer","Key":"617","Value":{"valNotNull":"688647620","valNullable":null},"Delete":false},{"TypeName":"test_bool","Key":false,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"","Value":[-1,"GwE="],"Delete":false},{"TypeName":"ManyValues","Key":"_; ᾚDzA{˭҄\nA^$?ᾦ,:\u003c\"?_\u0014;|","Value":[0,"APMAAh8=",2.6405210300043274e-261,4678],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"+","Value":[-265,"7v+nXKjOoQ=="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["(弡𞥃",124],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int64","Key":-1,"Value":{"valNotNull":2070362465348116,"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"NACQYgAaAwcFAK/IAQEFWgcArAEpMAA=","Value":["AKjiCQIBAyv/AAD8AcQADwD/AEP7eg==","C2YHNQMBaxQz0wAPGXQqGQYCAAPQAhUB05AB7QUAbnLpM7hyjBwAb+QAdJmb/0hGGAMzEoat/wYeAQ=="],"Delete":false},{"TypeName":"test_float64","Key":5224,"Value":[-1683.1097246298846,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AA==","Value":["Md4BCACgAADoAG8cHQ5tB0c1HAA=",null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["a\u003c",-84],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":2,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float32","Key":-218792,"Value":[1.0914612,null],"Delete":false},{"TypeName":"test_duration","Key":-9223372036854775808,"Value":{"valNotNull":399806,"valNullable":-336},"Delete":false}]}
Commit: {}
StartBlock: {5 <nil> <nil>}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":true,"Value":{"valNotNull":true,"valNullable":null},"Delete":false},{"TypeName":"test_uint64","Key":21,"Value":{"valNotNull":73,"valNullable":2},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"AgDYbdMBAZ31DGsBs7UGnAp/BgX/BkQFAQ3Si9sd6x8Hrw==","Value":["BQBsCf9MAgQAGfzKAAu1AYAClAADAhlDAP+oChQBYQA5AA0LT19MujQyf/8FbQMDawAM",null],"Delete":false},{"TypeName":"test_enum","Key":"foo","Value":{"valNotNull":"foo","valNullable":"foo"},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Singleton","Key":null,"Value":["𝔏؃\"ᵚ¡ $A\r",""],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["𒑏𑿞=A?¯ \t~",-6,53],"Value":-2,"Delete":false},{"TypeName":"Simple","Key":"?","Value":{"Value1":12,"Value2":"HAIBmK0D"},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"⍦","Value":[-202,"EQTRAwAELg=="],"Delete":false},{"TypeName":"ManyValues","Key":"`aAះA~~⹗=\u000b","Value":[-17,"okMB1d0=",-3.643491752614398e+288,1382771530458],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float64","Key":0,"Value":[-1014342049.3947449,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["a\u003c",-84],"Value":null,"Delete":true},{"TypeName":"Simple","Key":"d⹘:","Value":[3016,"AQ=="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AwMbGS8=","Value":null,"Delete":true},{"TypeName":"test_decimal","Key":"-02","Value":["1219101",null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"9.5E+8","Value":{"valNotNull":"13333140202.01031939e81","valNullable":"7210210.1e+1"},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint16","Key":11,"Value":[6,14912],"Delete":false},{"TypeName":"test_duration","Key":-152,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"`³Njॊ\u003c?ᾩ‮₦~","Value":{"Value1":2,"Value2":"lAAD4AAABQQbAwABAwHP"},"Delete":false},{"TypeName":"RetainDeletions","Key":"൴~𝔶ٞ蹯a_ ᛮ!؋aض©-?","Value":{"Value1":-6813,"Value2":"AhRPdlAC"},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"BkiVAAcAAJ6xA/dutlmcBe8DAA1UZAsB","Value":["AA57GQP/oifkJ8aYJENTAwLxPhPSAwEI1AA9xQMWAwEoBA==",null],"Delete":false},{"TypeName":"test_address","Key":"7QTt/24APN4FBA/TAG8B/wMBWOoCqP+HNg0FBQIdAw8F5AI=","Value":["BQNcFhh01gEBAm4BAfAlGwMKkCo=","aQQTfSUg2RkZARH/EP8IGAxENIBOGwbPFAA="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int8","Key":6,"Value":[-8,null],"Delete":false},{"TypeName":"test_address","Key":"AACHBAjyAgFHOQAABo+PGAK3Bj7TwwBb/wAB3gE=","Value":["ASwojxUABA8BAf/9AgUBIs4WAq9lqAEKAP8FAAgCGwEMDQKHZwEABA82AVZZAHO/ngS7AA==",null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"AWvYAbSo5gQCAz8XAQYGjwCaRx0DSAUpAWQV","Value":["/z/eNBkL5QAgCwXergJOUCEC/+ICAp4BTgBsVw==","HhoELBAPigABQwIDAxsB7KEAGlIOEAAEYQL/GQA37QAJWg0A"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":" ","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"79","Value":["-7872","53"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint32","Key":1322158439,"Value":{"valNotNull":2415,"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"_; ᾚDzA{˭҄\nA^$?ᾦ,:\u003c\"?_\u0014;|","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["\tA𐞙?\t",-5317218,1],"Value":-2147483648,"Delete":false},{"TypeName":"ManyValues","Key":"‮۽𝅸\u003c#󠁋","Value":[-3,"",-5.385845077524242e-269,2468],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":true,"Value":null,"Delete":true},{"TypeName":"test_int8","Key":-6,"Value":{"valNotNull":122,"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":{"valNullable":false},"Delete":false},{"TypeName":"test_address","Key":"UQMARFtfJYloAQ5FAQE+P5ezAZMCP82oChQBYQA5AA0LT19MujQyf/8FbQMDawAM","Value":["zQIdDAwCA1MfywMMFUrXCRcsAAC3OAYBAAyUCi36BQQAAuUkAACrBgAHAgUCAcYAJgM=","HAIBmK0DtgEBBwEBLzEFjXltUcIBBAFcAuZTALIBmAeVArgXLpEyAwAd2rwXD/+2wOT37ekWAr4EAEvnhw=="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"?Ⱥ","Value":{"Value4":80},"Delete":false},{"TypeName":"RetainDeletions","Key":"@:","Value":[3016,"AQ=="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AAD/AAAFAAEAUQ==","Value":null,"Delete":true},{"TypeName":"test_decimal","Key":"800","Value":["7119101",null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"","Value":{"Value2":"LpIWCQoAbw=="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint64","Key":96,"Value":[2,null],"Delete":false},{"TypeName":"test_uint8","Key":0,"Value":[178,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"৯aࠤာAᬺaȺ£Ρᵧa󠁳|𝙮 A","Value":{"Value2":""},"Delete":false},{"TypeName":"Singleton","Key":null,"Value":{"Value":"/ᾪ蹯a_ ᛮ!؋aض©-?","Value2":"4A=="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["Ⱥേ҈a҉Ⱥ",-114036639,4],"Value":2147483647,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_string","Key":"aή⃢\t{ǁ","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":-40715358873,"Value":{"valNotNull":-35986926993,"valNullable":null},"Delete":false},{"TypeName":"test_time","Key":"1969-12-31T18:59:59.981789806-05:00","Value":["1969-12-31T18:57:57.72625051-05:00","1969-12-26T16:36:45.679781385-05:00"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"-40530.610059","Value":{"valNotNull":"-344079482.57151","valNullable":null},"Delete":false},{"TypeName":"test_enum","Key":"baz","Value":{"valNotNull":"bar","valNullable":"baz"},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float32","Key":-218792,"Value":null,"Delete":true},{"TypeName":"test_address","Key":"NACQYgAaAwcFAK/IAQEFWgcArAEpMAA=","Value":{"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"-97E-70","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AA==","Value":null,"Delete":true},{"TypeName":"test_bytes","Key":"Bw==","Value":["AwYGBg2V","EWShfAE="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"A","Value":[3939571,"oAE="],"Delete":false},{"TypeName":"ThreeKeys","Key":["a .౺ऻ\u0026",-1,0],"Value":-343368,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["`ҡ",-483],"Value":null,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"aȺ\ta\u0026A୵","Value":{"Value1":1627290802,"Value2":"DQA=","Value3":70375169.64453125,"Value4":7578767657429368},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"󠇯$ aḍa\r","Value":[59,""],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["mA৴pa_〩ãᛮDž𑣠ʰA%a",1],"Value":null,"Delete":true}]}
Commit: {}
StartBlock: {6 <nil> <nil>}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["A𞥟",981],"Value":null,"Delete":false},{"TypeName":"ManyValues","Key":"ᵕ؏­􏿽A","Value":{"Value1":-317,"Value2":"AA==","Value3":-37.62890625,"Value4":232},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"AACHBAjyAgFHOQAABo+PGAK3Bj7TwwBb/wAB3gE=","Value":{"valNotNull":"HBwBHAY6AAKO+UwDKRICAT0lgRRvCRvHFFoNAigBAUEDHoQUfB2qApRB/z41AAubARsBATQg3gCppQMAAQwHAQ=="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"9.5E+8","Value":["-2","88111430.0122412446"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":7,"Value":null,"Delete":true},{"TypeName":"test_time","Key":"1969-12-31T18:59:59.999999999-05:00","Value":["1969-12-31T19:00:00.000000001-05:00",null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"൴~𝔶ٞ蹯a_ ᛮ!؋aض©-?","Value":{"Value2":""},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":14,"Value":{"valNotNull":116},"Delete":false},{"TypeName":"test_duration","Key":100403021838,"Value":[1547,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int64","Key":-34196421,"Value":[56,224549431],"Delete":false},{"TypeName":"test_bool","Key":true,"Value":{"valNotNull":true,"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["ⅷ_ŕ,A",-467,98],"Value":{"Value1":145},"Delete":false},{"TypeName":"RetainDeletions","Key":"?aa₽A\u001b=⇂́ᯫ𖽦ᩣ","Value":{"Value1":0,"Value2":""},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["",-4],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"NACQYgAaAwcFAK/IAQEFWgcArAEpMAA=","Value":{"valNotNull":"HBwBHAY6AAKO+UwDKRICAT0lgRRvCRvHFFoNAigBAUEDHoQUfB2qApRB/z41AAubARsBATQg3gCppQMAAQwHAQ=="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"-40530.610059","Value":["-2","88111430.0122412446"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":0,"Value":null,"Delete":true},{"TypeName":"test_time","Key":"1969-12-31T18:59:59.981789806-05:00","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Singleton","Key":null,"Value":{"Value":"","Value2":"NeIMrxEMAgI="},"Delete":false},{"TypeName":"RetainDeletions","Key":"꙲󽬺","Value":[835552366,"ngY="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["\u0026AȺ#˼%֘_ŕ,A",-467,98],"Value":{"Value1":145},"Delete":false},{"TypeName":"RetainDeletions","Key":"?aa₽A\u001b=⇂́ᯫ𖽦ᩣ","Value":{"Value1":0,"Value2":""},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["`ҡ",-483],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"","Value":{"Value1":1174095848,"Value2":"AR//A0kBNVwGGGsHANYAAAAtJQ=="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint64","Key":3,"Value":[14481555953,496],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"ǃ^@❽\u2028!𑿞aa`","Value":{"Value1":-33730,"Value2":"qKQ="},"Delete":false},{"TypeName":"Singleton","Key":null,"Value":["𞤎𞤡","BAconQGXHRuHXQN/GTUCSQACEg=="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"ൌ{ ༿","Value":[1110340689,"AQ==",0.00018342199999210607,1],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AwcJA//C","Value":{"valNotNull":"DQ==","valNullable":null},"Delete":false},{"TypeName":"test_duration","Key":210213542904,"Value":[-207349773999415086,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float64","Key":-3.0664227080502325e-103,"Value":[2.125936378595003e-239,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"৯aࠤာAᬺaȺ£Ρᵧa󠁳|𝙮 A","Value":null,"Delete":true},{"TypeName":"ManyValues","Key":"aȺ\ta\u0026A୵","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"A","Value":{"Value2":"NwIDBwkD/8I="},"Delete":false},{"TypeName":"Simple","Key":"a ¥𐅝`B܆Å$*","Value":{"Value1":2147483647,"Value2":"4gYDABg="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"19201864880978510.28381871008156E9","Value":["14793512",null],"Delete":false},{"TypeName":"test_enum","Key":"baz","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"󠇯$ aḍa\r","Value":[-9,"0AEFPHM="],"Delete":false},{"TypeName":"ThreeKeys","Key":["",0,3265605],"Value":-3703028,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["Ⱥേ҈a҉Ⱥ",-114036639,4],"Value":{"Value1":502},"Delete":false}]}
Commit: {}
StartBlock: {7 <nil> <nil>}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":true,"Value":{"valNotNull":true,"valNullable":true},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"d⹘:","Value":{"Value2":""},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["ऻॉ~$𒐈+Xʱ:²-~?ʳ~$ₜ\\",-787],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"","Value":{"Value2":""},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":[false,null],"Delete":false},{"TypeName":"test_bool","Key":false,"Value":{"valNullable":true},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["A𞥟",981],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["ः𒑨Dz؅",-2],"Value":null,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["@(\u0001\u0001\tᛰᾚ𐺭a'ᵆᾭaa",16,817744173394],"Value":{"Value1":-2},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AwcJA//C","Value":{"valNotNull":"AWNXAw=="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"Bw==","Value":{"valNotNull":"AWNXAw=="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"-85","Value":["-2511998","-077.01427082957E-7"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int16","Key":-988,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_enum","Key":"foo","Value":null,"Delete":true},{"TypeName":"test_decimal","Key":"-02","Value":["-40892500970.58239","11e0"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_string","Key":"","Value":{"valNotNull":"実.*𑁤!؋A\u000b.{;?󠀮_? *🄑󠇯","valNullable":"(Ⱥ#/\u003c_"},"Delete":false},{"TypeName":"test_integer","Key":"-1391361","Value":{"valNotNull":"-0105","valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"AWvYAbSo5gQCAz8XAQYGjwCaRx0DSAUpAWQV","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int8","Key":98,"Value":[-40,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int16","Key":-4371,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_enum","Key":"foo","Value":{"valNotNull":"foo","valNullable":null},"Delete":false},{"TypeName":"test_uint32","Key":522395,"Value":[2730,3],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"sucDH0r/CmEAgjcBB7H1AgAcEtI=","Value":["GVr4AxwBAN14AAYApgFuif8HrpAE9FcABBcPAGpHAQLtE3UmLQwOAjgrEMMC4w//","irH/SwYtmFOeC3EE/wEdAxnJCn8Oapb/tWjEj28BLhs1"],"Delete":false},{"TypeName":"test_address","Key":"NACQYgAaAwcFAK/IAQEFWgcArAEpMAA=","Value":["AwIBAz8EAA5dZQEATgEBAnG+p3MPVwYAEV1dBwMDAQADCgYEJQcD+EgAAAcB","t3xyAAYBDQQHAgHH1ANoVw//Pv+nAP89Ao8OANr3BUIBAg=="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":7,"Value":[190,null],"Delete":false}]}
Commit: {}
StartBlock: {8 <nil> <nil>}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"$","Value":[0,""],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"\u000b𝜛࣢Ⱥ+\u001c","Value":[0,""],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"8E4","Value":{"valNotNull":"4043421E29","valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"AACHBAjyAgFHOQAABo+PGAK3Bj7TwwBb/wAB3gE=","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["A𞥟",981],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["",55175],"Value":null,"Delete":false},{"TypeName":"RetainDeletions","Key":"`³Njॊ\u003c?ᾩ‮₦~","Value":{"Value1":3},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":468,"Value":[-4,-805402038367],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":true,"Value":null,"Delete":true},{"TypeName":"test_int32","Key":-24,"Value":[1,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"҉߃ ","Value":[-526,""],"Delete":false},{"TypeName":"Simple","Key":": Ⱥ","Value":[59,"Kw=="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_enum","Key":"bar","Value":{"valNotNull":"foo","valNullable":null},"Delete":false},{"TypeName":"test_int64","Key":2481611475,"Value":[136,6],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float64","Key":-3.0664227080502325e-103,"Value":[-0.34326171875,-1.9202818317669984e-13],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Singleton","Key":null,"Value":null,"Delete":true},{"TypeName":"Singleton","Key":null,"Value":{"Value":"","Value2":"ClAs"},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"?b\r##/$ͥ","Value":[10,"",5.231528162956238,42],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"ݙaس\u003cй?{E","Value":{"Value1":-15,"Value2":"o+MQ"},"Delete":false},{"TypeName":"RetainDeletions","Key":"൴~𝔶ٞ蹯a_ ᛮ!؋aض©-?","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"AwcJA//C","Value":{"valNullable":""},"Delete":false},{"TypeName":"test_uint32","Key":1322158439,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["[Ⰶ\u2029\u0026𒐗🕳c҉\u0026฿a\u0026",-79424],"Value":null,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int8","Key":-128,"Value":[7,null],"Delete":false},{"TypeName":"test_int32","Key":-103,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"ᾢ","Value":[-2356,"DA=="],"Delete":false},{"TypeName":"ManyValues","Key":"","Value":{"Value1":28,"Value2":"","Value3":-1.6098999622118156e+67,"Value4":14},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"?≚a'","Value":{"Value1":-611,"Value2":"AgqTAG4=","Value3":-2.0360732649240822e+100,"Value4":0},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float64","Key":0,"Value":[2.5625,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint64","Key":3,"Value":{"valNotNull":59,"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"NACQYgAaAwcFAK/IAQEFWgcArAEpMAA=","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["ः𒑨Dz؅",-2],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["",55175],"Value":null,"Delete":false},{"TypeName":"RetainDeletions","Key":"?aa₽A\u001b=⇂́ᯫ𖽦ᩣ","Value":{"Value1":3},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":-9223372036854775808,"Value":[-4,-805402038367],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":null,"Delete":true},{"TypeName":"test_int32","Key":-24,"Value":[1,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"҉߃ ","Value":[-526,""],"Delete":false},{"TypeName":"Simple","Key":"A","Value":[59,"Kw=="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"UQMARFtfJYloAQ5FAQE+P5ezAZMCP82oChQBYQA5AA0LT19MujQyf/8FbQMDawAM","Value":["CRRWVxf/DVOzCAMAClAsCT0BAP8BPQ==",null],"Delete":false},{"TypeName":"test_enum","Key":"baz","Value":["bar","foo"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bytes","Key":"BQ==","Value":{"valNotNull":"AQYYDVF9MQF2","valNullable":"qQU="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int64","Key":-1,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_integer","Key":"433032","Value":{"valNotNull":"25","valNullable":"937"},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int16","Key":9863,"Value":[1851,null],"Delete":false},{"TypeName":"test_decimal","Key":"800","Value":["0448127215514e88",null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"@:","Value":null,"Delete":true},{"TypeName":"ManyValues","Key":"ᵕ؏­􏿽A","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"'","Value":{"Value1":-611,"Value2":"AgqTAG4="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Singleton","Key":null,"Value":["$?A","BAtu"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["h ʶ?\\A魘",47994411],"Value":null,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint64","Key":96,"Value":{"valNotNull":4576150250879893,"valNullable":329},"Delete":false},{"TypeName":"test_duration","Key":-152,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"󴵠","Value":[-3,"QwH/FQ=="],"Delete":false},{"TypeName":"ThreeKeys","Key":["_\u001b\u0026㉉",7,3662],"Value":{"Value1":-3316206},"Delete":false}]}
Commit: {}
StartBlock: {9 <nil> <nil>}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["ः𒑨Dz؅",-2],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["h ʶ?\\A魘",47994411],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"_<>é","Value":{"Value1":9,"Value2":"Ywc="},"Delete":false},{"TypeName":"Singleton","Key":null,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"A%aa ¹­ ᾏaĵ¨","Value":[9,"A/faBuYCCecZ3ATQAQcC3gAsizI="],"Delete":false},{"TypeName":"ThreeKeys","Key":[" {a",2790155,310794],"Value":{"Value1":312},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int32","Key":892,"Value":[-3,null],"Delete":false},{"TypeName":"test_duration","Key":210213542904,"Value":[-722503,113854019],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":468,"Value":[12,null],"Delete":false},{"TypeName":"test_int16","Key":0,"Value":[3089,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"79","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["",11,107],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":[true,true],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":": Ⱥ","Value":{"Value1":-2147483648},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":14,"Value":null,"Delete":true},{"TypeName":"test_integer","Key":"-1391361","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"","Value":[-242379,"BngOEOsA"],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int8","Key":6,"Value":null,"Delete":true},{"TypeName":"test_address","Key":"BkiVAAcAAJ6xA/dutlmcBe8DAA1UZAsB","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":" 😖₱ ̄؀ा󠁿","Value":[7541152,""],"Delete":false},{"TypeName":"ThreeKeys","Key":["ⅷ_ŕ,A",-467,98],"Value":2,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_int32","Key":892,"Value":[-3,null],"Delete":false},{"TypeName":"test_duration","Key":-9223372036854775808,"Value":[-722503,113854019],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":-40715358873,"Value":[12,null],"Delete":false},{"TypeName":"test_int16","Key":0,"Value":[3089,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"19201864880978510.28381871008156E9","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["",0,3265605],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":{"valNotNull":false,"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"82509790016910","Value":{"valNotNull":"-51151","valNullable":null},"Delete":false},{"TypeName":"test_address","Key":"UQMARFtfJYloAQ5FAQE+P5ezAZMCP82oChQBYQA5AA0LT19MujQyf/8FbQMDawAM","Value":{"valNotNull":"xbA200EFExwKoFrhCgcAYwFvDgEBXAH8AADJAAQFDfgITwIFDh8BAXQMRUwBAgY8/wANBCQGANqvCWL/AYwA+g==","valNullable":"OgPvFo8DAA+2AgEBBM4BXSAA/wCBlzxUAVoC/wQBAbIMKiwD/0MBKAF4Bv8BAoIOUwALFSMuVgIAAZddBQEDBA=="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_integer","Key":"64","Value":["13","-732"],"Delete":false},{"TypeName":"test_float32","Key":-2147483648,"Value":{"valNotNull":-0.38865662,"valNullable":null},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"ൌ{ ༿","Value":{"Value1":-152,"Value3":-204.96875},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"","Value":{"Value1":-44227},"Delete":false},{"TypeName":"Simple","Key":"A","Value":[837,"Aw=="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"<EFBFBD>-\u003e𝟆Ⱥ`Ṙ|¤﮺̺","Value":[1137505,"UQAXACIMig=="],"Delete":false}]}
Commit: {}
StartBlock: {10 <nil> <nil>}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":87208838869,"Value":[-9725,4968373],"Delete":false},{"TypeName":"test_duration","Key":468,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_duration","Key":87208838869,"Value":[-9725,4968373],"Delete":false},{"TypeName":"test_duration","Key":-40715358873,"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"","Value":[-1,"FQIK"],"Delete":false},{"TypeName":"Singleton","Key":null,"Value":{"Value":"œLj$࿇ ᾙ☇؄ೲȺ","Value2":"ADei6AACZTMDDss="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":[true,null],"Delete":false},{"TypeName":"test_enum","Key":"bar","Value":{"valNotNull":"baz","valNullable":"baz"},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["\tA𐞙?\t",-5317218,1],"Value":{"Value1":1},"Delete":false},{"TypeName":"RetainDeletions","Key":"\u0026ٱȺ+҉@","Value":[63,"AAE="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float64","Key":-1.7392669057403718e+166,"Value":[-1.0781831287525041e+139,111.37014762980289],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"GJQSAs0BGAILARUXAwIrnf8pBgIrRQOrSQNOEgfvA8ATAAEMVw8s/w==","Value":{"valNotNull":"em2zQwR2O7EAAAYLk23QBADE/wA="},"Delete":false},{"TypeName":"test_address","Key":"PQYReIgDAAG/6fs+AVcXxgEGDXLQ30f0/w==","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_bool","Key":false,"Value":[true,null],"Delete":false},{"TypeName":"test_enum","Key":"baz","Value":{"valNotNull":"baz","valNullable":"baz"},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":[" {a",2790155,310794],"Value":{"Value1":1},"Delete":false},{"TypeName":"RetainDeletions","Key":"\u0026ٱȺ+҉@","Value":[63,"AAE="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_float64","Key":2818,"Value":[-1.0781831287525041e+139,111.37014762980289],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_address","Key":"sucDH0r/CmEAgjcBB7H1AgAcEtI=","Value":{"valNotNull":"em2zQwR2O7EAAAYLk23QBADE/wA="},"Delete":false},{"TypeName":"test_address","Key":"UQMARFtfJYloAQ5FAQE+P5ezAZMCP82oChQBYQA5AA0LT19MujQyf/8FbQMDawAM","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"","Value":[-188,"",-2632691.375,17],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["A]$",-125,43],"Value":12654289,"Delete":false},{"TypeName":"RetainDeletions","Key":"?aa₽A\u001b=⇂́ᯫ𖽦ᩣ","Value":{"Value2":"ARM="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":0,"Value":{"valNotNull":0,"valNullable":null},"Delete":false},{"TypeName":"test_float32","Key":1.7852577e+32,"Value":[1.6582896,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"?b\r##/$ͥ","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"TwoKeys","Key":["",55175],"Value":null,"Delete":true},{"TypeName":"ThreeKeys","Key":["˖|󺪆𝅲鄖_.;ǀ⃣%;#~",16,512578],"Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"RetainDeletions","Key":"A%aa ¹­ ᾏaĵ¨","Value":null,"Delete":true}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"Simple","Key":"","Value":{"Value2":"DAcBeTgAFAED"},"Delete":false},{"TypeName":"RetainDeletions","Key":"ʵ² *ᾍA@҂b⭗@‮൞","Value":{"Value1":547,"Value2":""},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":4,"Value":[17,null],"Delete":false},{"TypeName":"test_uint8","Key":8,"Value":[2,12],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"҉♰ᾜȺ൜堯Ⱥ៵\"","Value":{"Value1":-10,"Value2":"jg==","Value3":-0.11867497289509932,"Value4":24065},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["A]$",-125,43],"Value":12654289,"Delete":false},{"TypeName":"RetainDeletions","Key":"+","Value":{"Value2":"ARM="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_uint8","Key":35,"Value":[0,51],"Delete":false},{"TypeName":"test_uint8","Key":107,"Value":[4,null],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"all_kinds","Updates":[{"TypeName":"test_decimal","Key":"-85","Value":{"valNotNull":"-25"},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["_\u001b\u0026㉉",7,3662],"Value":{"Value1":-80},"Delete":false},{"TypeName":"RetainDeletions","Key":"'","Value":[5521,"kwsBjw=="],"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["@(\u0001\u0001\tᛰᾚ𐺭a'ᵆᾭaa",16,817744173394],"Value":-1,"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ManyValues","Key":"Nj#߁#҉♰ᾜȺ൜堯Ⱥ៵\"","Value":{"Value1":-10,"Value2":"jg==","Value3":-0.11867497289509932,"Value4":24065},"Delete":false},{"TypeName":"RetainDeletions","Key":"","Value":{"Value1":2204165,"Value2":"Jg=="},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["A*۽~Dz₱ {",-8,2],"Value":{"Value1":624},"Delete":false},{"TypeName":"ManyValues","Key":"ڥ\u0026\u000b","Value":{"Value1":0,"Value2":"BmQD","Value3":-6.822989118840796e-47,"Value4":654213},"Delete":false}]}
OnObjectUpdate: {"ModuleName":"test_cases","Updates":[{"TypeName":"ThreeKeys","Key":["{Ⱥ\t$࿐(#",117624,128273],"Value":14,"Delete":false},{"TypeName":"RetainDeletions","Key":"A%aa ¹­ ᾏaĵ¨","Value":{"Value2":"Av8="},"Delete":false}]}
Commit: {}

View File

@ -2,78 +2,68 @@ App State Diff:
MODULE COUNT ERROR: expected 2, got 1
Module all_kinds
Object Collection test_address
OBJECT COUNT ERROR: expected 16, got 14
Object key=0x0c6ff6530300000704ff285714816e0d0b03010d0102010302ff7400d60103c2110e3700c30105679f0910570048aa48f6b4680128821c98011d00240c2c00ff
valNotNull: expected [43 29 85 255 6 1 176 1 241 222 0 0 14 116 190 1 11 30 2 8 1 144 12 2 12 1 16 15 1 1 27 8 0 255 57 2 6 195 255 60 0 201 255 1 1 13 9 112 1 2 0 121 12 172 254 22 11 1 5 37 54 212 121 0], got [220 0 1 2 13 4 24 1 12 24 58 0 1 224 0 148 104 51 116 27 56 39 14 32 35 84 126 2 18 1 5 6]
valNullable: expected [189 125 119 246 192 0 3 170 24 6 10 123 0 7 34 118 1 212 187 7 1 249 110 146 10 14 0 3 223 134 65 0 15 248 153], got [29 201 1 2 1 63 13 0 191 75 1 2 240 10 209 58 15 137 184 141 148]
Object key=0x18f0037d00012c006d9c72096b011e01f600035108fe0303000100031f1f020f08002203000502010120060f1b0201180203006a00e0: NOT FOUND
Object key=0xa10f005de9c1010692980d213250ef13020697430007000bdc01010305054f4001b7ba39003a01d2ae0e59007eef4e19e9020e006974016d00001c00037b7028: NOT FOUND
Object key=0xff2619001c04b3031aa10d9d167f1f0046d6760216009c: NOT FOUND
Object Collection test_bytes
OBJECT COUNT ERROR: expected 5, got 4
Object key=0x000a4f0f6e9b67f6: NOT FOUND
Object key=0x0e0827
valNotNull: expected [159 2], got [41 6 2 75]
valNullable: expected [0 11 54 47 28], got [6]
Object key=0xff661b1c00
valNullable: expected [15 20 0 1 132 7 37 3 28 2], got [0 8 1 170 90 0 1 201 97 138 53 2]
Object Collection test_decimal
OBJECT COUNT ERROR: expected 5, got 3
Object key=-04360.6e32: NOT FOUND
Object key=-21918e-3: NOT FOUND
Object key=-37.02e01: NOT FOUND
Object key=41090120E-3
valNotNull: expected 04.13921382165470301184220430, got 0255559.705E-4
valNullable: expected -2e5, got nil
Object Collection test_duration
OBJECT COUNT ERROR: expected 1, got 2
Object Collection test_enum
OBJECT COUNT ERROR: expected 1, got 2
OBJECT COUNT ERROR: expected 14, got 13
Object key=0x34009062001a03070500afc80101055a0700ac01293000: NOT FOUND
Object key=0x5b01cd8d349b030278030112d8e6020f00000600cc2f66016a016d01: NOT FOUND
Object Collection test_bool
Object key=false
valNotNull: expected true, got false
Object key=true
valNotNull: expected true, got false
Object Collection test_bytes
Object key=0x09: NOT FOUND
Object Collection test_decimal
OBJECT COUNT ERROR: expected 6, got 5
Object key=-99910.16: NOT FOUND
Object key=309967364: NOT FOUND
Object Collection test_duration
OBJECT COUNT ERROR: expected 8, got 7
Object key=-3m19.124749496s: NOT FOUND
Object key=45ns: NOT FOUND
Object Collection test_float32
OBJECT COUNT ERROR: expected 3, got 4
Object Collection test_int16
OBJECT COUNT ERROR: expected 9, got 8
Object key=-44: NOT FOUND
Object Collection test_int32
OBJECT COUNT ERROR: expected 2, got 1
Object key=-453: NOT FOUND
Object key=205: NOT FOUND
Object Collection test_int64
OBJECT COUNT ERROR: expected 3, got 5
Object key=-41
valNotNull: expected 244, got -5717
valNullable: expected nil, got 0
Object Collection test_int8
OBJECT COUNT ERROR: expected 4, got 3
Object key=-2: NOT FOUND
Object key=53
valNotNull: expected 27, got 58
valNullable: expected nil, got -10
Object Collection test_integer
OBJECT COUNT ERROR: expected 7, got 6
Object key=-31083911818: NOT FOUND
Object key=191
valNotNull: expected 62, got -47110784
valNullable: expected 9297555, got nil
Object Collection test_string
OBJECT COUNT ERROR: expected 2, got 1
Object key=š℠¼々¢~;-Ⱥ!˃a[ʰᾌ?{ᪧ৵%ᾯ¦〈: NOT FOUND
Object Collection test_time
Object Collection test_int32
OBJECT COUNT ERROR: expected 1, got 0
Object key=-148250689: NOT FOUND
Object Collection test_int64
OBJECT COUNT ERROR: expected 4, got 3
Object key=1969-12-31 19:00:00.000000005 -0500 EST: NOT FOUND
Object key=1086011412347477: NOT FOUND
Object key=881248243728748743
valNotNull: expected 1, got -154
valNullable: expected 363352528, got nil
Object Collection test_int8
Object key=53
valNotNull: expected -7, got 58
valNullable: expected 15, got -10
Object Collection test_integer
OBJECT COUNT ERROR: expected 4, got 3
Object key=12
valNotNull: expected -3, got 101
Object key=4: NOT FOUND
Object Collection test_string
Object key=
#[Dž¦&?=: NOT FOUND
Object Collection test_time
Object key=1969-12-31 19:00:00.001598687 -0500 EST
valNotNull: expected 1969-12-31 19:00:00.007727197 -0500 EST, got 1969-12-31 19:00:00.034531678 -0500 EST
valNullable: expected 1969-12-31 19:00:00.000000484 -0500 EST, got 1969-12-31 19:00:00.000000033 -0500 EST
valNullable: expected nil, got 1969-12-31 19:00:00.000000033 -0500 EST
Object Collection test_uint16
OBJECT COUNT ERROR: expected 4, got 3
Object key=23712: NOT FOUND
Object key=1478: NOT FOUND
Object Collection test_uint32
OBJECT COUNT ERROR: expected 3, got 2
Object key=0: NOT FOUND
Object key=0
valNotNull: expected 1, got 26
valNullable: expected 321283034, got 2
Object key=23067: NOT FOUND
Object Collection test_uint64
OBJECT COUNT ERROR: expected 1, got 2
Object Collection test_uint8
OBJECT COUNT ERROR: expected 3, got 2
OBJECT COUNT ERROR: expected 2, got 0
Object key=1: NOT FOUND
Object key=50508131: NOT FOUND
Object Collection test_uint8
OBJECT COUNT ERROR: expected 2, got 1
Object key=119
valNotNull: expected 6, got 30
valNullable: expected nil, got 7
Object key=72: NOT FOUND
Module test_cases: actual module NOT FOUND
BlockNum: expected 2, got 1

View File

@ -152,6 +152,9 @@ func mkTestObjectType(kind schema.Kind) schema.ObjectType {
keyField := field
keyField.Name = "key"
if !kind.ValidKeyKind() {
keyField.Kind = schema.Int32Kind
}
val1Field := field
val1Field.Name = "valNotNull"
val2Field := field

View File

@ -35,6 +35,11 @@ var FieldGen = rapid.Custom(func(t *rapid.T) schema.Field {
return field
})
// KeyFieldGen generates random key fields based on the validity criteria of key fields.
var KeyFieldGen = FieldGen.Filter(func(f schema.Field) bool {
return !f.Nullable && f.Kind.ValidKeyKind()
})
// FieldValueGen generates random valid values for the field, aiming to exercise the full range of possible
// values for the field.
func FieldValueGen(field schema.Field) *rapid.Generator[any] {
@ -128,9 +133,8 @@ func ObjectKeyGen(keyFields []schema.Field) *rapid.Generator[any] {
// Values that are for update may skip some fields in a ValueUpdates instance whereas values for insertion
// will always contain all values.
func ObjectValueGen(valueFields []schema.Field, forUpdate bool) *rapid.Generator[any] {
// special case where there are no value fields
// we shouldn't end up here, but just in case
if len(valueFields) == 0 {
// if we have no value fields, always return nil
return rapid.Just[any](nil)
}

53
schema/testing/fmt.go Normal file
View File

@ -0,0 +1,53 @@
package schematesting
import (
"fmt"
"github.com/cockroachdb/apd/v3"
"cosmossdk.io/schema"
)
// ObjectKeyString formats the object key as a string deterministically for storage in a map.
// The key must be valid for the object type and the object type must be valid.
// No validation is performed here.
func ObjectKeyString(objectType schema.ObjectType, key any) string {
keyFields := objectType.KeyFields
n := len(keyFields)
switch n {
case 0:
return ""
case 1:
valStr := fmtValue(keyFields[0].Kind, key)
return fmt.Sprintf("%s=%v", keyFields[0].Name, valStr)
default:
ks := key.([]interface{})
res := ""
for i := 0; i < n; i++ {
if i != 0 {
res += ", "
}
valStr := fmtValue(keyFields[i].Kind, ks[i])
res += fmt.Sprintf("%s=%v", keyFields[i].Name, valStr)
}
return res
}
}
func fmtValue(kind schema.Kind, value any) string {
switch kind {
case schema.BytesKind, schema.AddressKind:
return fmt.Sprintf("0x%x", value)
case schema.DecimalStringKind, schema.IntegerStringKind:
// we need to normalize decimal & integer strings to remove leading & trailing zeros
d, _, err := apd.NewFromString(value.(string))
if err != nil {
panic(err)
}
r := &apd.Decimal{}
r, _ = r.Reduce(d)
return r.String()
default:
return fmt.Sprintf("%v", value)
}
}

View File

@ -0,0 +1,61 @@
package schematesting
import (
"testing"
"cosmossdk.io/schema"
)
func TestObjectKeyString(t *testing.T) {
tt := []struct {
objectType schema.ObjectType
key any
expected string
}{
{
objectType: schema.ObjectType{
Name: "Singleton",
ValueFields: []schema.Field{
{Name: "Value", Kind: schema.StringKind},
},
},
key: nil,
expected: "",
},
{
objectType: schema.ObjectType{
Name: "Simple",
KeyFields: []schema.Field{{Name: "Key", Kind: schema.StringKind}},
},
key: "key",
expected: "Key=key",
},
{
objectType: schema.ObjectType{
Name: "BytesAddressDecInt",
KeyFields: []schema.Field{
{Name: "Bz", Kind: schema.BytesKind},
{Name: "Addr", Kind: schema.AddressKind},
{Name: "Dec", Kind: schema.DecimalStringKind},
{Name: "Int", Kind: schema.IntegerStringKind},
},
},
key: []interface{}{
[]byte{0x01, 0x02},
[]byte{0x03, 0x04},
"123.4560000", // trailing zeros should get removed
"0000012345678900000000000", // leading zeros should get removed and this should be in exponential form
},
expected: "Bz=0x0102, Addr=0x0304, Dec=123.456, Int=1.23456789E+19",
},
}
for _, tc := range tt {
t.Run(tc.objectType.Name, func(t *testing.T) {
actual := ObjectKeyString(tc.objectType, tc.key)
if actual != tc.expected {
t.Errorf("expected %s, got %s", tc.expected, actual)
}
})
}
}

View File

@ -29,7 +29,7 @@ var objectTypesGen = rapid.Custom(func(t *rapid.T) []schema.ObjectType {
}).Filter(func(objectTypes []schema.ObjectType) bool {
typeNames := map[string]bool{}
for _, objectType := range objectTypes {
if hasDuplicateNames(typeNames, objectType.KeyFields) || hasDuplicateNames(typeNames, objectType.ValueFields) {
if hasDuplicateTypeNames(typeNames, objectType.KeyFields) || hasDuplicateTypeNames(typeNames, objectType.ValueFields) {
return false
}
if typeNames[objectType.Name] {
@ -43,9 +43,9 @@ var objectTypesGen = rapid.Custom(func(t *rapid.T) []schema.ObjectType {
// MustNewModuleSchema calls NewModuleSchema and panics if there's an error. This should generally be used
// only in tests or initialization code.
func MustNewModuleSchema(objectTypes []schema.ObjectType) schema.ModuleSchema {
schema, err := schema.NewModuleSchema(objectTypes)
sch, err := schema.NewModuleSchema(objectTypes)
if err != nil {
panic(err)
}
return schema
return sch
}

View File

@ -7,7 +7,11 @@ import (
"cosmossdk.io/schema"
)
var fieldsGen = rapid.SliceOfNDistinct(FieldGen, 1, 12, func(f schema.Field) string {
var keyFieldsGen = rapid.SliceOfNDistinct(KeyFieldGen, 1, 6, func(f schema.Field) string {
return f.Name
})
var valueFieldsGen = rapid.SliceOfNDistinct(FieldGen, 1, 12, func(f schema.Field) string {
return f.Name
})
@ -17,35 +21,44 @@ var ObjectTypeGen = rapid.Custom(func(t *rapid.T) schema.ObjectType {
Name: NameGen.Draw(t, "name"),
}
fields := fieldsGen.Draw(t, "fields")
numKeyFields := rapid.IntRange(0, len(fields)).Draw(t, "numKeyFields")
typ.KeyFields = fields[:numKeyFields]
for i := range typ.KeyFields {
// key fields can't be nullable
typ.KeyFields[i].Nullable = false
}
typ.ValueFields = fields[numKeyFields:]
typ.KeyFields = keyFieldsGen.Draw(t, "keyFields")
typ.ValueFields = valueFieldsGen.Draw(t, "valueFields")
typ.RetainDeletions = boolGen.Draw(t, "retainDeletions")
return typ
}).Filter(func(typ schema.ObjectType) bool {
// filter out duplicate enum names
typeNames := map[string]bool{typ.Name: true}
if hasDuplicateNames(typeNames, typ.KeyFields) {
// filter out duplicate field names
fieldNames := map[string]bool{}
if hasDuplicateFieldNames(fieldNames, typ.KeyFields) {
return false
}
if hasDuplicateNames(typeNames, typ.ValueFields) {
if hasDuplicateFieldNames(fieldNames, typ.ValueFields) {
return false
}
// filter out duplicate type names
typeNames := map[string]bool{typ.Name: true}
if hasDuplicateTypeNames(typeNames, typ.KeyFields) {
return false
}
if hasDuplicateTypeNames(typeNames, typ.ValueFields) {
return false
}
return true
})
// hasDuplicateNames checks if there is type name in the fields
func hasDuplicateNames(typeNames map[string]bool, fields []schema.Field) bool {
func hasDuplicateFieldNames(typeNames map[string]bool, fields []schema.Field) bool {
for _, field := range fields {
if _, ok := typeNames[field.Name]; ok {
return true
}
typeNames[field.Name] = true
}
return false
}
// hasDuplicateTypeNames checks if there is type name in the fields
func hasDuplicateTypeNames(typeNames map[string]bool, fields []schema.Field) bool {
for _, field := range fields {
if field.Kind != schema.EnumKind {
continue
@ -68,60 +81,41 @@ func ObjectInsertGen(objectType schema.ObjectType) *rapid.Generator[schema.Objec
// ObjectUpdateGen generates object updates that are valid for updates using the provided state map as a source
// of valid existing keys.
func ObjectUpdateGen(objectType schema.ObjectType, state *btree.Map[string, schema.ObjectUpdate]) *rapid.Generator[schema.ObjectUpdate] {
keyGen := ObjectKeyGen(objectType.KeyFields)
keyGen := ObjectKeyGen(objectType.KeyFields).Filter(func(key interface{}) bool {
// filter out keys that exist in the state
if state != nil {
_, exists := state.Get(ObjectKeyString(objectType, key))
return !exists
}
return true
})
insertValueGen := ObjectValueGen(objectType.ValueFields, false)
updateValueGen := ObjectValueGen(objectType.ValueFields, true)
return rapid.Custom(func(t *rapid.T) schema.ObjectUpdate {
update := schema.ObjectUpdate{
TypeName: objectType.Name,
}
if len(objectType.ValueFields) == 0 {
// special case where there are no value fields,
// so we just insert or delete, no updates
return rapid.Custom(func(t *rapid.T) schema.ObjectUpdate {
update := schema.ObjectUpdate{
TypeName: objectType.Name,
}
// 50% of the time use existing key (when there are keys)
n := 0
if state != nil {
n = state.Len()
}
if n > 0 && boolGen.Draw(t, "existingKey") {
i := rapid.IntRange(0, n-1).Draw(t, "index")
update.Key = state.Values()[i].Key
// 50% of the time delete existing key (when there are keys)
n := 0
if state != nil {
n = state.Len()
}
if n > 0 && boolGen.Draw(t, "delete") {
i := rapid.IntRange(0, n-1).Draw(t, "index")
update.Key = state.Values()[i].Key
// delete 50% of the time
if boolGen.Draw(t, "delete") {
update.Delete = true
} else {
update.Key = keyGen.Draw(t, "key")
update.Value = updateValueGen.Draw(t, "value")
}
} else {
update.Key = keyGen.Draw(t, "key")
update.Value = insertValueGen.Draw(t, "value")
}
return update
})
} else {
insertValueGen := ObjectValueGen(objectType.ValueFields, false)
updateValueGen := ObjectValueGen(objectType.ValueFields, true)
return rapid.Custom(func(t *rapid.T) schema.ObjectUpdate {
update := schema.ObjectUpdate{
TypeName: objectType.Name,
}
// 50% of the time use existing key (when there are keys)
n := 0
if state != nil {
n = state.Len()
}
if n > 0 && boolGen.Draw(t, "existingKey") {
i := rapid.IntRange(0, n-1).Draw(t, "index")
update.Key = state.Values()[i].Key
// delete 50% of the time
if boolGen.Draw(t, "delete") {
update.Delete = true
} else {
update.Value = updateValueGen.Draw(t, "value")
}
} else {
update.Key = keyGen.Draw(t, "key")
update.Value = insertValueGen.Draw(t, "value")
}
return update
})
}
return update
})
}

View File

@ -48,7 +48,7 @@ func (o *ObjectCollection) ApplyUpdate(update schema.ObjectUpdate) error {
return err
}
keyStr := fmtObjectKey(o.objectType, update.Key)
keyStr := schematesting.ObjectKeyString(o.objectType, update.Key)
cur, exists := o.objects.Get(keyStr)
if update.Delete {
if o.objectType.RetainDeletions && o.options.CanRetainDeletions {
@ -119,7 +119,7 @@ func (o *ObjectCollection) AllState(f func(schema.ObjectUpdate, error) bool) {
// GetObject returns the object with the given key from the collection represented as an ObjectUpdate
// itself. Deletions that are retained are returned as ObjectUpdate's with delete set to true.
func (o *ObjectCollection) GetObject(key interface{}) (update schema.ObjectUpdate, found bool, err error) {
update, ok := o.objects.Get(fmtObjectKey(o.objectType, key))
update, ok := o.objects.Get(schematesting.ObjectKeyString(o.objectType, key))
return update, ok, nil
}
@ -132,37 +132,3 @@ func (o *ObjectCollection) ObjectType() schema.ObjectType {
func (o *ObjectCollection) Len() (int, error) {
return o.objects.Len(), nil
}
func fmtObjectKey(objectType schema.ObjectType, key any) string {
keyFields := objectType.KeyFields
n := len(keyFields)
switch n {
case 0:
return ""
case 1:
valStr := fmtValue(keyFields[0].Kind, key)
return fmt.Sprintf("%s=%v", keyFields[0].Name, valStr)
default:
ks := key.([]interface{})
res := ""
for i := 0; i < n; i++ {
if i != 0 {
res += ", "
}
valStr := fmtValue(keyFields[i].Kind, ks[i])
res += fmt.Sprintf("%s=%v", keyFields[i].Name, valStr)
}
return res
}
}
func fmtValue(kind schema.Kind, value any) string {
switch kind {
case schema.BytesKind, schema.AddressKind:
return fmt.Sprintf("0x%x", value)
case schema.JSONKind:
return fmt.Sprintf("%s", value)
default:
return fmt.Sprintf("%v", value)
}
}

View File

@ -35,7 +35,7 @@ func DiffObjectCollections(expected, actual view.ObjectCollection) string {
continue
}
keyStr := fmtObjectKey(expected.ObjectType(), expectedUpdate.Key)
keyStr := schematesting.ObjectKeyString(expected.ObjectType(), expectedUpdate.Key)
actualUpdate, found, err := actual.GetObject(expectedUpdate.Key)
if err != nil {
res += fmt.Sprintf("Object %s: ERROR: %v\n", keyStr, err)