From 3e77c8402672807bab068a1c5b094a965aaffde7 Mon Sep 17 00:00:00 2001 From: pk910 Date: Sat, 30 Mar 2024 02:32:42 +0100 Subject: [PATCH 01/18] implemented dynamic ssz parser --- spec/deneb/beaconstate.go | 4 +- ssz/debug.go | 7 + ssz/dynssz.go | 17 ++ ssz/sszsize.go | 160 ++++++++++++++++++ ssz/test/main.go | 88 ++++++++++ ssz/unmarshal.go | 329 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 603 insertions(+), 2 deletions(-) create mode 100644 ssz/debug.go create mode 100644 ssz/dynssz.go create mode 100644 ssz/sszsize.go create mode 100644 ssz/test/main.go create mode 100644 ssz/unmarshal.go diff --git a/spec/deneb/beaconstate.go b/spec/deneb/beaconstate.go index 39d86c24..6b8163ef 100644 --- a/spec/deneb/beaconstate.go +++ b/spec/deneb/beaconstate.go @@ -30,8 +30,8 @@ type BeaconState struct { Slot phase0.Slot Fork *phase0.Fork LatestBlockHeader *phase0.BeaconBlockHeader - BlockRoots []phase0.Root `ssz-size:"8192,32"` - StateRoots []phase0.Root `ssz-size:"8192,32"` + BlockRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` + StateRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32"` ETH1Data *phase0.ETH1Data ETH1DataVotes []*phase0.ETH1Data `ssz-max:"2048"` diff --git a/ssz/debug.go b/ssz/debug.go new file mode 100644 index 00000000..f00d1130 --- /dev/null +++ b/ssz/debug.go @@ -0,0 +1,7 @@ +package ssz + +import "strings" + +func indent(c int) string { + return strings.Repeat(" ", c) +} diff --git a/ssz/dynssz.go b/ssz/dynssz.go new file mode 100644 index 00000000..5755b597 --- /dev/null +++ b/ssz/dynssz.go @@ -0,0 +1,17 @@ +package ssz + +import "reflect" + +type DynSsz struct { + typesWithSpecVals map[reflect.Type]uint8 + SpecValues map[string]any +} + +func NewDynSsz() *DynSsz { + return &DynSsz{ + typesWithSpecVals: map[reflect.Type]uint8{}, + SpecValues: map[string]any{ + "SLOTS_PER_HISTORICAL_ROOT": uint64(8192), + }, + } +} diff --git a/ssz/sszsize.go b/ssz/sszsize.go new file mode 100644 index 00000000..f63d2c55 --- /dev/null +++ b/ssz/sszsize.go @@ -0,0 +1,160 @@ +package ssz + +import ( + "fmt" + "reflect" + "strconv" + "strings" +) + +type sszSizeHint struct { + size uint64 + dynamic bool + specval bool +} + +func (d *DynSsz) getSszSizeTag(field *reflect.StructField) ([]sszSizeHint, error) { + sszSizes := []sszSizeHint{} + + fieldDynSszSizeStr, fieldHasDynSszSize := field.Tag.Lookup("dynssz-size") + if fieldHasDynSszSize { + for _, sszSizeStr := range strings.Split(fieldDynSszSizeStr, ",") { + sszSize := sszSizeHint{} + + if sszSizeStr == "?" { + sszSize.dynamic = true + } else if sszSizeInt, err := strconv.ParseUint(sszSizeStr, 10, 32); err == nil { + sszSize.size = sszSizeInt + } else if specVal := d.SpecValues[sszSizeStr]; specVal != nil { + // dynamic value from spec + specInt, ok := specVal.(uint64) + if !ok { + return sszSizes, fmt.Errorf("error parsing dynssz-size tag for '%v' field: %v spec value is not uint64", field.Name, sszSizeStr) + } + sszSize.size = specInt + sszSize.specval = true + } else { + // unknown spec value? fallback to fastssz + fieldHasDynSszSize = false + break + } + + sszSizes = append(sszSizes, sszSize) + } + } + + if !fieldHasDynSszSize { + if fieldSszSizeStr, fieldHasSszSize := field.Tag.Lookup("ssz-size"); fieldHasSszSize { + for _, sszSizeStr := range strings.Split(fieldSszSizeStr, ",") { + sszSize := sszSizeHint{} + + if sszSizeStr == "?" { + sszSize.dynamic = true + } else { + sszSizeInt, err := strconv.ParseUint(sszSizeStr, 10, 32) + if err != nil { + return sszSizes, fmt.Errorf("error parsing ssz-size tag for '%v' field: %v", field.Name, err) + } + sszSize.size = sszSizeInt + } + + sszSizes = append(sszSizes, sszSize) + } + } + } + + return sszSizes, nil +} + +func (d *DynSsz) getSszSize(targetType reflect.Type, sizeHints []sszSizeHint) (int, bool, error) { + staticSize := 0 + hasSpecValue := false + isDynamicSize := false + + childSizeHints := []sszSizeHint{} + if len(sizeHints) > 1 { + childSizeHints = sizeHints[1:] + } + + if targetType.Kind() == reflect.Ptr { + targetType = targetType.Elem() + } + + switch targetType.Kind() { + case reflect.Struct: + for i := 0; i < targetType.NumField(); i++ { + field := targetType.Field(i) + size, hasSpecVal, _, err := d.getSszFieldSize(&field) + if err != nil { + return 0, false, err + } + if size < 0 { + isDynamicSize = true + } + if hasSpecVal { + hasSpecValue = true + } + staticSize += size + } + case reflect.Array: + arrLen := targetType.Len() + fieldType := targetType.Elem() + size, hasSpecVal, err := d.getSszSize(fieldType, childSizeHints) + if err != nil { + return 0, false, err + } + if size < 0 { + isDynamicSize = true + } + if hasSpecVal { + hasSpecValue = true + } + staticSize += size * arrLen + case reflect.Slice: + fieldType := targetType.Elem() + size, hasSpecVal, err := d.getSszSize(fieldType, childSizeHints) + if err != nil { + return 0, false, err + } + if size < 0 { + isDynamicSize = true + } + if hasSpecVal || (len(sizeHints) > 0 && sizeHints[0].specval) { + hasSpecValue = true + } + + if len(sizeHints) > 0 && sizeHints[0].size > 0 { + staticSize += size * int(sizeHints[0].size) + } else { + isDynamicSize = true + } + case reflect.Bool: + staticSize = 1 + case reflect.Uint8: + staticSize = 1 + case reflect.Uint16: + staticSize = 2 + case reflect.Uint32: + staticSize = 4 + case reflect.Uint64: + staticSize = 8 + default: + return 0, false, fmt.Errorf("unhandled reflection kind in size check: %v", targetType.Kind()) + } + + if isDynamicSize { + staticSize = -1 + } + + return staticSize, hasSpecValue, nil +} + +func (d *DynSsz) getSszFieldSize(targetField *reflect.StructField) (int, bool, []sszSizeHint, error) { + sszSizes, err := d.getSszSizeTag(targetField) + if err != nil { + return 0, false, nil, err + } + + size, hasSpecVal, err := d.getSszSize(targetField.Type, sszSizes) + return size, hasSpecVal, sszSizes, err +} diff --git a/ssz/test/main.go b/ssz/test/main.go new file mode 100644 index 00000000..e0b52469 --- /dev/null +++ b/ssz/test/main.go @@ -0,0 +1,88 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + "runtime" + "runtime/pprof" + "time" + + "github.com/attestantio/go-eth2-client/spec/deneb" + "github.com/attestantio/go-eth2-client/ssz" + + _ "net/http/pprof" +) + +func main() { + body, _ := ioutil.ReadFile("state2.ssz") + + test1(body) + test2(body) + + f, _ := os.Create("mem.pprof") + pprof.WriteHeapProfile(f) + f.Close() +} + +func printMemUsage() { + var m runtime.MemStats + runtime.ReadMemStats(&m) + // For info on each, see: https://golang.org/pkg/runtime/#MemStats + fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc)) + fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc)) + fmt.Printf("\tSys = %v MiB", bToMb(m.Sys)) + fmt.Printf("\tNumGC = %v\n", m.NumGC) +} + +func bToMb(b uint64) uint64 { + return b / 1024 / 1024 +} + +func test1(body []byte) { + start := time.Now() + defer func() { + elapsed := time.Since(start) + fmt.Printf("unmarshal time: %v\n", elapsed) + }() + + fmt.Printf("\nfastssz / go-eth2-client\n") + + t := new(deneb.BeaconState) + err := t.UnmarshalSSZ(body) + if err != nil { + fmt.Printf("error: %v\n", err) + return + } + + runtime.GC() + printMemUsage() + + //root, _ := t.HashTreeRoot() + //fmt.Printf("state root: 0x%x\n", root) + fmt.Printf("gvr: 0x%x\n", t.GenesisValidatorsRoot) +} + +func test2(body []byte) { + start := time.Now() + defer func() { + elapsed := time.Since(start) + fmt.Printf("unmarshal time: %v\n", elapsed) + }() + + fmt.Printf("\npk's dynamic ssz\n") + + t := new(deneb.BeaconState) + err := ssz.UnmarshalSSZ(t, body) + if err != nil { + fmt.Printf("error: %v\n", err) + return + } + + runtime.GC() + printMemUsage() + + //root, _ := t.HashTreeRoot() + //fmt.Printf("state root: 0x%x\n", root) + fmt.Printf("gvr: 0x%x\n", t.GenesisValidatorsRoot) +} diff --git a/ssz/unmarshal.go b/ssz/unmarshal.go new file mode 100644 index 00000000..23b34cb5 --- /dev/null +++ b/ssz/unmarshal.go @@ -0,0 +1,329 @@ +package ssz + +import ( + "fmt" + "reflect" + + fastssz "github.com/ferranbt/fastssz" +) + +var byteType = reflect.TypeOf(byte(0)) +var sszUnmarshallerType = reflect.TypeOf((*fastssz.Unmarshaler)(nil)).Elem() + +func UnmarshalSSZ(target any, ssz []byte) error { + d := NewDynSsz() + + targetType := reflect.TypeOf(target) + targetValue := reflect.ValueOf(target) + + consumedBytes, err := d.unmarshalType(targetType, targetValue, ssz, []sszSizeHint{}, 0) + if err != nil { + return err + } + + if consumedBytes != len(ssz) { + return fmt.Errorf("did not consume full ssz range (consumed: %v, ssz size: %v)", consumedBytes, len(ssz)) + } + + return nil +} + +func (d *DynSsz) unmarshalType(targetType reflect.Type, targetValue reflect.Value, ssz []byte, sizeHints []sszSizeHint, idt int) (int, error) { + consumedBytes := 0 + + if targetType.Kind() == reflect.Ptr { + targetType = targetType.Elem() + if targetValue.IsNil() { + //fmt.Printf("new type %v\n", targetType.Name()) + newValue := reflect.New(targetType) + targetValue.Set(newValue) + } + targetValue = targetValue.Elem() + } + + //fmt.Printf("%stype: %s\t kind: %v\n", indent(idt), targetType.Name(), targetType.Kind()) + + switch targetType.Kind() { + case reflect.Struct: + usedFastSsz := false + + hasSpecVals := d.typesWithSpecVals[targetType] + if hasSpecVals == 0 { + // shortcut for performance: use fastssz unmarshaller if available + if targetValue.Addr().Type().Implements(sszUnmarshallerType) { + _, hasSpecValues, err := d.getSszSize(targetType, sizeHints) + if err != nil { + return 0, err + } + + if hasSpecValues { + hasSpecVals = 2 + } else { + hasSpecVals = 1 + } + d.typesWithSpecVals[targetType] = hasSpecVals + } + } + if hasSpecVals == 1 { + unmarshaller, ok := targetValue.Addr().Interface().(fastssz.Unmarshaler) + if ok { + //fmt.Printf("%s use fastssz for type: %s\n", indent(idt), targetType.Name()) + err := unmarshaller.UnmarshalSSZ(ssz) + if err != nil { + return 0, err + } + consumedBytes = len(ssz) + usedFastSsz = true + } + } + + if !usedFastSsz { + consumed, err := d.unmarshalStruct(targetType, targetValue, ssz, idt) + if err != nil { + return 0, err + } + consumedBytes = consumed + } + case reflect.Array: + consumed, err := d.unmarshalArray(targetType, targetValue, ssz, sizeHints, idt) + if err != nil { + return 0, err + } + consumedBytes = consumed + case reflect.Slice: + consumed, err := d.unmarshalSlice(targetType, targetValue, ssz, sizeHints, idt) + if err != nil { + return 0, err + } + consumedBytes = consumed + case reflect.Bool: + targetValue.SetBool(fastssz.UnmarshalBool(ssz)) + consumedBytes = 1 + case reflect.Uint8: + targetValue.SetUint(uint64(fastssz.UnmarshallUint8(ssz))) + consumedBytes = 1 + case reflect.Uint16: + targetValue.SetUint(uint64(fastssz.UnmarshallUint16(ssz))) + consumedBytes = 2 + case reflect.Uint32: + targetValue.SetUint(uint64(fastssz.UnmarshallUint32(ssz))) + consumedBytes = 4 + case reflect.Uint64: + targetValue.SetUint(uint64(fastssz.UnmarshallUint64(ssz))) + consumedBytes = 8 + default: + return 0, fmt.Errorf("unknown type: %v", targetType) + } + + return consumedBytes, nil +} + +func (d *DynSsz) unmarshalStruct(targetType reflect.Type, targetValue reflect.Value, ssz []byte, idt int) (int, error) { + offset := 0 + dynamicFields := []*reflect.StructField{} + dynamicOffsets := []int{} + dynamicSizeHints := [][]sszSizeHint{} + + for i := 0; i < targetType.NumField(); i++ { + field := targetType.Field(i) + + fieldSize, _, sizeHints, err := d.getSszFieldSize(&field) + if err != nil { + return 0, err + } + + if fieldSize > 0 { + //fmt.Printf("%sfield %d:\t static [%v:%v] %v\t %v\n", indent(idt+1), i, offset, offset+fieldSize, fieldSize, field.Name) + + fieldSsz := ssz[offset : offset+fieldSize] + fieldValue := targetValue.Field(i) + consumedBytes, err := d.unmarshalType(field.Type, fieldValue, fieldSsz, sizeHints, idt+2) + if err != nil { + return 0, fmt.Errorf("failed decoding field %v: %v", field.Name, err) + } + if consumedBytes != fieldSize { + return 0, fmt.Errorf("struct field did not consume expected ssz range (consumed: %v, expected: %v)", consumedBytes, fieldSize) + } + + } else { + fieldSize = 4 + fieldOffset := fastssz.ReadOffset(ssz[offset : offset+fieldSize]) + //fmt.Printf("%sfield %d:\t offset [%v:%v] %v\t %v \t %v\n", indent(idt+1), i, offset, offset+fieldSize, fieldSize, field.Name, fieldOffset) + + dynamicFields = append(dynamicFields, &field) + dynamicOffsets = append(dynamicOffsets, int(fieldOffset)) + dynamicSizeHints = append(dynamicSizeHints, sizeHints) + } + offset += fieldSize + } + dynamicFieldCount := len(dynamicFields) + for i, field := range dynamicFields { + var endOffset int + startOffset := dynamicOffsets[i] + if i < dynamicFieldCount-1 { + endOffset = dynamicOffsets[i+1] + } else { + endOffset = len(ssz) + } + + //fmt.Printf("%sfield %d:\t dynamic [%v:%v]\t %v\n", indent(idt+1), field.Index[0], startOffset, endOffset, field.Name) + + var fieldSsz []byte + if endOffset > startOffset { + fieldSsz = ssz[startOffset:endOffset] + } else { + fieldSsz = []byte{} + } + + fieldValue := targetValue.Field(field.Index[0]) + consumedBytes, err := d.unmarshalType(field.Type, fieldValue, fieldSsz, dynamicSizeHints[i], idt+2) + if err != nil { + return 0, fmt.Errorf("failed decoding field %v: %v", field.Name, err) + } + if consumedBytes != endOffset-startOffset { + return 0, fmt.Errorf("struct field did not consume expected ssz range (consumed: %v, expected: %v)", consumedBytes, endOffset-startOffset) + } + + offset += consumedBytes + } + + return offset, nil +} + +func (d *DynSsz) unmarshalArray(targetType reflect.Type, targetValue reflect.Value, ssz []byte, sizeHints []sszSizeHint, idt int) (int, error) { + var consumedBytes int + + childSizeHints := []sszSizeHint{} + if len(sizeHints) > 1 { + childSizeHints = sizeHints[1:] + } + + fieldType := targetType.Elem() + fieldIsPtr := fieldType.Kind() == reflect.Ptr + if fieldIsPtr { + fieldType = fieldType.Elem() + } + + arrLen := targetType.Len() + if fieldType == byteType { + // shortcut for performance: use copy on []byte arrays + reflect.Copy(targetValue, reflect.ValueOf(ssz[0:arrLen])) + consumedBytes = arrLen + } else { + offset := 0 + itemSize := len(ssz) / arrLen + for i := 0; i < arrLen; i++ { + var itemVal reflect.Value + if fieldIsPtr { + //fmt.Printf("new array item %v\n", fieldType.Name()) + itemVal = reflect.New(fieldType).Elem() + targetValue.Index(i).Set(itemVal.Addr()) + } else { + itemVal = targetValue.Index(i) + } + + itemSsz := ssz[offset : offset+itemSize] + + consumed, err := d.unmarshalType(fieldType, itemVal, itemSsz, childSizeHints, idt+2) + if err != nil { + return 0, err + } + if consumed != itemSize { + return 0, fmt.Errorf("unmarshalling array item did not consume expected ssz range (consumed: %v, expected: %v)", consumed, itemSize) + } + + offset += itemSize + } + + consumedBytes = offset + } + + return consumedBytes, nil +} + +func (d *DynSsz) unmarshalSlice(targetType reflect.Type, targetValue reflect.Value, ssz []byte, sizeHints []sszSizeHint, idt int) (int, error) { + var consumedBytes int + + childSizeHints := []sszSizeHint{} + if len(sizeHints) > 1 { + childSizeHints = sizeHints[1:] + } + + fieldType := targetType.Elem() + fieldIsPtr := fieldType.Kind() == reflect.Ptr + if fieldIsPtr { + fieldType = fieldType.Elem() + } + + sliceLen := 0 + sszLen := len(ssz) + + if len(sizeHints) > 0 && sizeHints[0].size > 0 { + sliceLen = int(sizeHints[0].size) + } else if len(sizeHints) > 1 && sizeHints[1].size > 0 { + ok := false + sliceLen, ok = fastssz.DivideInt(sszLen, int(sizeHints[1].size)) + if !ok { + return 0, fmt.Errorf("invalid slice length, expected multiple of %v, got %v", sizeHints[1], sszLen) + } + } else { + size, _, err := d.getSszSize(fieldType, childSizeHints) + if err != nil { + return 0, err + } + + if size > 0 { + ok := false + sliceLen, ok = fastssz.DivideInt(sszLen, size) + if !ok { + return 0, fmt.Errorf("invalid slice length, expected multiple of %v, got %v", size, sszLen) + } + } + } + + if sliceLen == 0 && len(ssz) > 0 { + return 0, fmt.Errorf("cannot deteriminate length of dynamic slice") + } + + //fmt.Printf("new slice %v %v\n", fieldType.Name(), sliceLen) + newValue := reflect.MakeSlice(targetType, sliceLen, sliceLen) + targetValue.Set(newValue) + + if fieldType == byteType { + // shortcut for performance: use copy on []byte arrays + reflect.Copy(newValue, reflect.ValueOf(ssz[0:sliceLen])) + consumedBytes = sliceLen + } else { + offset := 0 + if sliceLen > 0 { + itemSize := sszLen / sliceLen + + for i := 0; i < sliceLen; i++ { + var itemVal reflect.Value + if fieldIsPtr { + //fmt.Printf("new slice item %v\n", fieldType.Name()) + itemVal = reflect.New(fieldType).Elem() + newValue.Index(i).Set(itemVal.Addr()) + } else { + itemVal = newValue.Index(i) + } + + itemSsz := ssz[offset : offset+itemSize] + + consumed, err := d.unmarshalType(fieldType, itemVal, itemSsz, childSizeHints, idt+2) + if err != nil { + return 0, err + } + if consumed != itemSize { + return 0, fmt.Errorf("slice item did not consume expected ssz range (consumed: %v, expected: %v)", consumed, itemSize) + } + + offset += itemSize + } + } + + consumedBytes = offset + } + + return consumedBytes, nil +} From b7b8ef116f2d86babf39292c76a79c97d7d3b191 Mon Sep 17 00:00:00 2001 From: pk910 Date: Sat, 30 Mar 2024 04:58:12 +0100 Subject: [PATCH 02/18] added dynamic serializer --- spec/altair/beaconstate.go | 10 +- spec/altair/syncaggregate.go | 2 +- spec/altair/synccommittee.go | 2 +- spec/altair/synccommitteecontribution.go | 2 +- spec/phase0/beaconstate.go | 10 +- spec/phase0/deposit.go | 2 +- ssz/const.go | 11 ++ ssz/dynssz.go | 11 +- ssz/marshal.go | 229 +++++++++++++++++++++++ ssz/test/main.go | 24 +++ ssz/unmarshal.go | 22 +-- 11 files changed, 296 insertions(+), 29 deletions(-) create mode 100644 ssz/const.go create mode 100644 ssz/marshal.go diff --git a/spec/altair/beaconstate.go b/spec/altair/beaconstate.go index 4063a841..548700f7 100644 --- a/spec/altair/beaconstate.go +++ b/spec/altair/beaconstate.go @@ -34,16 +34,16 @@ type BeaconState struct { Slot phase0.Slot Fork *phase0.Fork LatestBlockHeader *phase0.BeaconBlockHeader - BlockRoots []phase0.Root `ssz-size:"8192,32"` - StateRoots []phase0.Root `ssz-size:"8192,32"` - HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32"` + BlockRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` + StateRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` + HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32" dynssz-size:"?,HISTORICAL_ROOTS_LIMIT"` ETH1Data *phase0.ETH1Data ETH1DataVotes []*phase0.ETH1Data `ssz-max:"2048"` ETH1DepositIndex uint64 Validators []*phase0.Validator `ssz-max:"1099511627776"` Balances []phase0.Gwei `ssz-max:"1099511627776"` - RANDAOMixes []phase0.Root `ssz-size:"65536,32"` - Slashings []phase0.Gwei `ssz-size:"8192"` + RANDAOMixes []phase0.Root `ssz-size:"65536,32" dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32"` + Slashings []phase0.Gwei `ssz-size:"8192" dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR"` PreviousEpochParticipation []ParticipationFlags `ssz-max:"1099511627776"` CurrentEpochParticipation []ParticipationFlags `ssz-max:"1099511627776"` JustificationBits bitfield.Bitvector4 `ssz-size:"1"` diff --git a/spec/altair/syncaggregate.go b/spec/altair/syncaggregate.go index 2106fd9c..1250a7cb 100644 --- a/spec/altair/syncaggregate.go +++ b/spec/altair/syncaggregate.go @@ -28,7 +28,7 @@ import ( // SyncAggregate is the Ethereum 2 sync aggregate structure. type SyncAggregate struct { - SyncCommitteeBits bitfield.Bitvector512 `ssz-size:"64"` + SyncCommitteeBits bitfield.Bitvector512 `ssz-size:"64" dynssz-size:"SYNC_COMMITTEE_SIZE/8"` SyncCommitteeSignature phase0.BLSSignature `ssz-size:"96"` } diff --git a/spec/altair/synccommittee.go b/spec/altair/synccommittee.go index 011d7acb..a42a1620 100644 --- a/spec/altair/synccommittee.go +++ b/spec/altair/synccommittee.go @@ -30,7 +30,7 @@ var syncCommitteeSize = 512 // SyncCommittee is the Ethereum 2 sync committee structure. type SyncCommittee struct { - Pubkeys []phase0.BLSPubKey `ssz-size:"512,48"` + Pubkeys []phase0.BLSPubKey `ssz-size:"512,48" dynssz-size:"SYNC_COMMITTEE_SIZE,48"` AggregatePubkey phase0.BLSPubKey `ssz-size:"48"` } diff --git a/spec/altair/synccommitteecontribution.go b/spec/altair/synccommitteecontribution.go index 83c94a99..de833b95 100644 --- a/spec/altair/synccommitteecontribution.go +++ b/spec/altair/synccommitteecontribution.go @@ -33,7 +33,7 @@ type SyncCommitteeContribution struct { BeaconBlockRoot phase0.Root `ssz-size:"32"` SubcommitteeIndex uint64 // AggregationBits size is SYNC_COMMITTEE_SIZE // SYNC_COMMITTEE_SUBNET_COUNT - AggregationBits bitfield.Bitvector128 `ssz-size:"16"` + AggregationBits bitfield.Bitvector128 `ssz-size:"16" dynssz-size:"SYNC_COMMITTEE_SIZE/SYNC_COMMITTEE_SUBNET_COUNT"` Signature phase0.BLSSignature `ssz-size:"96"` } diff --git a/spec/phase0/beaconstate.go b/spec/phase0/beaconstate.go index 12cdbe1a..4d27be0a 100644 --- a/spec/phase0/beaconstate.go +++ b/spec/phase0/beaconstate.go @@ -33,16 +33,16 @@ type BeaconState struct { Slot Slot Fork *Fork LatestBlockHeader *BeaconBlockHeader - BlockRoots []Root `ssz-size:"8192,32"` - StateRoots []Root `ssz-size:"8192,32"` - HistoricalRoots []Root `ssz-max:"16777216" ssz-size:"?,32"` + BlockRoots []Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` + StateRoots []Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` + HistoricalRoots []Root `ssz-max:"16777216" ssz-size:"?,32" dynssz-size:"?,HISTORICAL_ROOTS_LIMIT"` ETH1Data *ETH1Data ETH1DataVotes []*ETH1Data `ssz-max:"2048"` ETH1DepositIndex uint64 Validators []*Validator `ssz-max:"1099511627776"` Balances []Gwei `ssz-max:"1099511627776"` - RANDAOMixes []Root `ssz-size:"65536,32"` - Slashings []Gwei `ssz-size:"8192"` + RANDAOMixes []Root `ssz-size:"65536,32" dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32"` + Slashings []Gwei `ssz-size:"8192" dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR"` PreviousEpochAttestations []*PendingAttestation `ssz-max:"4096"` CurrentEpochAttestations []*PendingAttestation `ssz-max:"4096"` JustificationBits bitfield.Bitvector4 `ssz-size:"1"` diff --git a/spec/phase0/deposit.go b/spec/phase0/deposit.go index f1bfc02f..a3f9ef1e 100644 --- a/spec/phase0/deposit.go +++ b/spec/phase0/deposit.go @@ -26,7 +26,7 @@ import ( // Deposit provides information about a deposit. type Deposit struct { - Proof [][]byte `ssz-size:"33,32"` + Proof [][]byte `ssz-size:"33,32" dynssz-size:"DEPOSIT_CONTRACT_TREE_DEPTH+1,32"` Data *DepositData } diff --git a/ssz/const.go b/ssz/const.go new file mode 100644 index 00000000..6161f9e5 --- /dev/null +++ b/ssz/const.go @@ -0,0 +1,11 @@ +package ssz + +import ( + "reflect" + + fastssz "github.com/ferranbt/fastssz" +) + +var byteType = reflect.TypeOf(byte(0)) +var sszMarshallerType = reflect.TypeOf((*fastssz.Marshaler)(nil)).Elem() +var sszUnmarshallerType = reflect.TypeOf((*fastssz.Unmarshaler)(nil)).Elem() diff --git a/ssz/dynssz.go b/ssz/dynssz.go index 5755b597..22c70eff 100644 --- a/ssz/dynssz.go +++ b/ssz/dynssz.go @@ -5,13 +5,20 @@ import "reflect" type DynSsz struct { typesWithSpecVals map[reflect.Type]uint8 SpecValues map[string]any + NoFastSsz bool } +const ( + unknownSpecValued uint8 = iota + noSpecValues + hasSpecValues +) + func NewDynSsz() *DynSsz { return &DynSsz{ typesWithSpecVals: map[reflect.Type]uint8{}, - SpecValues: map[string]any{ - "SLOTS_PER_HISTORICAL_ROOT": uint64(8192), + SpecValues: map[string]any{ + //"SLOTS_PER_HISTORICAL_ROOT": uint64(8192), }, } } diff --git a/ssz/marshal.go b/ssz/marshal.go new file mode 100644 index 00000000..9fada4e8 --- /dev/null +++ b/ssz/marshal.go @@ -0,0 +1,229 @@ +package ssz + +import ( + "encoding/binary" + "fmt" + "reflect" + + fastssz "github.com/ferranbt/fastssz" +) + +func MarshalSSZ(source any, buf []byte) ([]byte, error) { + d := NewDynSsz() + d.NoFastSsz = true + + sourceType := reflect.TypeOf(source) + sourceValue := reflect.ValueOf(source) + + newBuf, err := d.marshalType(sourceType, sourceValue, buf, []sszSizeHint{}, 0) + if err != nil { + return nil, err + } + + return newBuf, nil +} + +func (d *DynSsz) marshalType(sourceType reflect.Type, sourceValue reflect.Value, buf []byte, sizeHints []sszSizeHint, idt int) ([]byte, error) { + if sourceType.Kind() == reflect.Ptr { + sourceType = sourceType.Elem() + sourceValue = sourceValue.Elem() + } + + //fmt.Printf("%stype: %s\t kind: %v\n", indent(idt), sourceType.Name(), sourceType.Kind()) + + switch sourceType.Kind() { + case reflect.Struct: + usedFastSsz := false + + hasSpecVals := d.typesWithSpecVals[sourceType] + if hasSpecVals == unknownSpecValued && !d.NoFastSsz { + hasSpecVals = noSpecValues + if sourceValue.Addr().Type().Implements(sszMarshallerType) { + _, hasSpecVals2, err := d.getSszSize(sourceType, sizeHints) + if err != nil { + return nil, err + } + + if hasSpecVals2 { + hasSpecVals = hasSpecValues + } + } + + fmt.Printf("%s fastssz for type %s: %v\n", indent(idt), sourceType.Name(), hasSpecVals) + d.typesWithSpecVals[sourceType] = hasSpecVals + } + if hasSpecVals == noSpecValues && !d.NoFastSsz { + marshaller, ok := sourceValue.Addr().Interface().(fastssz.Marshaler) + if ok { + newBuf, err := marshaller.MarshalSSZTo(buf) + if err != nil { + return nil, err + } + buf = newBuf + usedFastSsz = true + } + } + + if !usedFastSsz { + newBuf, err := d.marshalStruct(sourceType, sourceValue, buf, idt) + if err != nil { + return nil, err + } + buf = newBuf + } + case reflect.Array: + newBuf, err := d.marshalArray(sourceType, sourceValue, buf, sizeHints, idt) + if err != nil { + return nil, err + } + buf = newBuf + case reflect.Slice: + newBuf, err := d.marshalSlice(sourceType, sourceValue, buf, sizeHints, idt) + if err != nil { + return nil, err + } + buf = newBuf + case reflect.Bool: + buf = fastssz.MarshalBool(buf, sourceValue.Bool()) + case reflect.Uint8: + buf = fastssz.MarshalUint8(buf, uint8(sourceValue.Uint())) + case reflect.Uint16: + buf = fastssz.MarshalUint16(buf, uint16(sourceValue.Uint())) + case reflect.Uint32: + buf = fastssz.MarshalUint32(buf, uint32(sourceValue.Uint())) + case reflect.Uint64: + buf = fastssz.MarshalUint64(buf, uint64(sourceValue.Uint())) + default: + return nil, fmt.Errorf("unknown type: %v", sourceType) + } + + return buf, nil +} + +func (d *DynSsz) marshalStruct(sourceType reflect.Type, sourceValue reflect.Value, buf []byte, idt int) ([]byte, error) { + offset := 0 + startLen := len(buf) + dynamicFields := []*reflect.StructField{} + dynamicOffsets := []int{} + dynamicSizeHints := [][]sszSizeHint{} + + for i := 0; i < sourceType.NumField(); i++ { + field := sourceType.Field(i) + + fieldSize, _, sizeHints, err := d.getSszFieldSize(&field) + if err != nil { + return nil, err + } + + if fieldSize > 0 { + //fmt.Printf("%sfield %d:\t static [%v:%v] %v\t %v\n", indent(idt+1), i, offset, offset+fieldSize, fieldSize, field.Name) + + fieldValue := sourceValue.Field(i) + newBuf, err := d.marshalType(field.Type, fieldValue, buf, sizeHints, idt+2) + if err != nil { + return nil, fmt.Errorf("failed encoding field %v: %v", field.Name, err) + } + buf = newBuf + + } else { + fieldSize = 4 + buf = append(buf, 0, 0, 0, 0) + //fmt.Printf("%sfield %d:\t offset [%v:%v] %v\t %v\n", indent(idt+1), i, offset, offset+fieldSize, fieldSize, field.Name) + + dynamicFields = append(dynamicFields, &field) + dynamicOffsets = append(dynamicOffsets, offset) + dynamicSizeHints = append(dynamicSizeHints, sizeHints) + } + offset += fieldSize + } + + for i, field := range dynamicFields { + // set field offset + fieldOffset := dynamicOffsets[i] + offsetBuf := make([]byte, 4) + binary.LittleEndian.PutUint32(offsetBuf, uint32(offset)) + copy(buf[fieldOffset+startLen:fieldOffset+startLen+4], offsetBuf) + + //fmt.Printf("%sfield %d:\t dynamic [%v:]\t %v\n", indent(idt+1), field.Index[0], offset, field.Name) + + fieldValue := sourceValue.Field(field.Index[0]) + bufLen := len(buf) + newBuf, err := d.marshalType(field.Type, fieldValue, buf, dynamicSizeHints[i], idt+2) + if err != nil { + return nil, fmt.Errorf("failed decoding field %v: %v", field.Name, err) + } + buf = newBuf + offset += len(buf) - bufLen + } + + return buf, nil +} + +func (d *DynSsz) marshalArray(sourceType reflect.Type, sourceValue reflect.Value, buf []byte, sizeHints []sszSizeHint, idt int) ([]byte, error) { + + childSizeHints := []sszSizeHint{} + if len(sizeHints) > 1 { + childSizeHints = sizeHints[1:] + } + + fieldType := sourceType.Elem() + fieldIsPtr := fieldType.Kind() == reflect.Ptr + if fieldIsPtr { + fieldType = fieldType.Elem() + } + + arrLen := sourceType.Len() + if fieldType == byteType { + // shortcut for performance: use append on []byte arrays + buf = append(buf, sourceValue.Bytes()...) + } else { + for i := 0; i < arrLen; i++ { + itemVal := sourceValue.Index(i) + if fieldIsPtr { + itemVal = itemVal.Elem() + } + + newBuf, err := d.marshalType(fieldType, itemVal, buf, childSizeHints, idt+2) + if err != nil { + return nil, err + } + buf = newBuf + } + } + + return buf, nil +} + +func (d *DynSsz) marshalSlice(sourceType reflect.Type, sourceValue reflect.Value, buf []byte, sizeHints []sszSizeHint, idt int) ([]byte, error) { + childSizeHints := []sszSizeHint{} + if len(sizeHints) > 1 { + childSizeHints = sizeHints[1:] + } + + fieldType := sourceType.Elem() + fieldIsPtr := fieldType.Kind() == reflect.Ptr + if fieldIsPtr { + fieldType = fieldType.Elem() + } + + sliceLen := sourceValue.Len() + if fieldType == byteType { + // shortcut for performance: use append on []byte arrays + buf = append(buf, sourceValue.Bytes()...) + } else { + for i := 0; i < sliceLen; i++ { + itemVal := sourceValue.Index(i) + if fieldIsPtr { + itemVal = itemVal.Elem() + } + + newBuf, err := d.marshalType(fieldType, itemVal, buf, childSizeHints, idt+2) + if err != nil { + return nil, err + } + buf = newBuf + } + } + + return buf, nil +} diff --git a/ssz/test/main.go b/ssz/test/main.go index e0b52469..562215b0 100644 --- a/ssz/test/main.go +++ b/ssz/test/main.go @@ -61,6 +61,12 @@ func test1(body []byte) { //root, _ := t.HashTreeRoot() //fmt.Printf("state root: 0x%x\n", root) fmt.Printf("gvr: 0x%x\n", t.GenesisValidatorsRoot) + + _, err = t.MarshalSSZ() + if err != nil { + fmt.Printf("error: %v\n", err) + return + } } func test2(body []byte) { @@ -85,4 +91,22 @@ func test2(body []byte) { //root, _ := t.HashTreeRoot() //fmt.Printf("state root: 0x%x\n", root) fmt.Printf("gvr: 0x%x\n", t.GenesisValidatorsRoot) + + _, err = ssz.MarshalSSZ(t, nil) + if err != nil { + fmt.Printf("error: %v\n", err) + return + } + + /* + if len(buf) != len(body) { + fmt.Printf("size mismatch: %v / %v\n", len(buf), len(body)) + } + for i := 0; i < len(body); i++ { + if body[i] != buf[i] { + fmt.Printf("ssz mismatch: %v : %v / %v\n", i, buf[i], body[i]) + break + } + } + */ } diff --git a/ssz/unmarshal.go b/ssz/unmarshal.go index 23b34cb5..dfa12f3f 100644 --- a/ssz/unmarshal.go +++ b/ssz/unmarshal.go @@ -7,9 +7,6 @@ import ( fastssz "github.com/ferranbt/fastssz" ) -var byteType = reflect.TypeOf(byte(0)) -var sszUnmarshallerType = reflect.TypeOf((*fastssz.Unmarshaler)(nil)).Elem() - func UnmarshalSSZ(target any, ssz []byte) error { d := NewDynSsz() @@ -48,26 +45,25 @@ func (d *DynSsz) unmarshalType(targetType reflect.Type, targetValue reflect.Valu usedFastSsz := false hasSpecVals := d.typesWithSpecVals[targetType] - if hasSpecVals == 0 { - // shortcut for performance: use fastssz unmarshaller if available + if hasSpecVals == unknownSpecValued { + hasSpecVals = noSpecValues if targetValue.Addr().Type().Implements(sszUnmarshallerType) { - _, hasSpecValues, err := d.getSszSize(targetType, sizeHints) + _, hasSpecVals2, err := d.getSszSize(targetType, sizeHints) if err != nil { return 0, err } - if hasSpecValues { - hasSpecVals = 2 - } else { - hasSpecVals = 1 + if hasSpecVals2 { + hasSpecVals = hasSpecValues } - d.typesWithSpecVals[targetType] = hasSpecVals } + + //fmt.Printf("%s fastssz for type %s: %v\n", indent(idt), targetType.Name(), hasSpecVals) + d.typesWithSpecVals[targetType] = hasSpecVals } - if hasSpecVals == 1 { + if hasSpecVals == noSpecValues { unmarshaller, ok := targetValue.Addr().Interface().(fastssz.Unmarshaler) if ok { - //fmt.Printf("%s use fastssz for type: %s\n", indent(idt), targetType.Name()) err := unmarshaller.UnmarshalSSZ(ssz) if err != nil { return 0, err From 0e54c95f02441046d42a854d805f90b58419a438 Mon Sep 17 00:00:00 2001 From: pk910 Date: Sat, 30 Mar 2024 06:19:23 +0100 Subject: [PATCH 03/18] added SizeSSZ & refactoring --- ssz/dynssz.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++- ssz/marshal.go | 17 +----------- ssz/sszsize.go | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ ssz/test/main.go | 2 +- ssz/unmarshal.go | 18 ------------- 5 files changed, 138 insertions(+), 36 deletions(-) diff --git a/ssz/dynssz.go b/ssz/dynssz.go index 22c70eff..a249c1c0 100644 --- a/ssz/dynssz.go +++ b/ssz/dynssz.go @@ -1,6 +1,9 @@ package ssz -import "reflect" +import ( + "fmt" + "reflect" +) type DynSsz struct { typesWithSpecVals map[reflect.Type]uint8 @@ -22,3 +25,66 @@ func NewDynSsz() *DynSsz { }, } } + +func MarshalSSZ(source any) ([]byte, error) { + d := NewDynSsz() + sourceType := reflect.TypeOf(source) + sourceValue := reflect.ValueOf(source) + + size, err := d.getSszValueSize(sourceType, sourceValue) + if err != nil { + return nil, err + } + + buf := make([]byte, size) + newBuf, err := d.marshalType(sourceType, sourceValue, buf[:0], []sszSizeHint{}, 0) + if err != nil { + return nil, err + } + + if len(newBuf) != size { + return nil, fmt.Errorf("ssz length does not match expected length (expected: %v, got: %v)", size, len(newBuf)) + } + + return newBuf, nil +} + +func MarshalSSZTo(source any, buf []byte) ([]byte, error) { + d := NewDynSsz() + + sourceType := reflect.TypeOf(source) + sourceValue := reflect.ValueOf(source) + + newBuf, err := d.marshalType(sourceType, sourceValue, buf, []sszSizeHint{}, 0) + if err != nil { + return nil, err + } + + return newBuf, nil +} + +func SizeSSZ(source any) (int, error) { + d := NewDynSsz() + sourceType := reflect.TypeOf(source) + sourceValue := reflect.ValueOf(source) + + return d.getSszValueSize(sourceType, sourceValue) +} + +func UnmarshalSSZ(target any, ssz []byte) error { + d := NewDynSsz() + + targetType := reflect.TypeOf(target) + targetValue := reflect.ValueOf(target) + + consumedBytes, err := d.unmarshalType(targetType, targetValue, ssz, []sszSizeHint{}, 0) + if err != nil { + return err + } + + if consumedBytes != len(ssz) { + return fmt.Errorf("did not consume full ssz range (consumed: %v, ssz size: %v)", consumedBytes, len(ssz)) + } + + return nil +} diff --git a/ssz/marshal.go b/ssz/marshal.go index 9fada4e8..96c08442 100644 --- a/ssz/marshal.go +++ b/ssz/marshal.go @@ -8,21 +8,6 @@ import ( fastssz "github.com/ferranbt/fastssz" ) -func MarshalSSZ(source any, buf []byte) ([]byte, error) { - d := NewDynSsz() - d.NoFastSsz = true - - sourceType := reflect.TypeOf(source) - sourceValue := reflect.ValueOf(source) - - newBuf, err := d.marshalType(sourceType, sourceValue, buf, []sszSizeHint{}, 0) - if err != nil { - return nil, err - } - - return newBuf, nil -} - func (d *DynSsz) marshalType(sourceType reflect.Type, sourceValue reflect.Value, buf []byte, sizeHints []sszSizeHint, idt int) ([]byte, error) { if sourceType.Kind() == reflect.Ptr { sourceType = sourceType.Elem() @@ -49,7 +34,7 @@ func (d *DynSsz) marshalType(sourceType reflect.Type, sourceValue reflect.Value, } } - fmt.Printf("%s fastssz for type %s: %v\n", indent(idt), sourceType.Name(), hasSpecVals) + //fmt.Printf("%s fastssz for type %s: %v\n", indent(idt), sourceType.Name(), hasSpecVals) d.typesWithSpecVals[sourceType] = hasSpecVals } if hasSpecVals == noSpecValues && !d.NoFastSsz { diff --git a/ssz/sszsize.go b/ssz/sszsize.go index f63d2c55..5f83704b 100644 --- a/ssz/sszsize.go +++ b/ssz/sszsize.go @@ -158,3 +158,72 @@ func (d *DynSsz) getSszFieldSize(targetField *reflect.StructField) (int, bool, [ size, hasSpecVal, err := d.getSszSize(targetField.Type, sszSizes) return size, hasSpecVal, sszSizes, err } + +func (d *DynSsz) getSszValueSize(targetType reflect.Type, targetValue reflect.Value) (int, error) { + staticSize := 0 + + if targetType.Kind() == reflect.Ptr { + targetType = targetType.Elem() + targetValue = targetValue.Elem() + } + + switch targetType.Kind() { + case reflect.Struct: + for i := 0; i < targetType.NumField(); i++ { + field := targetType.Field(i) + fieldValue := targetValue.Field(i) + + fieldTypeSize, _, _, err := d.getSszFieldSize(&field) + if err != nil { + return 0, err + } + + if fieldTypeSize < 0 { + // dynamic field, add 4 bytes for offset + staticSize += 4 + } + + size, err := d.getSszValueSize(field.Type, fieldValue) + if err != nil { + return 0, err + } + + staticSize += size + } + case reflect.Array: + arrLen := targetType.Len() + if arrLen > 0 { + fieldType := targetType.Elem() + size, err := d.getSszValueSize(fieldType, targetValue.Index(0)) + if err != nil { + return 0, err + } + staticSize = size * arrLen + } + case reflect.Slice: + fieldType := targetType.Elem() + sliceLen := targetValue.Len() + + if sliceLen > 0 { + size, err := d.getSszValueSize(fieldType, targetValue.Index(0)) + if err != nil { + return 0, err + } + staticSize = size * sliceLen + } + case reflect.Bool: + staticSize = 1 + case reflect.Uint8: + staticSize = 1 + case reflect.Uint16: + staticSize = 2 + case reflect.Uint32: + staticSize = 4 + case reflect.Uint64: + staticSize = 8 + default: + return 0, fmt.Errorf("unhandled reflection kind in size check: %v", targetType.Kind()) + } + + return staticSize, nil +} diff --git a/ssz/test/main.go b/ssz/test/main.go index 562215b0..aaeba929 100644 --- a/ssz/test/main.go +++ b/ssz/test/main.go @@ -92,7 +92,7 @@ func test2(body []byte) { //fmt.Printf("state root: 0x%x\n", root) fmt.Printf("gvr: 0x%x\n", t.GenesisValidatorsRoot) - _, err = ssz.MarshalSSZ(t, nil) + _, err = ssz.MarshalSSZ(t) if err != nil { fmt.Printf("error: %v\n", err) return diff --git a/ssz/unmarshal.go b/ssz/unmarshal.go index dfa12f3f..8a4d4ee3 100644 --- a/ssz/unmarshal.go +++ b/ssz/unmarshal.go @@ -7,24 +7,6 @@ import ( fastssz "github.com/ferranbt/fastssz" ) -func UnmarshalSSZ(target any, ssz []byte) error { - d := NewDynSsz() - - targetType := reflect.TypeOf(target) - targetValue := reflect.ValueOf(target) - - consumedBytes, err := d.unmarshalType(targetType, targetValue, ssz, []sszSizeHint{}, 0) - if err != nil { - return err - } - - if consumedBytes != len(ssz) { - return fmt.Errorf("did not consume full ssz range (consumed: %v, ssz size: %v)", consumedBytes, len(ssz)) - } - - return nil -} - func (d *DynSsz) unmarshalType(targetType reflect.Type, targetValue reflect.Value, ssz []byte, sizeHints []sszSizeHint, idt int) (int, error) { consumedBytes := 0 From fc712e1e0e4a6a51cb5d130af21028da65ef6775 Mon Sep 17 00:00:00 2001 From: pk910 Date: Sat, 30 Mar 2024 06:30:33 +0100 Subject: [PATCH 04/18] add more dynssz-size tags to spec structs --- spec/altair/beaconstate.go | 2 +- spec/bellatrix/beaconstate.go | 8 ++++---- spec/capella/beaconstate.go | 8 ++++---- spec/deneb/beaconstate.go | 4 ++-- spec/phase0/beaconstate.go | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/spec/altair/beaconstate.go b/spec/altair/beaconstate.go index 61bf3f72..fdbded3b 100644 --- a/spec/altair/beaconstate.go +++ b/spec/altair/beaconstate.go @@ -36,7 +36,7 @@ type BeaconState struct { LatestBlockHeader *phase0.BeaconBlockHeader BlockRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` StateRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` - HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32" dynssz-size:"?,HISTORICAL_ROOTS_LIMIT"` + HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32"` ETH1Data *phase0.ETH1Data ETH1DataVotes []*phase0.ETH1Data `ssz-max:"2048"` ETH1DepositIndex uint64 diff --git a/spec/bellatrix/beaconstate.go b/spec/bellatrix/beaconstate.go index d8addb91..2a339960 100644 --- a/spec/bellatrix/beaconstate.go +++ b/spec/bellatrix/beaconstate.go @@ -35,16 +35,16 @@ type BeaconState struct { Slot phase0.Slot Fork *phase0.Fork LatestBlockHeader *phase0.BeaconBlockHeader - BlockRoots []phase0.Root `ssz-size:"8192,32"` - StateRoots []phase0.Root `ssz-size:"8192,32"` + BlockRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` + StateRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32"` ETH1Data *phase0.ETH1Data ETH1DataVotes []*phase0.ETH1Data `ssz-max:"2048"` ETH1DepositIndex uint64 Validators []*phase0.Validator `ssz-max:"1099511627776"` Balances []phase0.Gwei `ssz-max:"1099511627776"` - RANDAOMixes []phase0.Root `ssz-size:"65536,32"` - Slashings []phase0.Gwei `ssz-size:"8192"` + RANDAOMixes []phase0.Root `ssz-size:"65536,32" dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32"` + Slashings []phase0.Gwei `ssz-size:"8192" dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR"` PreviousEpochParticipation []altair.ParticipationFlags `ssz-max:"1099511627776"` CurrentEpochParticipation []altair.ParticipationFlags `ssz-max:"1099511627776"` JustificationBits bitfield.Bitvector4 `ssz-size:"1"` diff --git a/spec/capella/beaconstate.go b/spec/capella/beaconstate.go index db439c9e..43b04f6b 100644 --- a/spec/capella/beaconstate.go +++ b/spec/capella/beaconstate.go @@ -29,16 +29,16 @@ type BeaconState struct { Slot phase0.Slot Fork *phase0.Fork LatestBlockHeader *phase0.BeaconBlockHeader - BlockRoots []phase0.Root `ssz-size:"8192,32"` - StateRoots []phase0.Root `ssz-size:"8192,32"` + BlockRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` + StateRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32"` ETH1Data *phase0.ETH1Data ETH1DataVotes []*phase0.ETH1Data `ssz-max:"2048"` ETH1DepositIndex uint64 Validators []*phase0.Validator `ssz-max:"1099511627776"` Balances []phase0.Gwei `ssz-max:"1099511627776"` - RANDAOMixes []phase0.Root `ssz-size:"65536,32"` - Slashings []phase0.Gwei `ssz-size:"8192"` + RANDAOMixes []phase0.Root `ssz-size:"65536,32" dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32"` + Slashings []phase0.Gwei `ssz-size:"8192" dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR"` PreviousEpochParticipation []altair.ParticipationFlags `ssz-max:"1099511627776"` CurrentEpochParticipation []altair.ParticipationFlags `ssz-max:"1099511627776"` JustificationBits bitfield.Bitvector4 `ssz-size:"1"` diff --git a/spec/deneb/beaconstate.go b/spec/deneb/beaconstate.go index 3671c77b..cfa0e148 100644 --- a/spec/deneb/beaconstate.go +++ b/spec/deneb/beaconstate.go @@ -38,8 +38,8 @@ type BeaconState struct { ETH1DepositIndex uint64 Validators []*phase0.Validator `ssz-max:"1099511627776"` Balances []phase0.Gwei `ssz-max:"1099511627776"` - RANDAOMixes []phase0.Root `ssz-size:"65536,32"` - Slashings []phase0.Gwei `ssz-size:"8192"` + RANDAOMixes []phase0.Root `ssz-size:"65536,32" dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32"` + Slashings []phase0.Gwei `ssz-size:"8192" dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR"` PreviousEpochParticipation []altair.ParticipationFlags `ssz-max:"1099511627776"` CurrentEpochParticipation []altair.ParticipationFlags `ssz-max:"1099511627776"` JustificationBits bitfield.Bitvector4 `ssz-size:"1"` diff --git a/spec/phase0/beaconstate.go b/spec/phase0/beaconstate.go index c9d97492..07c559f2 100644 --- a/spec/phase0/beaconstate.go +++ b/spec/phase0/beaconstate.go @@ -35,7 +35,7 @@ type BeaconState struct { LatestBlockHeader *BeaconBlockHeader BlockRoots []Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` StateRoots []Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` - HistoricalRoots []Root `ssz-max:"16777216" ssz-size:"?,32" dynssz-size:"?,HISTORICAL_ROOTS_LIMIT"` + HistoricalRoots []Root `ssz-max:"16777216" ssz-size:"?,32"` ETH1Data *ETH1Data ETH1DataVotes []*ETH1Data `ssz-max:"2048"` ETH1DepositIndex uint64 From 0350168c6691716222b7354de0338c74bea0ca7b Mon Sep 17 00:00:00 2001 From: pk910 Date: Sat, 30 Mar 2024 07:26:21 +0100 Subject: [PATCH 05/18] add dynamic ssz handling via parameter --- http/beaconstate.go | 56 +++++++++++++++++++++++++++++++------- http/parameters.go | 9 +++++++ http/proposal.go | 54 +++++++++++++++++++++++++++++++------ http/service.go | 2 ++ http/signedbeaconblock.go | 56 +++++++++++++++++++++++++++++++------- ssz/dynssz.go | 23 +++++++--------- ssz/specvals.go | 43 +++++++++++++++++++++++++++++ ssz/sszsize.go | 57 ++++++++++++++++++++------------------- ssz/test/main.go | 6 +++-- 9 files changed, 234 insertions(+), 72 deletions(-) create mode 100644 ssz/specvals.go diff --git a/http/beaconstate.go b/http/beaconstate.go index 0d62dfdd..e8c00583 100644 --- a/http/beaconstate.go +++ b/http/beaconstate.go @@ -27,6 +27,7 @@ import ( "github.com/attestantio/go-eth2-client/spec/capella" "github.com/attestantio/go-eth2-client/spec/deneb" "github.com/attestantio/go-eth2-client/spec/phase0" + "github.com/attestantio/go-eth2-client/ssz" ) // BeaconState fetches a beacon state. @@ -70,31 +71,66 @@ func (s *Service) beaconStateFromSSZ(res *httpResponse) (*api.Response[*spec.Ver Metadata: metadataFromHeaders(res.headers), } + var dynSSZ *ssz.DynSsz + if s.useDynamicSSZ { + dynSSZ = ssz.NewDynSsz(s.spec) + } + switch res.consensusVersion { case spec.DataVersionPhase0: response.Data.Phase0 = &phase0.BeaconState{} - if err := response.Data.Phase0.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode phase0 beacon state"), err) + if s.useDynamicSSZ { + if err := dynSSZ.UnmarshalSSZ(response.Data.Phase0, res.body); err != nil { + return nil, errors.Join(errors.New("failed to dynamic decode phase0 beacon state"), err) + } + } else { + if err := response.Data.Phase0.UnmarshalSSZ(res.body); err != nil { + return nil, errors.Join(errors.New("failed to decode phase0 beacon state"), err) + } } case spec.DataVersionAltair: response.Data.Altair = &altair.BeaconState{} - if err := response.Data.Altair.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode altair beacon state"), err) + if s.useDynamicSSZ { + if err := dynSSZ.UnmarshalSSZ(response.Data.Altair, res.body); err != nil { + return nil, errors.Join(errors.New("failed to dynamic decode altair beacon state"), err) + } + } else { + if err := response.Data.Altair.UnmarshalSSZ(res.body); err != nil { + return nil, errors.Join(errors.New("failed to decode altair beacon state"), err) + } } case spec.DataVersionBellatrix: response.Data.Bellatrix = &bellatrix.BeaconState{} - if err := response.Data.Bellatrix.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode bellatrix beacon state"), err) + if s.useDynamicSSZ { + if err := dynSSZ.UnmarshalSSZ(response.Data.Bellatrix, res.body); err != nil { + return nil, errors.Join(errors.New("failed to dynamic decode bellatrix beacon state"), err) + } + } else { + if err := response.Data.Bellatrix.UnmarshalSSZ(res.body); err != nil { + return nil, errors.Join(errors.New("failed to decode bellatrix beacon state"), err) + } } case spec.DataVersionCapella: response.Data.Capella = &capella.BeaconState{} - if err := response.Data.Capella.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode capella beacon state"), err) + if s.useDynamicSSZ { + if err := dynSSZ.UnmarshalSSZ(response.Data.Capella, res.body); err != nil { + return nil, errors.Join(errors.New("failed to dynamic decode capella beacon state"), err) + } + } else { + if err := response.Data.Capella.UnmarshalSSZ(res.body); err != nil { + return nil, errors.Join(errors.New("failed to decode capella beacon state"), err) + } } case spec.DataVersionDeneb: response.Data.Deneb = &deneb.BeaconState{} - if err := response.Data.Deneb.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode deneb beacon state"), err) + if s.useDynamicSSZ { + if err := dynSSZ.UnmarshalSSZ(response.Data.Deneb, res.body); err != nil { + return nil, errors.Join(errors.New("failed to dynamic decode deneb beacon state"), err) + } + } else { + if err := response.Data.Deneb.UnmarshalSSZ(res.body); err != nil { + return nil, errors.Join(errors.New("failed to decode deneb beacon state"), err) + } } default: return nil, fmt.Errorf("unhandled state version %s", res.consensusVersion) diff --git a/http/parameters.go b/http/parameters.go index ead2f988..b84f0990 100644 --- a/http/parameters.go +++ b/http/parameters.go @@ -33,6 +33,7 @@ type parameters struct { allowDelayedStart bool hooks *Hooks reducedMemoryUsage bool + dynamicSSZ bool } // Parameter is the interface for service parameters. @@ -124,6 +125,14 @@ func WithReducedMemoryUsage(reducedMemoryUsage bool) Parameter { }) } +// WithDynamicSSZ use dynamic SSZ library, which is able to handle non-mainnet presets. +// Dynamic SSZ en-/decoding is much slower than the static one. Use only if required. +func WithDynamicSSZ(dynamicSSZ bool) Parameter { + return parameterFunc(func(p *parameters) { + p.dynamicSSZ = dynamicSSZ + }) +} + // parseAndCheckParameters parses and checks parameters to ensure that mandatory parameters are present and correct. func parseAndCheckParameters(params ...Parameter) (*parameters, error) { parameters := parameters{ diff --git a/http/proposal.go b/http/proposal.go index ca33eb80..ca927644 100644 --- a/http/proposal.go +++ b/http/proposal.go @@ -31,6 +31,7 @@ import ( "github.com/attestantio/go-eth2-client/spec/bellatrix" "github.com/attestantio/go-eth2-client/spec/capella" "github.com/attestantio/go-eth2-client/spec/phase0" + "github.com/attestantio/go-eth2-client/ssz" "go.opentelemetry.io/otel" ) @@ -134,37 +135,74 @@ func (s *Service) beaconBlockProposalFromSSZ(res *httpResponse) (*api.Response[* return nil, err } + var dynSSZ *ssz.DynSsz + if s.useDynamicSSZ { + dynSSZ = ssz.NewDynSsz(s.spec) + } + var err error switch res.consensusVersion { case spec.DataVersionPhase0: response.Data.Phase0 = &phase0.BeaconBlock{} - err = response.Data.Phase0.UnmarshalSSZ(res.body) + if s.useDynamicSSZ { + err = dynSSZ.UnmarshalSSZ(response.Data.Phase0, res.body) + } else { + err = response.Data.Phase0.UnmarshalSSZ(res.body) + } case spec.DataVersionAltair: response.Data.Altair = &altair.BeaconBlock{} - err = response.Data.Altair.UnmarshalSSZ(res.body) + if s.useDynamicSSZ { + err = dynSSZ.UnmarshalSSZ(response.Data.Altair, res.body) + } else { + err = response.Data.Altair.UnmarshalSSZ(res.body) + } case spec.DataVersionBellatrix: if response.Data.Blinded { response.Data.BellatrixBlinded = &apiv1bellatrix.BlindedBeaconBlock{} - err = response.Data.BellatrixBlinded.UnmarshalSSZ(res.body) + if s.useDynamicSSZ { + err = dynSSZ.UnmarshalSSZ(response.Data.BellatrixBlinded, res.body) + } else { + err = response.Data.BellatrixBlinded.UnmarshalSSZ(res.body) + } } else { response.Data.Bellatrix = &bellatrix.BeaconBlock{} - err = response.Data.Bellatrix.UnmarshalSSZ(res.body) + if s.useDynamicSSZ { + err = dynSSZ.UnmarshalSSZ(response.Data.Bellatrix, res.body) + } else { + err = response.Data.Bellatrix.UnmarshalSSZ(res.body) + } } case spec.DataVersionCapella: if response.Data.Blinded { response.Data.CapellaBlinded = &apiv1capella.BlindedBeaconBlock{} - err = response.Data.CapellaBlinded.UnmarshalSSZ(res.body) + if s.useDynamicSSZ { + err = dynSSZ.UnmarshalSSZ(response.Data.CapellaBlinded, res.body) + } else { + err = response.Data.CapellaBlinded.UnmarshalSSZ(res.body) + } } else { response.Data.Capella = &capella.BeaconBlock{} - err = response.Data.Capella.UnmarshalSSZ(res.body) + if s.useDynamicSSZ { + err = dynSSZ.UnmarshalSSZ(response.Data.Capella, res.body) + } else { + err = response.Data.Capella.UnmarshalSSZ(res.body) + } } case spec.DataVersionDeneb: if response.Data.Blinded { response.Data.DenebBlinded = &apiv1deneb.BlindedBeaconBlock{} - err = response.Data.DenebBlinded.UnmarshalSSZ(res.body) + if s.useDynamicSSZ { + err = dynSSZ.UnmarshalSSZ(response.Data.DenebBlinded, res.body) + } else { + err = response.Data.DenebBlinded.UnmarshalSSZ(res.body) + } } else { response.Data.Deneb = &apiv1deneb.BlockContents{} - err = response.Data.Deneb.UnmarshalSSZ(res.body) + if s.useDynamicSSZ { + err = dynSSZ.UnmarshalSSZ(response.Data.Deneb, res.body) + } else { + err = response.Data.Deneb.UnmarshalSSZ(res.body) + } } default: return nil, fmt.Errorf("unhandled block proposal version %s", res.consensusVersion) diff --git a/http/service.go b/http/service.go index 7895230b..6cb30c71 100644 --- a/http/service.go +++ b/http/service.go @@ -73,6 +73,7 @@ type Service struct { enforceJSON bool connectedToDVTMiddleware bool reducedMemoryUsage bool + useDynamicSSZ bool } // New creates a new Ethereum 2 client service, connecting with a standard HTTP. @@ -126,6 +127,7 @@ func New(ctx context.Context, params ...Parameter) (client.Service, error) { pingSem: semaphore.NewWeighted(1), hooks: parameters.hooks, reducedMemoryUsage: parameters.reducedMemoryUsage, + useDynamicSSZ: parameters.dynamicSSZ, } // Ping the client to see if it is ready to serve requests. diff --git a/http/signedbeaconblock.go b/http/signedbeaconblock.go index f4bc3c00..f0a2acb3 100644 --- a/http/signedbeaconblock.go +++ b/http/signedbeaconblock.go @@ -27,6 +27,7 @@ import ( "github.com/attestantio/go-eth2-client/spec/capella" "github.com/attestantio/go-eth2-client/spec/deneb" "github.com/attestantio/go-eth2-client/spec/phase0" + "github.com/attestantio/go-eth2-client/ssz" ) // SignedBeaconBlock fetches a signed beacon block given a block ID. @@ -73,31 +74,66 @@ func (s *Service) signedBeaconBlockFromSSZ(res *httpResponse) (*api.Response[*sp Metadata: metadataFromHeaders(res.headers), } + var dynSSZ *ssz.DynSsz + if s.useDynamicSSZ { + dynSSZ = ssz.NewDynSsz(s.spec) + } + switch res.consensusVersion { case spec.DataVersionPhase0: response.Data.Phase0 = &phase0.SignedBeaconBlock{} - if err := response.Data.Phase0.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode phase0 signed beacon block"), err) + if s.useDynamicSSZ { + if err := dynSSZ.UnmarshalSSZ(response.Data.Phase0, res.body); err != nil { + return nil, errors.Join(errors.New("failed to dynamic decode phase0 signed beacon block"), err) + } + } else { + if err := response.Data.Phase0.UnmarshalSSZ(res.body); err != nil { + return nil, errors.Join(errors.New("failed to decode phase0 signed beacon block"), err) + } } case spec.DataVersionAltair: response.Data.Altair = &altair.SignedBeaconBlock{} - if err := response.Data.Altair.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode altair signed beacon block"), err) + if s.useDynamicSSZ { + if err := dynSSZ.UnmarshalSSZ(response.Data.Altair, res.body); err != nil { + return nil, errors.Join(errors.New("failed to dynamic decode altair signed beacon block"), err) + } + } else { + if err := response.Data.Altair.UnmarshalSSZ(res.body); err != nil { + return nil, errors.Join(errors.New("failed to decode altair signed beacon block"), err) + } } case spec.DataVersionBellatrix: response.Data.Bellatrix = &bellatrix.SignedBeaconBlock{} - if err := response.Data.Bellatrix.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode bellatrix signed beacon block"), err) + if s.useDynamicSSZ { + if err := dynSSZ.UnmarshalSSZ(response.Data.Bellatrix, res.body); err != nil { + return nil, errors.Join(errors.New("failed to dynamic decode bellatrix signed beacon block"), err) + } + } else { + if err := response.Data.Bellatrix.UnmarshalSSZ(res.body); err != nil { + return nil, errors.Join(errors.New("failed to decode bellatrix signed beacon block"), err) + } } case spec.DataVersionCapella: response.Data.Capella = &capella.SignedBeaconBlock{} - if err := response.Data.Capella.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode capella signed beacon block"), err) + if s.useDynamicSSZ { + if err := dynSSZ.UnmarshalSSZ(response.Data.Capella, res.body); err != nil { + return nil, errors.Join(errors.New("failed to dynamic decode capella signed beacon block"), err) + } + } else { + if err := response.Data.Capella.UnmarshalSSZ(res.body); err != nil { + return nil, errors.Join(errors.New("failed to decode capella signed beacon block"), err) + } } case spec.DataVersionDeneb: response.Data.Deneb = &deneb.SignedBeaconBlock{} - if err := response.Data.Deneb.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode deneb signed block contents"), err) + if s.useDynamicSSZ { + if err := dynSSZ.UnmarshalSSZ(response.Data.Deneb, res.body); err != nil { + return nil, errors.Join(errors.New("failed to dynamic decode deneb signed beacon block"), err) + } + } else { + if err := response.Data.Deneb.UnmarshalSSZ(res.body); err != nil { + return nil, errors.Join(errors.New("failed to decode deneb signed block contents"), err) + } } default: return nil, fmt.Errorf("unhandled block version %s", res.consensusVersion) diff --git a/ssz/dynssz.go b/ssz/dynssz.go index a249c1c0..ab4ef385 100644 --- a/ssz/dynssz.go +++ b/ssz/dynssz.go @@ -17,17 +17,17 @@ const ( hasSpecValues ) -func NewDynSsz() *DynSsz { +func NewDynSsz(specs map[string]any) *DynSsz { + if specs == nil { + specs = map[string]any{} + } return &DynSsz{ typesWithSpecVals: map[reflect.Type]uint8{}, - SpecValues: map[string]any{ - //"SLOTS_PER_HISTORICAL_ROOT": uint64(8192), - }, + SpecValues: specs, } } -func MarshalSSZ(source any) ([]byte, error) { - d := NewDynSsz() +func (d *DynSsz) MarshalSSZ(source any) ([]byte, error) { sourceType := reflect.TypeOf(source) sourceValue := reflect.ValueOf(source) @@ -49,9 +49,7 @@ func MarshalSSZ(source any) ([]byte, error) { return newBuf, nil } -func MarshalSSZTo(source any, buf []byte) ([]byte, error) { - d := NewDynSsz() - +func (d *DynSsz) MarshalSSZTo(source any, buf []byte) ([]byte, error) { sourceType := reflect.TypeOf(source) sourceValue := reflect.ValueOf(source) @@ -63,17 +61,14 @@ func MarshalSSZTo(source any, buf []byte) ([]byte, error) { return newBuf, nil } -func SizeSSZ(source any) (int, error) { - d := NewDynSsz() +func (d *DynSsz) SizeSSZ(source any) (int, error) { sourceType := reflect.TypeOf(source) sourceValue := reflect.ValueOf(source) return d.getSszValueSize(sourceType, sourceValue) } -func UnmarshalSSZ(target any, ssz []byte) error { - d := NewDynSsz() - +func (d *DynSsz) UnmarshalSSZ(target any, ssz []byte) error { targetType := reflect.TypeOf(target) targetValue := reflect.ValueOf(target) diff --git a/ssz/specvals.go b/ssz/specvals.go new file mode 100644 index 00000000..2a1b3199 --- /dev/null +++ b/ssz/specvals.go @@ -0,0 +1,43 @@ +package ssz + +import "fmt" + +func (d *DynSsz) getSpecValue(name string) (bool, uint64, error) { + + switch name { + // there are some calculated values, but adding a parser & dynamic calculations for these seems a bit overkill + case "SYNC_COMMITTEE_SIZE/8": + ok, val, err := d.getSpecValue("SYNC_COMMITTEE_SIZE") + if ok { + return ok, val / 8, err + } + case "SYNC_COMMITTEE_SIZE/SYNC_COMMITTEE_SUBNET_COUNT": + ok1, val1, err1 := d.getSpecValue("SYNC_COMMITTEE_SIZE") + ok2, val2, err2 := d.getSpecValue("SYNC_COMMITTEE_SUBNET_COUNT") + if err1 != nil { + return false, 0, err1 + } + if err2 != nil { + return false, 0, err2 + } + if ok1 && ok2 { + return true, val1 / val2, nil + } + case "DEPOSIT_CONTRACT_TREE_DEPTH+1": + ok, val, err := d.getSpecValue("DEPOSIT_CONTRACT_TREE_DEPTH") + if ok { + return ok, val + 1, err + } + default: + specVal := d.SpecValues[name] + if specVal != nil { + specInt, ok := specVal.(uint64) + if !ok { + return false, 0, fmt.Errorf("value is not uint64") + } + return true, specInt, nil + } + + } + return false, 0, nil +} diff --git a/ssz/sszsize.go b/ssz/sszsize.go index 5f83704b..7c084b29 100644 --- a/ssz/sszsize.go +++ b/ssz/sszsize.go @@ -16,49 +16,50 @@ type sszSizeHint struct { func (d *DynSsz) getSszSizeTag(field *reflect.StructField) ([]sszSizeHint, error) { sszSizes := []sszSizeHint{} - fieldDynSszSizeStr, fieldHasDynSszSize := field.Tag.Lookup("dynssz-size") - if fieldHasDynSszSize { - for _, sszSizeStr := range strings.Split(fieldDynSszSizeStr, ",") { + if fieldSszSizeStr, fieldHasSszSize := field.Tag.Lookup("ssz-size"); fieldHasSszSize { + for _, sszSizeStr := range strings.Split(fieldSszSizeStr, ",") { sszSize := sszSizeHint{} if sszSizeStr == "?" { sszSize.dynamic = true - } else if sszSizeInt, err := strconv.ParseUint(sszSizeStr, 10, 32); err == nil { - sszSize.size = sszSizeInt - } else if specVal := d.SpecValues[sszSizeStr]; specVal != nil { - // dynamic value from spec - specInt, ok := specVal.(uint64) - if !ok { - return sszSizes, fmt.Errorf("error parsing dynssz-size tag for '%v' field: %v spec value is not uint64", field.Name, sszSizeStr) - } - sszSize.size = specInt - sszSize.specval = true } else { - // unknown spec value? fallback to fastssz - fieldHasDynSszSize = false - break + sszSizeInt, err := strconv.ParseUint(sszSizeStr, 10, 32) + if err != nil { + return sszSizes, fmt.Errorf("error parsing ssz-size tag for '%v' field: %v", field.Name, err) + } + sszSize.size = sszSizeInt } sszSizes = append(sszSizes, sszSize) } } - if !fieldHasDynSszSize { - if fieldSszSizeStr, fieldHasSszSize := field.Tag.Lookup("ssz-size"); fieldHasSszSize { - for _, sszSizeStr := range strings.Split(fieldSszSizeStr, ",") { - sszSize := sszSizeHint{} + fieldDynSszSizeStr, fieldHasDynSszSize := field.Tag.Lookup("dynssz-size") + if fieldHasDynSszSize { + for i, sszSizeStr := range strings.Split(fieldDynSszSizeStr, ",") { + sszSize := sszSizeHint{} - if sszSizeStr == "?" { - sszSize.dynamic = true + if sszSizeStr == "?" { + sszSize.dynamic = true + } else if sszSizeInt, err := strconv.ParseUint(sszSizeStr, 10, 32); err == nil { + sszSize.size = sszSizeInt + } else { + ok, specVal, err := d.getSpecValue(sszSizeStr) + if err != nil { + return sszSizes, fmt.Errorf("error parsing dynssz-size tag for '%v' field (%v): %v", field.Name, sszSizeStr, err) + } + if ok { + // dynamic value from spec + sszSize.size = specVal + sszSize.specval = true } else { - sszSizeInt, err := strconv.ParseUint(sszSizeStr, 10, 32) - if err != nil { - return sszSizes, fmt.Errorf("error parsing ssz-size tag for '%v' field: %v", field.Name, err) - } - sszSize.size = sszSizeInt + // unknown spec value? fallback to fastssz + break } + } - sszSizes = append(sszSizes, sszSize) + if sszSizes[i].size != sszSize.size { + sszSizes[i] = sszSize } } } diff --git a/ssz/test/main.go b/ssz/test/main.go index aaeba929..f09238b5 100644 --- a/ssz/test/main.go +++ b/ssz/test/main.go @@ -78,8 +78,10 @@ func test2(body []byte) { fmt.Printf("\npk's dynamic ssz\n") + d := ssz.NewDynSsz(map[string]any{}) + t := new(deneb.BeaconState) - err := ssz.UnmarshalSSZ(t, body) + err := d.UnmarshalSSZ(t, body) if err != nil { fmt.Printf("error: %v\n", err) return @@ -92,7 +94,7 @@ func test2(body []byte) { //fmt.Printf("state root: 0x%x\n", root) fmt.Printf("gvr: 0x%x\n", t.GenesisValidatorsRoot) - _, err = ssz.MarshalSSZ(t) + _, err = d.MarshalSSZ(t) if err != nil { fmt.Printf("error: %v\n", err) return From 93f905e392bd2d6c4cc3c351685688f5789e39bd Mon Sep 17 00:00:00 2001 From: pk910 Date: Sat, 30 Mar 2024 08:53:37 +0100 Subject: [PATCH 06/18] ads dynamic length slices --- ssz/marshal.go | 58 +++++++++++++++++++++++++++++++++++++++++- ssz/sszsize.go | 20 +++++++++++++-- ssz/test/main.go | 45 ++++++++++++++++++--------------- ssz/unmarshal.go | 66 +++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 165 insertions(+), 24 deletions(-) diff --git a/ssz/marshal.go b/ssz/marshal.go index 96c08442..8d32d9e9 100644 --- a/ssz/marshal.go +++ b/ssz/marshal.go @@ -191,11 +191,28 @@ func (d *DynSsz) marshalSlice(sourceType reflect.Type, sourceValue reflect.Value fieldType = fieldType.Elem() } - sliceLen := sourceValue.Len() + isDynSlice := false + if len(sizeHints) > 1 && sizeHints[1].dynamic { + isDynSlice = true + } else { + size, _, err := d.getSszSize(fieldType, childSizeHints) + if err != nil { + return nil, err + } + if size < 0 { + isDynSlice = true + } + } + + if isDynSlice { + return d.marshalDynamicSlice(sourceType, sourceValue, buf, childSizeHints, idt) + } + if fieldType == byteType { // shortcut for performance: use append on []byte arrays buf = append(buf, sourceValue.Bytes()...) } else { + sliceLen := sourceValue.Len() for i := 0; i < sliceLen; i++ { itemVal := sourceValue.Index(i) if fieldIsPtr { @@ -212,3 +229,42 @@ func (d *DynSsz) marshalSlice(sourceType reflect.Type, sourceValue reflect.Value return buf, nil } + +func (d *DynSsz) marshalDynamicSlice(sourceType reflect.Type, sourceValue reflect.Value, buf []byte, sizeHints []sszSizeHint, idt int) ([]byte, error) { + sliceLen := sourceValue.Len() + startOffset := len(buf) + offsetBuf := make([]byte, 4*sliceLen) + buf = append(buf, offsetBuf...) + + fieldType := sourceType.Elem() + fieldIsPtr := fieldType.Kind() == reflect.Ptr + if fieldIsPtr { + fieldType = fieldType.Elem() + } + + offset := 4 * sliceLen + bufLen := len(buf) + + for i := 0; i < sliceLen; i++ { + itemVal := sourceValue.Index(i) + if fieldIsPtr { + itemVal = itemVal.Elem() + } + + newBuf, err := d.marshalType(fieldType, itemVal, buf, sizeHints, idt+2) + if err != nil { + return nil, err + } + newBufLen := len(newBuf) + buf = newBuf + + offsetBuf := make([]byte, 4) + binary.LittleEndian.PutUint32(offsetBuf, uint32(offset)) + copy(buf[startOffset+(i*4):startOffset+((i+1)*4)], offsetBuf) + + offset += newBufLen - bufLen + bufLen = newBufLen + } + + return buf, nil +} diff --git a/ssz/sszsize.go b/ssz/sszsize.go index 7c084b29..aaa29f4f 100644 --- a/ssz/sszsize.go +++ b/ssz/sszsize.go @@ -206,11 +206,27 @@ func (d *DynSsz) getSszValueSize(targetType reflect.Type, targetValue reflect.Va sliceLen := targetValue.Len() if sliceLen > 0 { - size, err := d.getSszValueSize(fieldType, targetValue.Index(0)) + fieldTypeSize, _, err := d.getSszSize(fieldType, nil) if err != nil { return 0, err } - staticSize = size * sliceLen + + if fieldTypeSize < 0 { + // dyn size slice + for i := 0; i < sliceLen; i++ { + size, err := d.getSszValueSize(fieldType, targetValue.Index(i)) + if err != nil { + return 0, err + } + staticSize += size + 4 + } + } else { + size, err := d.getSszValueSize(fieldType, targetValue.Index(0)) + if err != nil { + return 0, err + } + staticSize = size * sliceLen + } } case reflect.Bool: staticSize = 1 diff --git a/ssz/test/main.go b/ssz/test/main.go index f09238b5..eef4728c 100644 --- a/ssz/test/main.go +++ b/ssz/test/main.go @@ -15,10 +15,18 @@ import ( ) func main() { - body, _ := ioutil.ReadFile("state2.ssz") + body, _ := ioutil.ReadFile("block-min.ssz") + + d := ssz.NewDynSsz(map[string]any{ + "SYNC_COMMITTEE_SIZE": uint64(32), + "SYNC_COMMITTEE_SUBNET_COUNT": uint64(4), + "EPOCHS_PER_HISTORICAL_VECTOR": uint64(64), + "SLOTS_PER_HISTORICAL_ROOT": uint64(64), + }) + d.NoFastSsz = true test1(body) - test2(body) + test2(d, body) f, _ := os.Create("mem.pprof") pprof.WriteHeapProfile(f) @@ -48,7 +56,7 @@ func test1(body []byte) { fmt.Printf("\nfastssz / go-eth2-client\n") - t := new(deneb.BeaconState) + t := new(deneb.SignedBeaconBlock) err := t.UnmarshalSSZ(body) if err != nil { fmt.Printf("error: %v\n", err) @@ -60,7 +68,7 @@ func test1(body []byte) { //root, _ := t.HashTreeRoot() //fmt.Printf("state root: 0x%x\n", root) - fmt.Printf("gvr: 0x%x\n", t.GenesisValidatorsRoot) + //fmt.Printf("gvr: 0x%x\n", t.GenesisValidatorsRoot) _, err = t.MarshalSSZ() if err != nil { @@ -69,7 +77,7 @@ func test1(body []byte) { } } -func test2(body []byte) { +func test2(d *ssz.DynSsz, body []byte) { start := time.Now() defer func() { elapsed := time.Since(start) @@ -78,9 +86,7 @@ func test2(body []byte) { fmt.Printf("\npk's dynamic ssz\n") - d := ssz.NewDynSsz(map[string]any{}) - - t := new(deneb.BeaconState) + t := new(deneb.SignedBeaconBlock) err := d.UnmarshalSSZ(t, body) if err != nil { fmt.Printf("error: %v\n", err) @@ -92,23 +98,22 @@ func test2(body []byte) { //root, _ := t.HashTreeRoot() //fmt.Printf("state root: 0x%x\n", root) - fmt.Printf("gvr: 0x%x\n", t.GenesisValidatorsRoot) + //fmt.Printf("gvr: 0x%x\n", t.GenesisValidatorsRoot) - _, err = d.MarshalSSZ(t) + buf, err := d.MarshalSSZ(t) if err != nil { fmt.Printf("error: %v\n", err) return } - /* - if len(buf) != len(body) { - fmt.Printf("size mismatch: %v / %v\n", len(buf), len(body)) - } - for i := 0; i < len(body); i++ { - if body[i] != buf[i] { - fmt.Printf("ssz mismatch: %v : %v / %v\n", i, buf[i], body[i]) - break - } + if len(buf) != len(body) { + fmt.Printf("size mismatch: %v / %v\n", len(buf), len(body)) + } + for i := 0; i < len(body); i++ { + if body[i] != buf[i] { + fmt.Printf("ssz mismatch: %v : %v / %v\n", i, buf[i], body[i]) + break } - */ + } + } diff --git a/ssz/unmarshal.go b/ssz/unmarshal.go index 8a4d4ee3..5335b1a5 100644 --- a/ssz/unmarshal.go +++ b/ssz/unmarshal.go @@ -260,7 +260,8 @@ func (d *DynSsz) unmarshalSlice(targetType reflect.Type, targetValue reflect.Val } if sliceLen == 0 && len(ssz) > 0 { - return 0, fmt.Errorf("cannot deteriminate length of dynamic slice") + // dynamic size slice + return d.unmarshalDynamicSlice(targetType, targetValue, ssz, childSizeHints, idt) } //fmt.Printf("new slice %v %v\n", fieldType.Name(), sliceLen) @@ -305,3 +306,66 @@ func (d *DynSsz) unmarshalSlice(targetType reflect.Type, targetValue reflect.Val return consumedBytes, nil } + +func (d *DynSsz) unmarshalDynamicSlice(targetType reflect.Type, targetValue reflect.Value, ssz []byte, sizeHints []sszSizeHint, idt int) (int, error) { + firstOffset := fastssz.ReadOffset(ssz[0:4]) + sliceLen := int(firstOffset / 4) + + sliceOffsets := make([]int, sliceLen) + sliceOffsets[0] = int(firstOffset) + for i := 1; i < sliceLen; i++ { + sliceOffsets[i] = int(fastssz.ReadOffset(ssz[i*4 : (i+1)*4])) + } + + fieldType := targetType.Elem() + fieldIsPtr := fieldType.Kind() == reflect.Ptr + if fieldIsPtr { + fieldType = fieldType.Elem() + } + + for i := 0; i < sliceLen; i++ { + + } + + //fmt.Printf("new dynamic slice %v %v\n", fieldType.Name(), sliceLen) + newValue := reflect.MakeSlice(targetType, sliceLen, sliceLen) + targetValue.Set(newValue) + + offset := int(firstOffset) + if sliceLen > 0 { + for i := 0; i < sliceLen; i++ { + var itemVal reflect.Value + if fieldIsPtr { + //fmt.Printf("new slice item %v\n", fieldType.Name()) + itemVal = reflect.New(fieldType).Elem() + newValue.Index(i).Set(itemVal.Addr()) + } else { + itemVal = newValue.Index(i) + } + + startOffset := sliceOffsets[i] + endOffset := 0 + if i == sliceLen-1 { + endOffset = len(ssz) + } else { + endOffset = sliceOffsets[i+1] + } + itemSize := endOffset - startOffset + + itemSsz := ssz[startOffset:endOffset] + + consumed, err := d.unmarshalType(fieldType, itemVal, itemSsz, sizeHints, idt+2) + if err != nil { + return 0, err + } + if consumed != itemSize { + return 0, fmt.Errorf("dynamic slice item did not consume expected ssz range (consumed: %v, expected: %v)", consumed, itemSize) + } + + offset += itemSize + } + } + + return offset, nil + +} From 3de79c2955b4bb526de71948089e0c812f760800 Mon Sep 17 00:00:00 2001 From: pk910 Date: Sat, 30 Mar 2024 23:37:24 +0100 Subject: [PATCH 07/18] move dynamic ssz marshaller to its own repository: https://github.com/pk910/dynamic-ssz --- go.mod | 3 +- go.sum | 2 + http/beaconstate.go | 6 +- http/proposal.go | 6 +- http/signedbeaconblock.go | 6 +- ssz/const.go | 11 -- ssz/debug.go | 7 - ssz/dynssz.go | 85 --------- ssz/marshal.go | 270 --------------------------- ssz/specvals.go | 43 ----- ssz/sszsize.go | 246 ------------------------- ssz/test/main.go | 119 ------------ ssz/unmarshal.go | 371 -------------------------------------- 13 files changed, 13 insertions(+), 1162 deletions(-) delete mode 100644 ssz/const.go delete mode 100644 ssz/debug.go delete mode 100644 ssz/dynssz.go delete mode 100644 ssz/marshal.go delete mode 100644 ssz/specvals.go delete mode 100644 ssz/sszsize.go delete mode 100644 ssz/test/main.go delete mode 100644 ssz/unmarshal.go diff --git a/go.mod b/go.mod index fb3e3e48..a833d5f9 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/attestantio/go-eth2-client -go 1.20 +go 1.21.1 require ( github.com/ferranbt/fastssz v0.1.3 @@ -35,6 +35,7 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pk910/dynamic-ssz v0.0.0-20240330223230-eced6836d885 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect diff --git a/go.sum b/go.sum index 9ae03b72..3216a8e8 100644 --- a/go.sum +++ b/go.sum @@ -65,6 +65,8 @@ github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dz github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/pk910/dynamic-ssz v0.0.0-20240330223230-eced6836d885 h1:7n5NaBz3f5Zb79C3zU8OVuTM0D0XAEwmhfn/Qvi1STU= +github.com/pk910/dynamic-ssz v0.0.0-20240330223230-eced6836d885/go.mod h1:boKvD5unVPTNvyETQV3gDNh0ga4AVCuZ+hJ+ja08QRc= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/http/beaconstate.go b/http/beaconstate.go index e8c00583..37edb35d 100644 --- a/http/beaconstate.go +++ b/http/beaconstate.go @@ -27,7 +27,7 @@ import ( "github.com/attestantio/go-eth2-client/spec/capella" "github.com/attestantio/go-eth2-client/spec/deneb" "github.com/attestantio/go-eth2-client/spec/phase0" - "github.com/attestantio/go-eth2-client/ssz" + dynssz "github.com/pk910/dynamic-ssz" ) // BeaconState fetches a beacon state. @@ -71,9 +71,9 @@ func (s *Service) beaconStateFromSSZ(res *httpResponse) (*api.Response[*spec.Ver Metadata: metadataFromHeaders(res.headers), } - var dynSSZ *ssz.DynSsz + var dynSSZ *dynssz.DynSsz if s.useDynamicSSZ { - dynSSZ = ssz.NewDynSsz(s.spec) + dynSSZ = dynssz.NewDynSsz(s.spec) } switch res.consensusVersion { diff --git a/http/proposal.go b/http/proposal.go index ca927644..6e2435fb 100644 --- a/http/proposal.go +++ b/http/proposal.go @@ -31,7 +31,7 @@ import ( "github.com/attestantio/go-eth2-client/spec/bellatrix" "github.com/attestantio/go-eth2-client/spec/capella" "github.com/attestantio/go-eth2-client/spec/phase0" - "github.com/attestantio/go-eth2-client/ssz" + dynssz "github.com/pk910/dynamic-ssz" "go.opentelemetry.io/otel" ) @@ -135,9 +135,9 @@ func (s *Service) beaconBlockProposalFromSSZ(res *httpResponse) (*api.Response[* return nil, err } - var dynSSZ *ssz.DynSsz + var dynSSZ *dynssz.DynSsz if s.useDynamicSSZ { - dynSSZ = ssz.NewDynSsz(s.spec) + dynSSZ = dynssz.NewDynSsz(s.spec) } var err error diff --git a/http/signedbeaconblock.go b/http/signedbeaconblock.go index f0a2acb3..62a2e282 100644 --- a/http/signedbeaconblock.go +++ b/http/signedbeaconblock.go @@ -27,7 +27,7 @@ import ( "github.com/attestantio/go-eth2-client/spec/capella" "github.com/attestantio/go-eth2-client/spec/deneb" "github.com/attestantio/go-eth2-client/spec/phase0" - "github.com/attestantio/go-eth2-client/ssz" + dynssz "github.com/pk910/dynamic-ssz" ) // SignedBeaconBlock fetches a signed beacon block given a block ID. @@ -74,9 +74,9 @@ func (s *Service) signedBeaconBlockFromSSZ(res *httpResponse) (*api.Response[*sp Metadata: metadataFromHeaders(res.headers), } - var dynSSZ *ssz.DynSsz + var dynSSZ *dynssz.DynSsz if s.useDynamicSSZ { - dynSSZ = ssz.NewDynSsz(s.spec) + dynSSZ = dynssz.NewDynSsz(s.spec) } switch res.consensusVersion { diff --git a/ssz/const.go b/ssz/const.go deleted file mode 100644 index 6161f9e5..00000000 --- a/ssz/const.go +++ /dev/null @@ -1,11 +0,0 @@ -package ssz - -import ( - "reflect" - - fastssz "github.com/ferranbt/fastssz" -) - -var byteType = reflect.TypeOf(byte(0)) -var sszMarshallerType = reflect.TypeOf((*fastssz.Marshaler)(nil)).Elem() -var sszUnmarshallerType = reflect.TypeOf((*fastssz.Unmarshaler)(nil)).Elem() diff --git a/ssz/debug.go b/ssz/debug.go deleted file mode 100644 index f00d1130..00000000 --- a/ssz/debug.go +++ /dev/null @@ -1,7 +0,0 @@ -package ssz - -import "strings" - -func indent(c int) string { - return strings.Repeat(" ", c) -} diff --git a/ssz/dynssz.go b/ssz/dynssz.go deleted file mode 100644 index ab4ef385..00000000 --- a/ssz/dynssz.go +++ /dev/null @@ -1,85 +0,0 @@ -package ssz - -import ( - "fmt" - "reflect" -) - -type DynSsz struct { - typesWithSpecVals map[reflect.Type]uint8 - SpecValues map[string]any - NoFastSsz bool -} - -const ( - unknownSpecValued uint8 = iota - noSpecValues - hasSpecValues -) - -func NewDynSsz(specs map[string]any) *DynSsz { - if specs == nil { - specs = map[string]any{} - } - return &DynSsz{ - typesWithSpecVals: map[reflect.Type]uint8{}, - SpecValues: specs, - } -} - -func (d *DynSsz) MarshalSSZ(source any) ([]byte, error) { - sourceType := reflect.TypeOf(source) - sourceValue := reflect.ValueOf(source) - - size, err := d.getSszValueSize(sourceType, sourceValue) - if err != nil { - return nil, err - } - - buf := make([]byte, size) - newBuf, err := d.marshalType(sourceType, sourceValue, buf[:0], []sszSizeHint{}, 0) - if err != nil { - return nil, err - } - - if len(newBuf) != size { - return nil, fmt.Errorf("ssz length does not match expected length (expected: %v, got: %v)", size, len(newBuf)) - } - - return newBuf, nil -} - -func (d *DynSsz) MarshalSSZTo(source any, buf []byte) ([]byte, error) { - sourceType := reflect.TypeOf(source) - sourceValue := reflect.ValueOf(source) - - newBuf, err := d.marshalType(sourceType, sourceValue, buf, []sszSizeHint{}, 0) - if err != nil { - return nil, err - } - - return newBuf, nil -} - -func (d *DynSsz) SizeSSZ(source any) (int, error) { - sourceType := reflect.TypeOf(source) - sourceValue := reflect.ValueOf(source) - - return d.getSszValueSize(sourceType, sourceValue) -} - -func (d *DynSsz) UnmarshalSSZ(target any, ssz []byte) error { - targetType := reflect.TypeOf(target) - targetValue := reflect.ValueOf(target) - - consumedBytes, err := d.unmarshalType(targetType, targetValue, ssz, []sszSizeHint{}, 0) - if err != nil { - return err - } - - if consumedBytes != len(ssz) { - return fmt.Errorf("did not consume full ssz range (consumed: %v, ssz size: %v)", consumedBytes, len(ssz)) - } - - return nil -} diff --git a/ssz/marshal.go b/ssz/marshal.go deleted file mode 100644 index 8d32d9e9..00000000 --- a/ssz/marshal.go +++ /dev/null @@ -1,270 +0,0 @@ -package ssz - -import ( - "encoding/binary" - "fmt" - "reflect" - - fastssz "github.com/ferranbt/fastssz" -) - -func (d *DynSsz) marshalType(sourceType reflect.Type, sourceValue reflect.Value, buf []byte, sizeHints []sszSizeHint, idt int) ([]byte, error) { - if sourceType.Kind() == reflect.Ptr { - sourceType = sourceType.Elem() - sourceValue = sourceValue.Elem() - } - - //fmt.Printf("%stype: %s\t kind: %v\n", indent(idt), sourceType.Name(), sourceType.Kind()) - - switch sourceType.Kind() { - case reflect.Struct: - usedFastSsz := false - - hasSpecVals := d.typesWithSpecVals[sourceType] - if hasSpecVals == unknownSpecValued && !d.NoFastSsz { - hasSpecVals = noSpecValues - if sourceValue.Addr().Type().Implements(sszMarshallerType) { - _, hasSpecVals2, err := d.getSszSize(sourceType, sizeHints) - if err != nil { - return nil, err - } - - if hasSpecVals2 { - hasSpecVals = hasSpecValues - } - } - - //fmt.Printf("%s fastssz for type %s: %v\n", indent(idt), sourceType.Name(), hasSpecVals) - d.typesWithSpecVals[sourceType] = hasSpecVals - } - if hasSpecVals == noSpecValues && !d.NoFastSsz { - marshaller, ok := sourceValue.Addr().Interface().(fastssz.Marshaler) - if ok { - newBuf, err := marshaller.MarshalSSZTo(buf) - if err != nil { - return nil, err - } - buf = newBuf - usedFastSsz = true - } - } - - if !usedFastSsz { - newBuf, err := d.marshalStruct(sourceType, sourceValue, buf, idt) - if err != nil { - return nil, err - } - buf = newBuf - } - case reflect.Array: - newBuf, err := d.marshalArray(sourceType, sourceValue, buf, sizeHints, idt) - if err != nil { - return nil, err - } - buf = newBuf - case reflect.Slice: - newBuf, err := d.marshalSlice(sourceType, sourceValue, buf, sizeHints, idt) - if err != nil { - return nil, err - } - buf = newBuf - case reflect.Bool: - buf = fastssz.MarshalBool(buf, sourceValue.Bool()) - case reflect.Uint8: - buf = fastssz.MarshalUint8(buf, uint8(sourceValue.Uint())) - case reflect.Uint16: - buf = fastssz.MarshalUint16(buf, uint16(sourceValue.Uint())) - case reflect.Uint32: - buf = fastssz.MarshalUint32(buf, uint32(sourceValue.Uint())) - case reflect.Uint64: - buf = fastssz.MarshalUint64(buf, uint64(sourceValue.Uint())) - default: - return nil, fmt.Errorf("unknown type: %v", sourceType) - } - - return buf, nil -} - -func (d *DynSsz) marshalStruct(sourceType reflect.Type, sourceValue reflect.Value, buf []byte, idt int) ([]byte, error) { - offset := 0 - startLen := len(buf) - dynamicFields := []*reflect.StructField{} - dynamicOffsets := []int{} - dynamicSizeHints := [][]sszSizeHint{} - - for i := 0; i < sourceType.NumField(); i++ { - field := sourceType.Field(i) - - fieldSize, _, sizeHints, err := d.getSszFieldSize(&field) - if err != nil { - return nil, err - } - - if fieldSize > 0 { - //fmt.Printf("%sfield %d:\t static [%v:%v] %v\t %v\n", indent(idt+1), i, offset, offset+fieldSize, fieldSize, field.Name) - - fieldValue := sourceValue.Field(i) - newBuf, err := d.marshalType(field.Type, fieldValue, buf, sizeHints, idt+2) - if err != nil { - return nil, fmt.Errorf("failed encoding field %v: %v", field.Name, err) - } - buf = newBuf - - } else { - fieldSize = 4 - buf = append(buf, 0, 0, 0, 0) - //fmt.Printf("%sfield %d:\t offset [%v:%v] %v\t %v\n", indent(idt+1), i, offset, offset+fieldSize, fieldSize, field.Name) - - dynamicFields = append(dynamicFields, &field) - dynamicOffsets = append(dynamicOffsets, offset) - dynamicSizeHints = append(dynamicSizeHints, sizeHints) - } - offset += fieldSize - } - - for i, field := range dynamicFields { - // set field offset - fieldOffset := dynamicOffsets[i] - offsetBuf := make([]byte, 4) - binary.LittleEndian.PutUint32(offsetBuf, uint32(offset)) - copy(buf[fieldOffset+startLen:fieldOffset+startLen+4], offsetBuf) - - //fmt.Printf("%sfield %d:\t dynamic [%v:]\t %v\n", indent(idt+1), field.Index[0], offset, field.Name) - - fieldValue := sourceValue.Field(field.Index[0]) - bufLen := len(buf) - newBuf, err := d.marshalType(field.Type, fieldValue, buf, dynamicSizeHints[i], idt+2) - if err != nil { - return nil, fmt.Errorf("failed decoding field %v: %v", field.Name, err) - } - buf = newBuf - offset += len(buf) - bufLen - } - - return buf, nil -} - -func (d *DynSsz) marshalArray(sourceType reflect.Type, sourceValue reflect.Value, buf []byte, sizeHints []sszSizeHint, idt int) ([]byte, error) { - - childSizeHints := []sszSizeHint{} - if len(sizeHints) > 1 { - childSizeHints = sizeHints[1:] - } - - fieldType := sourceType.Elem() - fieldIsPtr := fieldType.Kind() == reflect.Ptr - if fieldIsPtr { - fieldType = fieldType.Elem() - } - - arrLen := sourceType.Len() - if fieldType == byteType { - // shortcut for performance: use append on []byte arrays - buf = append(buf, sourceValue.Bytes()...) - } else { - for i := 0; i < arrLen; i++ { - itemVal := sourceValue.Index(i) - if fieldIsPtr { - itemVal = itemVal.Elem() - } - - newBuf, err := d.marshalType(fieldType, itemVal, buf, childSizeHints, idt+2) - if err != nil { - return nil, err - } - buf = newBuf - } - } - - return buf, nil -} - -func (d *DynSsz) marshalSlice(sourceType reflect.Type, sourceValue reflect.Value, buf []byte, sizeHints []sszSizeHint, idt int) ([]byte, error) { - childSizeHints := []sszSizeHint{} - if len(sizeHints) > 1 { - childSizeHints = sizeHints[1:] - } - - fieldType := sourceType.Elem() - fieldIsPtr := fieldType.Kind() == reflect.Ptr - if fieldIsPtr { - fieldType = fieldType.Elem() - } - - isDynSlice := false - if len(sizeHints) > 1 && sizeHints[1].dynamic { - isDynSlice = true - } else { - size, _, err := d.getSszSize(fieldType, childSizeHints) - if err != nil { - return nil, err - } - if size < 0 { - isDynSlice = true - } - } - - if isDynSlice { - return d.marshalDynamicSlice(sourceType, sourceValue, buf, childSizeHints, idt) - } - - if fieldType == byteType { - // shortcut for performance: use append on []byte arrays - buf = append(buf, sourceValue.Bytes()...) - } else { - sliceLen := sourceValue.Len() - for i := 0; i < sliceLen; i++ { - itemVal := sourceValue.Index(i) - if fieldIsPtr { - itemVal = itemVal.Elem() - } - - newBuf, err := d.marshalType(fieldType, itemVal, buf, childSizeHints, idt+2) - if err != nil { - return nil, err - } - buf = newBuf - } - } - - return buf, nil -} - -func (d *DynSsz) marshalDynamicSlice(sourceType reflect.Type, sourceValue reflect.Value, buf []byte, sizeHints []sszSizeHint, idt int) ([]byte, error) { - sliceLen := sourceValue.Len() - startOffset := len(buf) - offsetBuf := make([]byte, 4*sliceLen) - buf = append(buf, offsetBuf...) - - fieldType := sourceType.Elem() - fieldIsPtr := fieldType.Kind() == reflect.Ptr - if fieldIsPtr { - fieldType = fieldType.Elem() - } - - offset := 4 * sliceLen - bufLen := len(buf) - - for i := 0; i < sliceLen; i++ { - itemVal := sourceValue.Index(i) - if fieldIsPtr { - itemVal = itemVal.Elem() - } - - newBuf, err := d.marshalType(fieldType, itemVal, buf, sizeHints, idt+2) - if err != nil { - return nil, err - } - newBufLen := len(newBuf) - buf = newBuf - - offsetBuf := make([]byte, 4) - binary.LittleEndian.PutUint32(offsetBuf, uint32(offset)) - copy(buf[startOffset+(i*4):startOffset+((i+1)*4)], offsetBuf) - - offset += newBufLen - bufLen - bufLen = newBufLen - } - - return buf, nil -} diff --git a/ssz/specvals.go b/ssz/specvals.go deleted file mode 100644 index 2a1b3199..00000000 --- a/ssz/specvals.go +++ /dev/null @@ -1,43 +0,0 @@ -package ssz - -import "fmt" - -func (d *DynSsz) getSpecValue(name string) (bool, uint64, error) { - - switch name { - // there are some calculated values, but adding a parser & dynamic calculations for these seems a bit overkill - case "SYNC_COMMITTEE_SIZE/8": - ok, val, err := d.getSpecValue("SYNC_COMMITTEE_SIZE") - if ok { - return ok, val / 8, err - } - case "SYNC_COMMITTEE_SIZE/SYNC_COMMITTEE_SUBNET_COUNT": - ok1, val1, err1 := d.getSpecValue("SYNC_COMMITTEE_SIZE") - ok2, val2, err2 := d.getSpecValue("SYNC_COMMITTEE_SUBNET_COUNT") - if err1 != nil { - return false, 0, err1 - } - if err2 != nil { - return false, 0, err2 - } - if ok1 && ok2 { - return true, val1 / val2, nil - } - case "DEPOSIT_CONTRACT_TREE_DEPTH+1": - ok, val, err := d.getSpecValue("DEPOSIT_CONTRACT_TREE_DEPTH") - if ok { - return ok, val + 1, err - } - default: - specVal := d.SpecValues[name] - if specVal != nil { - specInt, ok := specVal.(uint64) - if !ok { - return false, 0, fmt.Errorf("value is not uint64") - } - return true, specInt, nil - } - - } - return false, 0, nil -} diff --git a/ssz/sszsize.go b/ssz/sszsize.go deleted file mode 100644 index aaa29f4f..00000000 --- a/ssz/sszsize.go +++ /dev/null @@ -1,246 +0,0 @@ -package ssz - -import ( - "fmt" - "reflect" - "strconv" - "strings" -) - -type sszSizeHint struct { - size uint64 - dynamic bool - specval bool -} - -func (d *DynSsz) getSszSizeTag(field *reflect.StructField) ([]sszSizeHint, error) { - sszSizes := []sszSizeHint{} - - if fieldSszSizeStr, fieldHasSszSize := field.Tag.Lookup("ssz-size"); fieldHasSszSize { - for _, sszSizeStr := range strings.Split(fieldSszSizeStr, ",") { - sszSize := sszSizeHint{} - - if sszSizeStr == "?" { - sszSize.dynamic = true - } else { - sszSizeInt, err := strconv.ParseUint(sszSizeStr, 10, 32) - if err != nil { - return sszSizes, fmt.Errorf("error parsing ssz-size tag for '%v' field: %v", field.Name, err) - } - sszSize.size = sszSizeInt - } - - sszSizes = append(sszSizes, sszSize) - } - } - - fieldDynSszSizeStr, fieldHasDynSszSize := field.Tag.Lookup("dynssz-size") - if fieldHasDynSszSize { - for i, sszSizeStr := range strings.Split(fieldDynSszSizeStr, ",") { - sszSize := sszSizeHint{} - - if sszSizeStr == "?" { - sszSize.dynamic = true - } else if sszSizeInt, err := strconv.ParseUint(sszSizeStr, 10, 32); err == nil { - sszSize.size = sszSizeInt - } else { - ok, specVal, err := d.getSpecValue(sszSizeStr) - if err != nil { - return sszSizes, fmt.Errorf("error parsing dynssz-size tag for '%v' field (%v): %v", field.Name, sszSizeStr, err) - } - if ok { - // dynamic value from spec - sszSize.size = specVal - sszSize.specval = true - } else { - // unknown spec value? fallback to fastssz - break - } - } - - if sszSizes[i].size != sszSize.size { - sszSizes[i] = sszSize - } - } - } - - return sszSizes, nil -} - -func (d *DynSsz) getSszSize(targetType reflect.Type, sizeHints []sszSizeHint) (int, bool, error) { - staticSize := 0 - hasSpecValue := false - isDynamicSize := false - - childSizeHints := []sszSizeHint{} - if len(sizeHints) > 1 { - childSizeHints = sizeHints[1:] - } - - if targetType.Kind() == reflect.Ptr { - targetType = targetType.Elem() - } - - switch targetType.Kind() { - case reflect.Struct: - for i := 0; i < targetType.NumField(); i++ { - field := targetType.Field(i) - size, hasSpecVal, _, err := d.getSszFieldSize(&field) - if err != nil { - return 0, false, err - } - if size < 0 { - isDynamicSize = true - } - if hasSpecVal { - hasSpecValue = true - } - staticSize += size - } - case reflect.Array: - arrLen := targetType.Len() - fieldType := targetType.Elem() - size, hasSpecVal, err := d.getSszSize(fieldType, childSizeHints) - if err != nil { - return 0, false, err - } - if size < 0 { - isDynamicSize = true - } - if hasSpecVal { - hasSpecValue = true - } - staticSize += size * arrLen - case reflect.Slice: - fieldType := targetType.Elem() - size, hasSpecVal, err := d.getSszSize(fieldType, childSizeHints) - if err != nil { - return 0, false, err - } - if size < 0 { - isDynamicSize = true - } - if hasSpecVal || (len(sizeHints) > 0 && sizeHints[0].specval) { - hasSpecValue = true - } - - if len(sizeHints) > 0 && sizeHints[0].size > 0 { - staticSize += size * int(sizeHints[0].size) - } else { - isDynamicSize = true - } - case reflect.Bool: - staticSize = 1 - case reflect.Uint8: - staticSize = 1 - case reflect.Uint16: - staticSize = 2 - case reflect.Uint32: - staticSize = 4 - case reflect.Uint64: - staticSize = 8 - default: - return 0, false, fmt.Errorf("unhandled reflection kind in size check: %v", targetType.Kind()) - } - - if isDynamicSize { - staticSize = -1 - } - - return staticSize, hasSpecValue, nil -} - -func (d *DynSsz) getSszFieldSize(targetField *reflect.StructField) (int, bool, []sszSizeHint, error) { - sszSizes, err := d.getSszSizeTag(targetField) - if err != nil { - return 0, false, nil, err - } - - size, hasSpecVal, err := d.getSszSize(targetField.Type, sszSizes) - return size, hasSpecVal, sszSizes, err -} - -func (d *DynSsz) getSszValueSize(targetType reflect.Type, targetValue reflect.Value) (int, error) { - staticSize := 0 - - if targetType.Kind() == reflect.Ptr { - targetType = targetType.Elem() - targetValue = targetValue.Elem() - } - - switch targetType.Kind() { - case reflect.Struct: - for i := 0; i < targetType.NumField(); i++ { - field := targetType.Field(i) - fieldValue := targetValue.Field(i) - - fieldTypeSize, _, _, err := d.getSszFieldSize(&field) - if err != nil { - return 0, err - } - - if fieldTypeSize < 0 { - // dynamic field, add 4 bytes for offset - staticSize += 4 - } - - size, err := d.getSszValueSize(field.Type, fieldValue) - if err != nil { - return 0, err - } - - staticSize += size - } - case reflect.Array: - arrLen := targetType.Len() - if arrLen > 0 { - fieldType := targetType.Elem() - size, err := d.getSszValueSize(fieldType, targetValue.Index(0)) - if err != nil { - return 0, err - } - staticSize = size * arrLen - } - case reflect.Slice: - fieldType := targetType.Elem() - sliceLen := targetValue.Len() - - if sliceLen > 0 { - fieldTypeSize, _, err := d.getSszSize(fieldType, nil) - if err != nil { - return 0, err - } - - if fieldTypeSize < 0 { - // dyn size slice - for i := 0; i < sliceLen; i++ { - size, err := d.getSszValueSize(fieldType, targetValue.Index(i)) - if err != nil { - return 0, err - } - staticSize += size + 4 - } - } else { - size, err := d.getSszValueSize(fieldType, targetValue.Index(0)) - if err != nil { - return 0, err - } - staticSize = size * sliceLen - } - } - case reflect.Bool: - staticSize = 1 - case reflect.Uint8: - staticSize = 1 - case reflect.Uint16: - staticSize = 2 - case reflect.Uint32: - staticSize = 4 - case reflect.Uint64: - staticSize = 8 - default: - return 0, fmt.Errorf("unhandled reflection kind in size check: %v", targetType.Kind()) - } - - return staticSize, nil -} diff --git a/ssz/test/main.go b/ssz/test/main.go deleted file mode 100644 index eef4728c..00000000 --- a/ssz/test/main.go +++ /dev/null @@ -1,119 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "os" - "runtime" - "runtime/pprof" - "time" - - "github.com/attestantio/go-eth2-client/spec/deneb" - "github.com/attestantio/go-eth2-client/ssz" - - _ "net/http/pprof" -) - -func main() { - body, _ := ioutil.ReadFile("block-min.ssz") - - d := ssz.NewDynSsz(map[string]any{ - "SYNC_COMMITTEE_SIZE": uint64(32), - "SYNC_COMMITTEE_SUBNET_COUNT": uint64(4), - "EPOCHS_PER_HISTORICAL_VECTOR": uint64(64), - "SLOTS_PER_HISTORICAL_ROOT": uint64(64), - }) - d.NoFastSsz = true - - test1(body) - test2(d, body) - - f, _ := os.Create("mem.pprof") - pprof.WriteHeapProfile(f) - f.Close() -} - -func printMemUsage() { - var m runtime.MemStats - runtime.ReadMemStats(&m) - // For info on each, see: https://golang.org/pkg/runtime/#MemStats - fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc)) - fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc)) - fmt.Printf("\tSys = %v MiB", bToMb(m.Sys)) - fmt.Printf("\tNumGC = %v\n", m.NumGC) -} - -func bToMb(b uint64) uint64 { - return b / 1024 / 1024 -} - -func test1(body []byte) { - start := time.Now() - defer func() { - elapsed := time.Since(start) - fmt.Printf("unmarshal time: %v\n", elapsed) - }() - - fmt.Printf("\nfastssz / go-eth2-client\n") - - t := new(deneb.SignedBeaconBlock) - err := t.UnmarshalSSZ(body) - if err != nil { - fmt.Printf("error: %v\n", err) - return - } - - runtime.GC() - printMemUsage() - - //root, _ := t.HashTreeRoot() - //fmt.Printf("state root: 0x%x\n", root) - //fmt.Printf("gvr: 0x%x\n", t.GenesisValidatorsRoot) - - _, err = t.MarshalSSZ() - if err != nil { - fmt.Printf("error: %v\n", err) - return - } -} - -func test2(d *ssz.DynSsz, body []byte) { - start := time.Now() - defer func() { - elapsed := time.Since(start) - fmt.Printf("unmarshal time: %v\n", elapsed) - }() - - fmt.Printf("\npk's dynamic ssz\n") - - t := new(deneb.SignedBeaconBlock) - err := d.UnmarshalSSZ(t, body) - if err != nil { - fmt.Printf("error: %v\n", err) - return - } - - runtime.GC() - printMemUsage() - - //root, _ := t.HashTreeRoot() - //fmt.Printf("state root: 0x%x\n", root) - //fmt.Printf("gvr: 0x%x\n", t.GenesisValidatorsRoot) - - buf, err := d.MarshalSSZ(t) - if err != nil { - fmt.Printf("error: %v\n", err) - return - } - - if len(buf) != len(body) { - fmt.Printf("size mismatch: %v / %v\n", len(buf), len(body)) - } - for i := 0; i < len(body); i++ { - if body[i] != buf[i] { - fmt.Printf("ssz mismatch: %v : %v / %v\n", i, buf[i], body[i]) - break - } - } - -} diff --git a/ssz/unmarshal.go b/ssz/unmarshal.go deleted file mode 100644 index 5335b1a5..00000000 --- a/ssz/unmarshal.go +++ /dev/null @@ -1,371 +0,0 @@ -package ssz - -import ( - "fmt" - "reflect" - - fastssz "github.com/ferranbt/fastssz" -) - -func (d *DynSsz) unmarshalType(targetType reflect.Type, targetValue reflect.Value, ssz []byte, sizeHints []sszSizeHint, idt int) (int, error) { - consumedBytes := 0 - - if targetType.Kind() == reflect.Ptr { - targetType = targetType.Elem() - if targetValue.IsNil() { - //fmt.Printf("new type %v\n", targetType.Name()) - newValue := reflect.New(targetType) - targetValue.Set(newValue) - } - targetValue = targetValue.Elem() - } - - //fmt.Printf("%stype: %s\t kind: %v\n", indent(idt), targetType.Name(), targetType.Kind()) - - switch targetType.Kind() { - case reflect.Struct: - usedFastSsz := false - - hasSpecVals := d.typesWithSpecVals[targetType] - if hasSpecVals == unknownSpecValued { - hasSpecVals = noSpecValues - if targetValue.Addr().Type().Implements(sszUnmarshallerType) { - _, hasSpecVals2, err := d.getSszSize(targetType, sizeHints) - if err != nil { - return 0, err - } - - if hasSpecVals2 { - hasSpecVals = hasSpecValues - } - } - - //fmt.Printf("%s fastssz for type %s: %v\n", indent(idt), targetType.Name(), hasSpecVals) - d.typesWithSpecVals[targetType] = hasSpecVals - } - if hasSpecVals == noSpecValues { - unmarshaller, ok := targetValue.Addr().Interface().(fastssz.Unmarshaler) - if ok { - err := unmarshaller.UnmarshalSSZ(ssz) - if err != nil { - return 0, err - } - consumedBytes = len(ssz) - usedFastSsz = true - } - } - - if !usedFastSsz { - consumed, err := d.unmarshalStruct(targetType, targetValue, ssz, idt) - if err != nil { - return 0, err - } - consumedBytes = consumed - } - case reflect.Array: - consumed, err := d.unmarshalArray(targetType, targetValue, ssz, sizeHints, idt) - if err != nil { - return 0, err - } - consumedBytes = consumed - case reflect.Slice: - consumed, err := d.unmarshalSlice(targetType, targetValue, ssz, sizeHints, idt) - if err != nil { - return 0, err - } - consumedBytes = consumed - case reflect.Bool: - targetValue.SetBool(fastssz.UnmarshalBool(ssz)) - consumedBytes = 1 - case reflect.Uint8: - targetValue.SetUint(uint64(fastssz.UnmarshallUint8(ssz))) - consumedBytes = 1 - case reflect.Uint16: - targetValue.SetUint(uint64(fastssz.UnmarshallUint16(ssz))) - consumedBytes = 2 - case reflect.Uint32: - targetValue.SetUint(uint64(fastssz.UnmarshallUint32(ssz))) - consumedBytes = 4 - case reflect.Uint64: - targetValue.SetUint(uint64(fastssz.UnmarshallUint64(ssz))) - consumedBytes = 8 - default: - return 0, fmt.Errorf("unknown type: %v", targetType) - } - - return consumedBytes, nil -} - -func (d *DynSsz) unmarshalStruct(targetType reflect.Type, targetValue reflect.Value, ssz []byte, idt int) (int, error) { - offset := 0 - dynamicFields := []*reflect.StructField{} - dynamicOffsets := []int{} - dynamicSizeHints := [][]sszSizeHint{} - - for i := 0; i < targetType.NumField(); i++ { - field := targetType.Field(i) - - fieldSize, _, sizeHints, err := d.getSszFieldSize(&field) - if err != nil { - return 0, err - } - - if fieldSize > 0 { - //fmt.Printf("%sfield %d:\t static [%v:%v] %v\t %v\n", indent(idt+1), i, offset, offset+fieldSize, fieldSize, field.Name) - - fieldSsz := ssz[offset : offset+fieldSize] - fieldValue := targetValue.Field(i) - consumedBytes, err := d.unmarshalType(field.Type, fieldValue, fieldSsz, sizeHints, idt+2) - if err != nil { - return 0, fmt.Errorf("failed decoding field %v: %v", field.Name, err) - } - if consumedBytes != fieldSize { - return 0, fmt.Errorf("struct field did not consume expected ssz range (consumed: %v, expected: %v)", consumedBytes, fieldSize) - } - - } else { - fieldSize = 4 - fieldOffset := fastssz.ReadOffset(ssz[offset : offset+fieldSize]) - //fmt.Printf("%sfield %d:\t offset [%v:%v] %v\t %v \t %v\n", indent(idt+1), i, offset, offset+fieldSize, fieldSize, field.Name, fieldOffset) - - dynamicFields = append(dynamicFields, &field) - dynamicOffsets = append(dynamicOffsets, int(fieldOffset)) - dynamicSizeHints = append(dynamicSizeHints, sizeHints) - } - offset += fieldSize - } - dynamicFieldCount := len(dynamicFields) - for i, field := range dynamicFields { - var endOffset int - startOffset := dynamicOffsets[i] - if i < dynamicFieldCount-1 { - endOffset = dynamicOffsets[i+1] - } else { - endOffset = len(ssz) - } - - //fmt.Printf("%sfield %d:\t dynamic [%v:%v]\t %v\n", indent(idt+1), field.Index[0], startOffset, endOffset, field.Name) - - var fieldSsz []byte - if endOffset > startOffset { - fieldSsz = ssz[startOffset:endOffset] - } else { - fieldSsz = []byte{} - } - - fieldValue := targetValue.Field(field.Index[0]) - consumedBytes, err := d.unmarshalType(field.Type, fieldValue, fieldSsz, dynamicSizeHints[i], idt+2) - if err != nil { - return 0, fmt.Errorf("failed decoding field %v: %v", field.Name, err) - } - if consumedBytes != endOffset-startOffset { - return 0, fmt.Errorf("struct field did not consume expected ssz range (consumed: %v, expected: %v)", consumedBytes, endOffset-startOffset) - } - - offset += consumedBytes - } - - return offset, nil -} - -func (d *DynSsz) unmarshalArray(targetType reflect.Type, targetValue reflect.Value, ssz []byte, sizeHints []sszSizeHint, idt int) (int, error) { - var consumedBytes int - - childSizeHints := []sszSizeHint{} - if len(sizeHints) > 1 { - childSizeHints = sizeHints[1:] - } - - fieldType := targetType.Elem() - fieldIsPtr := fieldType.Kind() == reflect.Ptr - if fieldIsPtr { - fieldType = fieldType.Elem() - } - - arrLen := targetType.Len() - if fieldType == byteType { - // shortcut for performance: use copy on []byte arrays - reflect.Copy(targetValue, reflect.ValueOf(ssz[0:arrLen])) - consumedBytes = arrLen - } else { - offset := 0 - itemSize := len(ssz) / arrLen - for i := 0; i < arrLen; i++ { - var itemVal reflect.Value - if fieldIsPtr { - //fmt.Printf("new array item %v\n", fieldType.Name()) - itemVal = reflect.New(fieldType).Elem() - targetValue.Index(i).Set(itemVal.Addr()) - } else { - itemVal = targetValue.Index(i) - } - - itemSsz := ssz[offset : offset+itemSize] - - consumed, err := d.unmarshalType(fieldType, itemVal, itemSsz, childSizeHints, idt+2) - if err != nil { - return 0, err - } - if consumed != itemSize { - return 0, fmt.Errorf("unmarshalling array item did not consume expected ssz range (consumed: %v, expected: %v)", consumed, itemSize) - } - - offset += itemSize - } - - consumedBytes = offset - } - - return consumedBytes, nil -} - -func (d *DynSsz) unmarshalSlice(targetType reflect.Type, targetValue reflect.Value, ssz []byte, sizeHints []sszSizeHint, idt int) (int, error) { - var consumedBytes int - - childSizeHints := []sszSizeHint{} - if len(sizeHints) > 1 { - childSizeHints = sizeHints[1:] - } - - fieldType := targetType.Elem() - fieldIsPtr := fieldType.Kind() == reflect.Ptr - if fieldIsPtr { - fieldType = fieldType.Elem() - } - - sliceLen := 0 - sszLen := len(ssz) - - if len(sizeHints) > 0 && sizeHints[0].size > 0 { - sliceLen = int(sizeHints[0].size) - } else if len(sizeHints) > 1 && sizeHints[1].size > 0 { - ok := false - sliceLen, ok = fastssz.DivideInt(sszLen, int(sizeHints[1].size)) - if !ok { - return 0, fmt.Errorf("invalid slice length, expected multiple of %v, got %v", sizeHints[1], sszLen) - } - } else { - size, _, err := d.getSszSize(fieldType, childSizeHints) - if err != nil { - return 0, err - } - - if size > 0 { - ok := false - sliceLen, ok = fastssz.DivideInt(sszLen, size) - if !ok { - return 0, fmt.Errorf("invalid slice length, expected multiple of %v, got %v", size, sszLen) - } - } - } - - if sliceLen == 0 && len(ssz) > 0 { - // dynamic size slice - return d.unmarshalDynamicSlice(targetType, targetValue, ssz, childSizeHints, idt) - } - - //fmt.Printf("new slice %v %v\n", fieldType.Name(), sliceLen) - newValue := reflect.MakeSlice(targetType, sliceLen, sliceLen) - targetValue.Set(newValue) - - if fieldType == byteType { - // shortcut for performance: use copy on []byte arrays - reflect.Copy(newValue, reflect.ValueOf(ssz[0:sliceLen])) - consumedBytes = sliceLen - } else { - offset := 0 - if sliceLen > 0 { - itemSize := sszLen / sliceLen - - for i := 0; i < sliceLen; i++ { - var itemVal reflect.Value - if fieldIsPtr { - //fmt.Printf("new slice item %v\n", fieldType.Name()) - itemVal = reflect.New(fieldType).Elem() - newValue.Index(i).Set(itemVal.Addr()) - } else { - itemVal = newValue.Index(i) - } - - itemSsz := ssz[offset : offset+itemSize] - - consumed, err := d.unmarshalType(fieldType, itemVal, itemSsz, childSizeHints, idt+2) - if err != nil { - return 0, err - } - if consumed != itemSize { - return 0, fmt.Errorf("slice item did not consume expected ssz range (consumed: %v, expected: %v)", consumed, itemSize) - } - - offset += itemSize - } - } - - consumedBytes = offset - } - - return consumedBytes, nil -} - -func (d *DynSsz) unmarshalDynamicSlice(targetType reflect.Type, targetValue reflect.Value, ssz []byte, sizeHints []sszSizeHint, idt int) (int, error) { - firstOffset := fastssz.ReadOffset(ssz[0:4]) - sliceLen := int(firstOffset / 4) - - sliceOffsets := make([]int, sliceLen) - sliceOffsets[0] = int(firstOffset) - for i := 1; i < sliceLen; i++ { - sliceOffsets[i] = int(fastssz.ReadOffset(ssz[i*4 : (i+1)*4])) - } - - fieldType := targetType.Elem() - fieldIsPtr := fieldType.Kind() == reflect.Ptr - if fieldIsPtr { - fieldType = fieldType.Elem() - } - - for i := 0; i < sliceLen; i++ { - - } - - //fmt.Printf("new dynamic slice %v %v\n", fieldType.Name(), sliceLen) - newValue := reflect.MakeSlice(targetType, sliceLen, sliceLen) - targetValue.Set(newValue) - - offset := int(firstOffset) - if sliceLen > 0 { - for i := 0; i < sliceLen; i++ { - var itemVal reflect.Value - if fieldIsPtr { - //fmt.Printf("new slice item %v\n", fieldType.Name()) - itemVal = reflect.New(fieldType).Elem() - newValue.Index(i).Set(itemVal.Addr()) - } else { - itemVal = newValue.Index(i) - } - - startOffset := sliceOffsets[i] - endOffset := 0 - if i == sliceLen-1 { - endOffset = len(ssz) - } else { - endOffset = sliceOffsets[i+1] - } - itemSize := endOffset - startOffset - - itemSsz := ssz[startOffset:endOffset] - - consumed, err := d.unmarshalType(fieldType, itemVal, itemSsz, sizeHints, idt+2) - if err != nil { - return 0, err - } - if consumed != itemSize { - return 0, fmt.Errorf("dynamic slice item did not consume expected ssz range (consumed: %v, expected: %v)", consumed, itemSize) - } - - offset += itemSize - } - } - - return offset, nil - -} From e6830a25b6be7d229834f0665a3f0bfba2bec507 Mon Sep 17 00:00:00 2001 From: pk910 Date: Sat, 30 Mar 2024 23:38:42 +0100 Subject: [PATCH 08/18] revert go version bump --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index a833d5f9..720a243a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/attestantio/go-eth2-client -go 1.21.1 +go 1.20 require ( github.com/ferranbt/fastssz v0.1.3 From 374c61da6e596e915adceb568a7bd6d550ef1753 Mon Sep 17 00:00:00 2001 From: pk910 Date: Sun, 31 Mar 2024 03:32:16 +0200 Subject: [PATCH 09/18] remove hardcoded sync committee size checks --- spec/altair/syncaggregate.go | 6 ------ spec/altair/synccommittee.go | 9 +++------ spec/altair/synccommittee_test.go | 12 +----------- 3 files changed, 4 insertions(+), 23 deletions(-) diff --git a/spec/altair/syncaggregate.go b/spec/altair/syncaggregate.go index b8b0de96..cc00ef62 100644 --- a/spec/altair/syncaggregate.go +++ b/spec/altair/syncaggregate.go @@ -70,12 +70,6 @@ func (s *SyncAggregate) unpack(syncAggregateJSON *syncAggregateJSON) error { if err != nil { return errors.Wrap(err, "invalid value for sync committee bits") } - if len(syncCommitteeBits) < syncCommitteeSize/8 { - return errors.New("sync committee bits too short") - } - if len(syncCommitteeBits) > syncCommitteeSize/8 { - return errors.New("sync committee bits too long") - } s.SyncCommitteeBits = syncCommitteeBits if syncAggregateJSON.SyncCommitteeSignature == "" { diff --git a/spec/altair/synccommittee.go b/spec/altair/synccommittee.go index 9e2e1f37..1887d608 100644 --- a/spec/altair/synccommittee.go +++ b/spec/altair/synccommittee.go @@ -25,9 +25,6 @@ import ( "github.com/pkg/errors" ) -// Altair constants. -var syncCommitteeSize = 512 - // SyncCommittee is the Ethereum 2 sync committee structure. type SyncCommittee struct { Pubkeys []phase0.BLSPubKey `ssz-size:"512,48" dynssz-size:"SYNC_COMMITTEE_SIZE,48"` @@ -70,10 +67,10 @@ func (s *SyncCommittee) UnmarshalJSON(input []byte) error { } func (s *SyncCommittee) unpack(syncCommitteeJSON *syncCommitteeJSON) error { - if len(syncCommitteeJSON.Pubkeys) != syncCommitteeSize { - return errors.New("incorrect length for public keys") + if len(syncCommitteeJSON.Pubkeys) == 0 { + return errors.New("public keys missing") } - s.Pubkeys = make([]phase0.BLSPubKey, syncCommitteeSize) + s.Pubkeys = make([]phase0.BLSPubKey, len(syncCommitteeJSON.Pubkeys)) for i := range syncCommitteeJSON.Pubkeys { pubKey, err := hex.DecodeString(strings.TrimPrefix(syncCommitteeJSON.Pubkeys[i], "0x")) if err != nil { diff --git a/spec/altair/synccommittee_test.go b/spec/altair/synccommittee_test.go index e21d5f28..a16b0ff1 100644 --- a/spec/altair/synccommittee_test.go +++ b/spec/altair/synccommittee_test.go @@ -42,17 +42,7 @@ func TestSyncCommitteeJSON(t *testing.T) { { name: "PubKeysMissing", input: []byte(`{"pubkeys":[],"aggregate_pubkey":"0xab964f788f3b0fa9d9345804f3b8d8fe01cac12b0b0a0168325b6e151c1475b929aa1c0957e1a801bb4725ed17a41dc8"}`), - err: "incorrect length for public keys", - }, - { - name: "PubKeysShort", - input: []byte(`{"pubkeys":["0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b","0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b","0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e","0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e","0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34","0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373","0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac","0xa6d310dbbfab9a22450f59993f87a4ce5db6223f3b5f1f30d2c4ec718922d400e0b3c7741de8e59960f72411a0ee10a7","0x9893413c00283a3f9ed9fd9845dda1cea38228d22567f9541dccc357e54a2d6a6e204103c92564cbc05f4905ac7c493a","0x876dd4705157eb66dc71bc2e07fb151ea53e1a62a0bb980a7ce72d15f58944a8a3752d754f52f4a60dbfc7b18169f268","0xaec922bd7a9b7b1dc21993133b586b0c3041c1e2e04b513e862227b9d7aecaf9444222f7e78282a449622ffc6278915d","0x9314c6de0386635e2799af798884c2ea09c63b9f079e572acc00b06a7faccce501ea4dfc0b1a23b8603680a5e3481327","0x903e2989e7442ee0a8958d020507a8bd985d3974f5e8273093be00db3935f0500e141b252bd09e3728892c7a8443863c","0x84398f539a64cbe01cfcd8c485ea51cd6657b94df93ee9b5dc61e1f18f69da6ca9d4dba63c956a81c68d5d4d4277a60f","0x872c61b4a7f8510ec809e5b023f5fdda2105d024c470ddbbeca4bc74e8280af0d178d749853e8f6a841083ac1b4db98f","0x8f467e5723deac7659e1ca273e28410cbaa6d495ab66ae77014f4cd21c64b6b5ab9987c9b5537fe0279bd063fe609be7","0x8dde8306920812b32def3b663f7c540b49180345d3bcb8d3770790b7dc80030ebc06497feebd1bcf017d918f00bfa88f","0xab8d3a9bcc160e518fac0756d3e192c74789588ed4a2b1debf0c78f78479ca8edb05b12ce21103076df6af4eb8756ff9","0x8d5d3672a233db513df7ad1e8beafeae99a9f0199ed4d949bbedbb6f394030c0416bd99b910e14f73c65b6a11fe6b62e","0xa1c76af1545d7901214bb6be06be5d9e458f8e989c19373a920f0018327c83982f6a2ac138260b8def732cb366411ddc","0x8dd74e1bb5228fc1fca274fda02b971c1003a4f409bbdfbcfec6426bf2f52addcbbebccdbf45eee6ae11eb5b5ee7244d","0x954eb88ed1207f891dc3c28fa6cfdf8f53bf0ed3d838f3476c0900a61314d22d4f0a300da3cd010444dd5183e35a593c","0xaf344fce60dbd5fb850070e6e76a065e1a32485245ef4f413135a86ae703da88407c5d01c71f6bb06a151ff96cca7191","0xae241af60691fda1cf8ca44d49573c55818c53b6141800cca2d488b9a3fba71c0f869179fff50c084657831fbeb42bf4","0x96746aaba64dc87835ba709332f4d5d7837ada092b439c49d251aecf92aab5dc132e917bf6f59799bc093f976a7bc021","0xb9d1d914df3d4565465c3fd52b5b96e637f9980570cabf5b5d4aadf5a329ac36ad672819d997e735f5052e28b1f0c104","0x963528adb5322c2e2c54dc296ffddd2861bb103cbf64646781dfa8a3c2d8a8eda7079d2b3e95600028c44365afbf8879","0xb245d63d3f9d8ea1807a629fcb1b328cb4d542f35a3d5bc478be0df389dddd712fc4c816ba3fede9a96320ae6b24a7d8","0xa98ed496c2f464226500a6ce04602ff9ef133ed6316f372f6c744aee165149f7e578b12780e0eacec307ae6907351d99","0xae00fc3de831b09661a0ac02873c45c84cb2b58cffb6430a3f607e4c3fa1e0932397f11307cd169cdc6f79c463527260","0xa4855c83d868f772a579133d9f23818008417b743e8447e235d8eb78b1d8f8a9f63f98c551beb7de254400f89592314d","0xa9cf360aa15fb1d1d30ee2b578dc5884823c19661886ae8b892775ccb3bd96b7d7345569a2aa0b14e4d015c54a6a0c54","0xaef9162ee6f29ee82fbfe387756d84f9ac472eb8709217aaf28f5ef0ea273f6210e531496470b30d2b7747216e3672d5","0xb7e6e187ed813d950a9a17d1e70c03e4de2903596c4c5ff326848515c985deee38198efebc265300cd4f1d6bd7b5d264","0x81054bd51ce57a8415f0c8e0f2fbf94f5a8464552baa33263c20a4da062e5ed994a4d32c171106d2008cd063f48f6fe2","0xaecc56f2b1c4011d450214d3e1254479d583a6a5c2c06fbc049512731f76227d140df9f36a3f76b4ccb4df1342403573","0x9243ef5ed3bd28892d1ef4f7aaf29faeb9c0e725673cd38e308bd756f20a9ee09de5cd9822e5e77bd03b734ef8a92695","0x925b1fb57c06b5668567bd5aa196531032d6f8918dd4f702017c11b59288e3bdb98e3820ac22780f73580a4119de4bbc","0x9648b83a4f09b4ca2021f0c193c5c41df1465715761bca52671ca790a3e92d67686b97b3d54c6110409779df887bd9c6","0xa34febc12af07316580b480364f90a76313ccce7927bbe263e27ea270853b02ad4d1428caf55363f3ebebac622cb9fd6","0xb8cd1cef89aa1567a6058957442a698cf1b267130606f749451152959a5dfb50d243890d4adc2c3309f7696d54af1260","0x92a93728c252a45ef587ca53a037593912599d82e2b8aa1b734b99d500a0ac8c142092ea8b3c2c34a28dc8ddf337a249","0xb7ee0ef26144de04d9cc80864b869b7ecafbf1b7c0050403cc3c3b514368713b8bb708c464568a18c837e1fd21d09063","0xafc0fa2ed6a270de6122a19d4600380b7f9b5e974d16f095f1702f55792ecab0128b155a69f17ad64a6de0a7063642ec","0xa5869ba554d1432b09ee677c117511291b9901f169e870831f457caa6ccfab376cb1fe33813bdb495cf4afec9ea35fdf","0x92f43d79d9f488010b310a54f3fc2e7f4be191ca06d93e588c30c8abf59a52190e060b285ac626eb13cd95bbcc3a0a2a","0x9698d9519a02b64f230e5a2520401799c2ca7d69ab23a6d9817943147264bf00d409264b928718245efff4f7ee97dd5c","0xa852816b8e463178eea5acebb4b86d0acb6d8c6812cf313296bd271ea4d2fd89d281e5fc296df4df49019169bdf96922","0x8a298ee1ac0466ecaa04d5798048c6e192409af63217f32fd7e07794cfcdcd8deca055b9782dd1ad45a578a9ec10606c","0xae4d49364e4a36760cc74a675500055b9aed99bc19d31abb953ea156bb5a76dcf36769d15341b850114a30ffc8057780","0xb397692ccbf442bfe078174c85dbad7fd605e4ff1caf2904b31e4a4c79d6444813ad9b2093ac8fbd4dd59ec7a4c8c006","0x87c9f7605d07550b46c79add5ea4e39de5014c03833669257bd6666b7ec838f53800104779940d8cdd884275a0f6a3ef","0xb08f7feb86786c37661afb9951a959c9b465fd11ca98fcbc908fcf49144084051f6c363e2eb4459da2c2d03d84175692","0xa48cc260df1df875176cb17493a5b53d669c091da74d5075acb8952a641b1b7ef68d01f009c1a365d2fa80937c79dd6b","0xac9f4df3f20a16a9fefad08817fcbc9a6ee17f7512db006414b4aa6f234c2313585ef72c5776df55fa6284af4bc3f631","0x94f0c8535601596eb2165adb28ebe495891a3e4ea77ef501e7790cccb281827d377a5a8d4c200e3595d3f38f8633b480","0xb5bb0162a4f27d1bab4c7dc3d20f5a75d6ee98c56bcd309a1f0f307685ad47ffb8a35bfdf8431b9b954b59662a74c478","0x8826e820179fd321819e78ffee16f50ac528db2da71ad8c269f60b878bc4887c79c0545b3d750e86e490d5ba9083cb70","0x92977e71396633d442f61e16a0cfcf8ffad0af93c9f1b7fdf4f7ccb816de052925fc192922d6252d325ef9fa2e0595d2","0x91ae4686b0d20470409f020eaca826c3efc6c1926ed25d05e6f0f7916391ec89c2341917277c437ac8fffffe94b68111","0x8a0d241955104bedacb3b829162f2b457915c2beb9018ede8ef8ea80f401b471c42354358da9e62b51c38d54263a78a9","0x80a2be2c7dbce8ddc2eba03522697587c375a5a9e92d4b31ed9e3c34bee047095d93e3c70b1662b3faa301f5b19978e5","0x86a73886aa0114bbdbba346cb7c07376c81b549a4802c24d98ebbc54a6a1b5d2ac874ef657cfb27c3644fcb85f97a2b5","0xa98c264dfc3bc3ed635df5dbfd54909e77600cd68480ec201d9f5c416580591daaa9735b04743e10e7fc6370a8189775","0x8bb7aa61aa8bbd2b7825d28c340da89b625381232dcf2742276b4e3a2e4a0f42ef68794fdf005d94014636732fba2f40","0x8bb9e1693eab1496d7583bf22fb1f2a475934c63b4d94118940617aa187bc277f738223e0ec1ce8a5566035d9bcc5470","0xafe6eface52fb6de91055a81abf9aa6e42ce2ef36fd8ae0d09aec6e5d8bd40a065dfccda6104af94df3f7a5854559ef4","0xaa241b2afbb33f92a5d281aec9c8bac8997c1dddc051455fc0f334de48320f160b5029b552495aed21ed9ce252aab499","0x974b2aed17665e51c1c091998ca9649875330947de3d2733a5bd2eda69b0c593cdac2e416993a87f9a17aec1ccdc2368","0xa3177a98f653cea646f525f0f13348efb27e0d3d0cd824704c91d8d959096d259c9e577298f444acc629920c9619be50","0xa8a18565733e70663c77bc0c80e08f50de908cc048152f1e7dae85d8cc218afbdd337d7d33a44e25400be2f06907c64a","0x902ff56a7a4c5b6cc57708ea7b0b72cb54e4b821c95373f503648185f15208f6ca6281677fa0ecc14f911d7b7ca04f4e","0x98f011f9a4dff94eb0352ff6e21b7df45e2a112bd5d789b5729111b89b368e7ed554e4d1c16b72f4d105090173cafed2","0xabef42538a17a55804b634aac9d211b92b5768c4cc1263342ca287323bb3d5c768080451d1b5d652e9f8646fbb35f57c","0xa8e3c2d3ac4e0e3c83380577ff7b7b5b2a98571e0d04ddebc0a6c472ce3bc5cc6a6733be728a0ee17da74b7691d2679d","0x98f620aadc4e58392b5b583fed96c452b54c39ba3a9fe8c277f625fae7e1317d034f732995fd88c1461463edd0f2b86d","0xa7f5d408af436d71ec7acfe9a4592679649d326c00ac92c6f3332423be30c3601d232f265078f1f2a5d6d6cde08de7d7","0xa8be337b3d0e6be415dcb037b246831f9966aacef62b69d6b609e4ff8208bc536c6473bc9fe9e3bec9a8665c8caa05c5","0x93bb1c86717fa7303f65cb8c45c9fcc8fecb88428b7cd1dd59967a132109c25ab5c97888e46c5d471ff911c573f45a34","0x815042c33c1a43c1ee58a58ee074bc93a13c23a035dedee6879730220379d0c03ff4a3829240b6c34e56feb55cd322df","0x8be11e9ead2e1bb5be7e2ec066ff83589558a5d9373666b3fc518a6a6639b3baecb87f8f34895f63e8d09d270d93ce04","0x8bf2630491d2a480ec243b00d65d76e69615e67d3df5d8c14ca7506edd8e896a9083e8ee9e4129af0f6d896a3225c08c","0x914b56f41c411fbfca9dc9763f44daf253c103b162457d07954fd0af768b5e74692b4639c22455fb81d71f7ed6144514","0x8794388915e86e4988363cdd4289ad19182209c873cbbbf5a80ff5c99f93acb839807787a77ad2b603f074405d7ed08b","0xa3862121db5914d7272b0b705e6e3c5336b79e316735661873566245207329c30f9a33d4fb5f5857fc6fd0a368186972","0x96ef954b331a534199f4f113d993a50ec7a781fc5aa2a181ea0bdbfd4c5c557abfebfcc02604d5aef52ba64afbe0ff18","0x96c8d3dd08724624017f178393d176b425dab9dfa1cc3f62c7669337446baa601e0aa261c00c76bde07ba9a1a3582c0a","0x92bd81b8e9099b9ca87a2033fdd84475752dc34a0fae0a8e50aabf4d3baff9cd45ed56508c837023944350f53dbc4ac7","0x83802cd575a3cea7e3e38fc1a73d94a9e4fdb999b8494e7929309c009d79a23edb1ba091ac02588f130e0585fb106540","0xb451eb0ff4990917aba6e3d80c34aee91ea1ce49053f38ae174cef107cb9acc595d0ca3fefcb804c9dd04510c630cabe","0xa7f711233af57440e9ea700113fc4dbaef97e7da7741dd2e38ae668a7f2685d4585d54a9e6712ff1b87c69dbb181abf7","0xaca5e4979f281b5ab0ea0f549d6dcc34989607c335e94efedeffc7e73b393f42c7b11d76144a750f82600b21d10b6777","0x984620db3658a19769475080998db9e7f5bcd4255a89a70b5ecf7db01226f213836d091a3b37eb96e4937966b094a291","0x8f1ef3639aea57fef705847e251b785bb608a848f42d9107c494cbc696be35642f6552fb83174ca2e73632568a5667f4","0x8967da3c8071ba2bf632cd40ae08fbbf0a203c47c02af1948fc232a7a743c0c0cfbe51606b89f102f2f6de7f039fb155","0x8d58f7e2e58471b46d20a66a61f4cde3c78ab6c0505517c615e08d8ef5adf59b65fa2b01ea2395c84584a6f10d6cee2f","0x8db9f236d3483af79703244c7034b5267a0546c3c840d4e91fdcdd466373d62d960553982225ca5f7666dd7375a29c19","0xb7721412ae5a793f34ac8866698b221c67ef8272eba44d3030512ec3f7ed8ffcb620b58f17809690d5276423e849827f","0x99f6e5b80dc52407f0436d3474bd5da5ff23a19cb188b933af6312d9793cbfd54f9e72596c5d481a1ed8d705b81c1f0e","0x8931cd39ec3133b6ec91f26eec4de555cd7966086b1993dfe69c2b16e80adc62ce82d353b3356d8cc249e4e2d4254122","0xad01d0f23cb74fcc4c39a2d0827d22f4722f02076196350dff5dcc6be765009c66e29001001959d77b277c2f0fba0425","0xb300303a03b8eff26a25449169d1946b208d5240f011ca6f5db23cd7f2c004b63f60afe3c9e047b67f9e4c8970c71cf0","0xaca096c7f41cfa6b9317dff26c6c96878c9e5d5eed50afde44d8df206372ad4b4c45568f6671552029f4c3509e295bef","0x87bbd5574c17dbf80463d11f812a77306f67913c510b1b234f5bd80478c7da8e69476cd6711cd1f4c0e228a4e2e99636","0x89a80c9263a21ebb9b7b99e59e53edc9ac766a55da86a52d1098d57572999ebad7cb92800b1f15be8d7c43889ab71c5d","0x802408c2a1901d316637a3ec6d20447bb9ee105c8c088510bfbcf8cda3ffa9376779f36e12e960e7efa5f2aba45e6483","0xaccc213c82702adfd5c32b24a68863f16ab6ab46947d1d7b3829bc62cd5f2a87bcd0d3ef27d442f07ad4363be9fc12f8","0xb0af0bfa83f0922e6cbfd2bc8ec19ff0f692fcb87c4e35f30e1353b342ae2fdaea6056bc2759970fc2a1f561826f564e","0xa626de0451397075bf145e720691c9d5ed92eddf1f4e48155b455aac7a8e920d042f5635c7a74fe3a9175ffbfb7ce12e","0xb0933ec64b73c49071fb92028a8e3d1ad18019e177370d335fa03c61de5d01e1a7e154812f720c44109701e2b07068b0","0x8b47707a1f563d3b1034e20be2a663587f17fece6581fca156cf660575fde4b8de4d45f1fda7ade9167b953d4c93417d","0x8ce551755078927147bae52f683f962ca09cd68e2a14dc7444f98739fe5d27e3596314d78deedc87beb705bcf9532182","0xb363a57c600a0037d54d738037358aa686e27da3ea65be95f95fc04d5736fba6338c5d544c3cf2b11262bd20e7a42dd1","0xa5e05143d5034740cb9ad524bec81678b07223989d4534ad44ffad33ee2fc73e4ee6b297b68aef9de33f98e5487467b5","0xaf14e8626e043caed52d9dfe62046eaa698f8b95d25cedc8c63e472def8b6a59e64febfa00e95568538c1a382ac91d2b","0xb41a0d9f8f19be13395aa09711b492d20eaf4a56d2360cd6daa2fd665532d852cb9224a5a39e5abff389882f961f12a6","0xb242e56475dca34fe92de09daee3951d647c04ed7a483a5c5c5613676f5ca88d54ec64d1aee81fb0f085aa67c88ee6db","0x894798d09babc765b3ba22473d820465e713c1d7f78f3eaeade3d957bd412a742f498a9b91e55cba8e08c36c8ad4788f","0x93c65ba88f12ad22c761003cef7ffb155b9b17134ed871c0703fac60e80dbd2dd8d163bd28eba9dff88b1e9bd1ae4a76","0x8ab4d3a78c54107bd7e71a0a006cb90dec379d6d86c9b6e4b3b010ceb37236cf2566febe76f955dbf0512884215f9f86","0x982d829cab4f09be252a2c57b77c166679b7e9fdf6f5cc882462b8f4dc9a90beb303c85af56304fb79b975d3643e2ed1","0x908ad5c41ba5fc8bea0cd8f028806a823bda814fcf6c2c32b5656c42b5d3061cfb077ecde2a50bf374e055e8d5dad4c7","0xab4de8ffccf7b19aa6d7d4ccc4c82f091ebd5715b5dd6680edf9eb4f0dfc312e8999b89a78a8d4ed4512aec75a5e5906","0xb544d0df633f2334845f73a3921f2a716b9694baa6abcd7cedfa359ba3448029d5b874eef8b3f9f324f1ff4c0f997e97","0xab77bbaf0047e03ef4bb1ddaefb777f263c9dd556502f3078d51790653a59452f1455d23002e175ec5b541cb69007f8a","0xb56c50c51aa1ba14062d9a477ae78646c459bfe12fc1fa3362f0652077a0ba090a0b780ee0b58085ad2b885fa4a37d4e","0x8bc5c1b16286219f479f6d00b0b31b193811b499a86139c45ff4350d8c9b492421e854cf75fba1a0dd566e6ead8ad667","0xb7eaf282595bd590bde41f67783d12ccf7666aea2f1efbaeaa80c8478a157cf59ca7bf009e5a125163212b0b9f51c876","0xb404c5cda4dad57827e456beecf745b1ed9f2bf776ca0eb806010b80b8912b683c288b4f231bb67c29ddfcdeb16ca909","0x944c4c5147a6b263898f335d2d59177c829d55901e5a4e394c9253cfbba6f0f3ce6ac393aa7b123f7a15db2909aaa37d","0x97dfc5eb14556d1a85e34c069da71fc5e1bb5e17b421d9503f25d76a8f3cd0f2f9c5a1937e785e1c0e73edb6561dd176","0x9145e0920e276f19fe65b9ea81339a41dee6e21ca12512005701a014426322be4fe504f853d6ae48314902fe9ff50a43","0x836c4b67713b082c060003d8fc839e265c1aca7f9bb82ce07f71a459d39073ebfdca87609859c70e55a1b0e7a613b395","0xb5217af9139deb6be95a106c7651e1d8dcd8eaa04f3c6196dd52abad84c862724603686f90c7c2a985f2d75a1c8facdc","0xa38b021855057c62bac15b2de83156dc8649bad858327b10cbab68c8fa3613a3de698322826d2644652ca9ef92664cb3","0x828b5be17d71a278644b6fbe7ab5fd3a065312d1b03734e0b9d74703a566dc99815c81fc50b13725961376edc2f54405","0x956aeb449c6e00e75a7795ea552bb0a2c14e065bfc9fee78c5a337f9d0c1814045802ad4f2e3c60868e54cd381809cca","0xa0ab6917fd4c65ff95b1a5ed5f3c0d7cef103de58a90f2cc5383b4914566aa085f04e8505c862a29a0c914072746f83a","0x93e08f94b3c1e5e9e7454185c5493111db66673fa0f1ba86d7a395858a32fd2c2ccd0c4838affb453112f0e9a8e3a370","0x907c4f53d28167c96d711746d338b7428e7ffa389ec76497920c25445df3b1ce7e88648a5fa9f4e1b5d2d254938bb65a","0x987b620dd2ade22c44ac3a642d17ac9009da6c2d989028957da877e5178668216cb9ad2314a520ebeeb8b032614ca2f7","0xb4bb3db19f9162fb238ddbdbf5b8e819696e90783775249825d64767625f2b6e9c52edd859bf8afac8a87371e9100d24","0xaa083a83471b7938693e54b673d98f90340fe5cd2556b27eeb9c9069b7150e853391d47543dab155f6fdc8ab7f2e185a","0x916d306c24956c1a97678695330d240cb492062889dbfbaa6349cf53259c719ef83748b065e4a30fa6edf8a171af326b","0x89d9aef34711c5ea0787f591e4683f34727391729c0a402702a51de4d6a36a9324e1c77890a1b34c70a06d30bf9cb0c9","0xa3cc6919919abf050a3e64b6c5d826148ee3f766e6b67e7e8000645e51ebed1b9c6a20b9b7413a4eb835529cbe4f77a9","0xaa70cfdc554a8e67bbd3e6f3d2a0ef61c2a7ce1784acef01e9d7f08ee3a4723c2b7bd789c4bb687f19466a58e6e7bb34","0xa1a1b99827c25c1079d4ed035a31478a38c2141db49291d0fcd10b64eb6ee5b0d9e758a9b47f40b2092f1c150bc28e11","0x87af7702ff5e6e9a4416bbb516c3aeec7827408b75e3d1a8d420031157ba7a5a4d1eb565d29f100c5cdaddc05399bce1","0x8db57d195b1216309f3182f522ee9c6a724af5eebfc8faf058edb4e444a74f7ca9fb0f227a7960887abf8ec4697ef4d2","0x8cd26495562e8fa526dd3dd5ccf7706e0b802747a2858ca76e4be7e9188ecaaf095b7ba58cf504057c4039e990f88618","0x95d668e777610672265275332a570af04c1a6090d9caae5152b66d476a7ac895c120e68724bdf30d3a51ece24a76b225","0xb37c32301c15cf9a62fdf10ac221d751918f78ca95cf7f79b5a3828fe77c88561cdf863454133bc4bf56e6209b53d0d8","0xb923cab7abb3e0b5a8ca7b841662262014e59dd8ab24ef4513ef5fc1c85dc1860bf4fee2565a732a7df4dd73ff638403","0xa25d1dd7f5dc5ed5aaba0187d33ee72921d6455b6052c657d87e108aaeee9c31c53701e7b288ae0f9ca74cae34a1f49c","0x824904d20a5620ca46c015ff630e1e26fead9df53243354ace937f01a971916e8883687a8e5f087598c633a91d0d6fbd","0xaed2a3ef693d13698e77966b8125442ac40ee0a62e8d97f71493c966da3c8604932dcee09606c2394afed25f8ad4f31c","0x8f8ac057107bc490de273453730753b9e2b69df03917a0addbfb13c5152d93fa05702cf21d8b58ed7c08ac3295c1de3e","0x8fe63d0f0da14a975a69446571eaa08409b6b4d091c720ca26519156a1cbd9e0fd44de574d8486ff98ad4086e0d96f59","0xb249899bfe2b0b123c7a151b5041d5e994c57568a6b427e38b25f2ef04ef0c30b4577e66fa7b499ef14d8d24563ef06e","0x965ce54aa0e435602fe222441ea4ac7b227948ea37e927f9816d89d779dbeba426dc68ba6829ab8da33a565a6b879c65","0xaea84e54336d09257061a8b23f419438c2e3d2659de36b993033bb30e396d9c9ee8b6f1b66261a6a060c3ab706827afb","0xa90dfa8114a00b3fde7cdddfb2fab9a6d113500aee32f08786634bc5c99ccd7730417e4ae4a05299b62342c1ab98ada3","0x9346419f620830d6535546fe2ddd827b69156ea9c29194780c63a8f07b6fdcb0568282914ce3cc06a2ba44e2ee1a6e9e","0xa399755dad117a369409206196a9e3a1637a625dc22d0da18583827dbc487ab9a2ba6c995927df9d8560e07860ae8b0f","0xa4695dc25f6cd20e48edd948321a09ebe2884b1d6ebf622aa02a023e96f9a1d365be7f2c6668444b347aee678fc7bc5d","0xa8c0966a8c0869e28110ea5587321cb26af1bc49591fdaab24b37c77feed399439515d2aca8f2483a3d666be8b4eeef5","0xb210d799f2cc4d87df36b60fe1d7408d9e4b5124aeed740eb42227dc1f456d9e13bcecf309e068f9775996c71b55ca8d","0x83af2f04a869d856df934893edd7f15dae94ef74d78139e0556e1166e81f8ab2c294708af67f194e854946f2da4e87da","0xad69af5d2ee0d68b32e6c4ebafc348a0c509aeed7e4f5c24c236dad4a8f91129cb9f8ee521de07c8199807e36e6a84f9","0x93568c9c40bb362329367dfc26a65567481a03c35fcaab51f781c9f364b7e676cfc3d2c08633888b29715a6731dfb6b0","0x8509086b192c039cc84d145fd6a2b2cc3e3a3d46092e928cc1ca9a66dd663550a2782ab32d677785e02c23b6637df70d","0x89494e98d8cc4c763b3b138e21d6cc1c86f7eeb69315cf6a4b8b5b7018dd59e3b82c0b7c785a381ffd1b809e5bbf4625","0x8451860d32c95e30f685cf31fccb967b0cd172566ff7b7d2c5ff35130bd1232cb1a216c9f0cd355ad69a93469b78e8ba","0xb48c495c19082d892f38227bced89f7199f4e9b642bf94c7f2f1ccf29c0e6a6f54d653002513aa7cd3b56c88368797ec","0x8bd22839c85ec58af4303cde58674394247fbe1f51b4e30ebcdf86aa861ebef2ac9239aa21bd9b07fd03f28dc4806780","0xaace874118a4ea9cfec8d7979dbb4618f4833dde4cfc493a403ee5cedb67f294bcac4aaa2d626ff25f4fc7ee9fa61401","0x956851460cb809871966cc4dd44d0b58dc68a1c22110864f374cd3aca743ee63b0743999d35b473e3f95ea38a276eaea","0xb8cd27d87c94a69cecd953999908640b437f6215ddae069a1ad403f995dfde6e4ac46e5c85fdd8bd4fa655f74cc2bc80","0xae37d415dda04db4f1abcf52c080c1c7a1921a819181161c4c2c18f809cdcf695de3f0f793c78802bacc1f4a32bd921a","0xa7c674e6660a1930c546b4a7e345265a51527fbd53327f90cf7edce01ec2a9c9470c9d9f0a2e4dcfe4c0c5df4382aafa","0xb2c9669a6f3e64a5f8b37c210c88adb507ce396042921b1aefd5bf52a3089f0ab0b5695cddf9b1a1157fe5dd43558e54","0xb00c6d2cf271b167f17135bf7bd14b7df669194045eb6f09b9dec787c7b608dcd42613dab0f857fbfa3fb84792a3e63e","0xa5e5e5af2ef8b65bf9b7575606f81e99d1fa645078544b0fcd4e0b506670e6a75504e6ba4001e6cec25632633d050276","0xb7ad21b3cc61c96c4ea90e81cb5a39836f114dc477bb63da54af20f60d42dffb99aac4ae12ecb70288b1d226ca7c2522","0xb3eea1ef03b3cd28709513f691d9b7aefcb9908efc7114e20e302598cc8dfcea02fd9423045f246112e4db1bdcfa9e14","0xb0f147fdb3e17379f4933c18e6dd3e3c9e9414ed5920ab029dc5907c01f671f664e4bfde8a4bcfa273a57daeb824f695","0xae04fca0e06b256e03d4173d7f772e2106efe6f72d469243dba695179b5d2be8b61052c2844247ce49ec3b6cfd18c73d","0x98c4e0f20616fa174bb221011e731650cb841ec29305f074fdafbed1d04b761c107a854722d4a6d69d6a15f7bf85c7d0","0x8800aa633b5ab60ea1da84e04e4a2fe6fb19c1d90197791ae6212e5349d306ff58afe02d4dfad739b07171ab5757d26b","0x9474c26852bc2adfc52d093351dbf7ea822a2639d99db5b0d344e440e0ebbd1e856ae37daf3d91a05cf62f33342bd790","0x86c82451f5ea5981c9031b3871e1463b10875934eda1c2520752d03bd51e71d943037b1a902979b6821eee7bd5779f78","0x864a08f5f022ce7757cb73be7ebf54e387fb3d5d4b0371d01ed493270be3236c5bc3b1272e42d2628f8f3c000d60eeaf","0xa38e925dd3c45de24e8d73e9170168dc8206035ea711741d91a35c24fa71bb7981b89bdca545ee68e8680307a754e801","0xa626ce67a47dea646ca21759fb026c6a258cc6ea8db330ee68cbd2455d1c347bbab51f3c08423eedecfa9e36920ef80e","0xaae22c365554eb37e2f402f6e6e4bfb0aa9416d8dda0a2f8ea5647ba7dd32023089f4dcc111121e56b52b1fdc29067b3","0xa5c3572c3b770214c14beb4d403d00ffa981480eb850195c99f3b6a2418cef98df28b7f1543d48a2500bfbe25e18ad80","0x8e793a86453b578e9b2f4c252e9ff18a8fb1af36fdd09d9144aea8e2b172738fde30faff3e9391d00827df5efb534821","0x969ca05ea6e49aa9b35d41c3354096f022e9a86718ac454cc8140419dd2ef5c19af37d42733a434a0e77970117ab884f","0x8b4ff71ee947785f545c017bbb9ce84c3f6a90097368cf79663b2e11acc53e18e8f7159919784f4d28282cb39a7113f7","0x984a6c8f4b7545aabbe9e0341c5ff990a05508c94e3757da474daf1d70124c8213ba2457718ec2d1fc562fc0bb36213d","0xa14cc20155f6fce0f248f9c306a32cbff425272829f7d920073c599b48168fb018c82b2aaf7cbb8b5f6449340023c37b","0x89737986b89c213367ab0fb9a4eb998d9b0b713143cc8b0f209c9355607daa4f6e6c925dac3026890e291a9480463395","0xacd8a33698c0b95294943f0642c8b8919bdfbf1e92c61f26107f0f9ad989497742b58363e3d885e4d41a3bcfcc9c073c","0x964e84e1272dcea0fd79d698c1db18e847a5abe1406ef7988e61f39e3f1ef46371be5c25b6c2bf7e53788730f702b735","0xb406b1521362c206669d15b4e5448aae2f1854c707592abc612973b4726d47edf3bcd9ecea1a4b6cffc6a9f7b039921f","0x8ca1bfff2cea25ae77249cb18146a39b9630be5947b65d15044a5e5816b6d29dac9da83504083bb8e87dbe97dfb6451f","0x8c2e07abba50e0e1c624bae0dfff418f8f00502e377840f72e067cd33917a209c525fea7dcc7c44f0195a3b9a5dabbb5","0xa4c11513391dd190b1ac0cf8a1c2c1b9c39d925b38aecb950d357283beee49ab97b1d7dfb34396bcaf1c25658fdf7713","0x92afb506a8345b325a4fc1cf1135455eac709fe1c623bd8f0972cd9e51a763cc1e80bab1f7e01976d1c4f13af3c57caa","0x978b5194d96515146754465533db2d854e58371f26e78fe0eebc5c5b65917a3611947cab3bf7fc645e3cb870e4826019","0xa3f841f04d3410b06a4b4eb31b3fd92eadcf486af60986723d34ef7b8a9908541ab6e7e0ecf421f593f86afdf8cbe894","0x81fba887a59873ac21711818cc8a63b2d4be1a69627f8c70586a56328a96aff64b880f1a07c125eda24784dfea0bacd4","0xa9da8f5d1d62844df8f6fae763aa653127d6eaad1b4d8ba0b3b3417e9c486be3cc879ebad7fb182dcb364d3a292ab07f","0xadeb5ccef7679c5d26e97ac5d2c8222058bf8b7c5eaebd31db3f3ecbb8d00987e2b921711dc6953eff6852601c57b198","0xa4e2f5a419590f3d30cbcf9cac0b4a89b636458dd6d38aa763694d4edd787056536089077d8e71cc4b182f8e87dc7916","0xa365251e868fae8780f009c14c7ddc349389230b75c79e11628b798dad880d9704a10f3358bea40f4136fe37fdec13ca","0x91ad339cd616316e79470c8695cd83b3811eb762f292c9a67c802b84e8e074ef5d208704dc1d5fb4a8343e0e44b25807","0xa2d7d0d6f85894bda115022811b35ed5689143187a911fee5bcd0d6b1c78f4db3542223f496024fb2279b8ee76b5ea79","0x80029a26a45145f67892bfb25783d04f700e8917afc2b406695d4443fc3a45ab9c2c0572c357a33a9ed3877ebc479822","0xb6c8c112c7802a29579e14b228ae6a33fd7f0a3d33d06708b0f07cf7ec18f48e5ed7d5c47e7942c2aea2d1f4dd95557b","0xad4beca6ee84273739c03792e0a2096337c92fb096f7a902e0b09b8bf38d3f67c27a00b05d3ca69a0c9a43b491e8af4b","0xa9ec8e4f705f27e6991a43ce006155825776666664d03be89929c4e5c9a01c7b759c1751e16b7a5d12084c419e97878d","0x801a35e02410c44a3d81b564980738fc5a1d4d15b887c9477c8835c9038233fceddfac4c572226599b25fe3faefa85b1","0xa38b922e79533b5fbec5f710ad90837cfce8073c982c57597027e5b6facaabc1edac06c7014fb1bcf8e11aaca4049dbb","0xaf4cb80f788305b5c22f5a16bd3f5d2f2f50a403e4171b78e267a4e2d15b14beb04735b9ec206751a8163dae9ef3e96f","0x8e0d2214a6f4364590a4acbe3db7b3757b6f2f1eee526babc383e68fee4a7c9735a672f83aff5e9384d66b2fe264c9b1","0xb110c3a2e0100ca6338d66f81c4fa6eb5cdf0aaaf839ea8e0a67645d958fba5f13bba8b66f7f9d069d571f25cdb8e47f","0x879db2b2da4652de6f12a5a9e5f8665daaffa2e4c25fc8609af45b428dd2a35244b66ac2a910dd76c0961e56c660cf59","0xa4cc78a560437549a4924c1d355e81a3467aaf9d7e7e1b4c7df6b39528345bb950c51c5316abe27f8618e5c7ca7dc5b7","0xb0959a30fabda6f21ccfff1b9a4854fbd869e767b253c2f9bc08c4cbbaa3c24f37a7124dd8e67e2b0bdf4b052c2c9873","0xa050c5180ee6cd9daef723caa6367112bc4b06636c3da59c3377e5e7b536942417a29cd5d1dad73011db4492032caff6","0x96dddc7430e5f035c0c4d005ef950eea0b3cb8188fa1db85b947bfa69745d4cc0f8ca522b3880823154796fcfedd970b","0xb1eef7970c10f8bb2a2d70f566657cc0209b198011ee3a4aaec9e7ddaf571fecc03db1042997b1554286e52ea95cce27","0x85f65540cda46d23cf0ef948b5793b46a81771b4621ffb4b98c6dfa222208ffe3215bfdd436eed5ab124969704752e18","0x8d016fd1936593cb41b3e94c01ae213a770cfcc1e94e06bf90dd77dfb8721090cd17255aeb4b4da53bc2a70257d2bc5c","0x953e4c8ef12a42ae5376ba23e06cfabf11c5e3fa773a98b487723225f1a2df60be50a54a7d5621bd85be25ddeb73af38","0x90b3bf8ea91bae7c8d0e33974c65e1ce677328030cf63111d9ee5cbf6d300c72fc033c3c70d6afc21858fb9d2964875a","0x9412476b39b4c36ba977e5aa1bda710a773b48c95a6486d0201a978eaf58c51bce7c8b37e34f3bd61322c2f7caf53bc5","0x8202a977e0d543f09f5f4b010fe308031db9c022058591b4ecc22205853f96fab8a906e31659cec3f20c23deced33fb0","0xa6071c891f8c353b0ed693c039c54f8ceaef1862c23904ecfbd88b3ca9180a52d7c4ce95bb9673e98ba6ac93a2d5b462","0xb722d39c1d7d9c5ec39961f903efbf7bfd5faa1a3af41749874b52d9a6ecf554b022beebfd42b5d4bc00ecdc726a1c69","0x98bed18337602301002525627e99e62911e6bc491e2c2bbfa2eef2f4bcf173eb60e493b74e95c3b5256555f20535694e","0xb499f66668919d5f1d82e55171c5961e78aaa70e0fab3a2ccf14aa402379ac66e05d542060e550d8a1d03796ce703a3c","0x92c237d7fb491bcf70aa4e50e71b305bcf71bf5a438b0e08f03fc4f74d5c3c9b8c823049e314d15f8266179b1a90841d","0xa1f2eb8596281b7e85285bcee8a4156140e069c6f50c02a0dd3b0f40ed62b8e15e7b9c40f6755496e13a94d91faaa194","0x8f4d945fafc936414122945190a1983192259705205fa3e92b72443a93183eb140ad527d4b1449507a18cd64764c89b8","0x98a8e7af1994e3d8f383dc4ee6d32a01077694ec93ecfd7ffbc5cd9448938a6c6d35cbbbe8e01a49fa4782f389757b06","0xa7c051843950c482ea373ca3aa30e523911ccfe061c681b16fb8a35ec6e4ff0ada5a25fb2ae70433b18913652cc3c181","0x8f14a40f502a87214891c922345fc2abc6795c28d72f9deb7ebffd7b805888222f7b1d479db1142ed013902987394cad","0x8e486d8c9ca07b6c4dc1181161ab52508b70980e9af31c97286b55be3df3701d73891bf0aecc6eb7d2e028572bb5c25a","0x91402ee72dd351a735017f11da3176ae5fce3e92369972d0eee22a45d1cc2badd77f627c4a0a9d9c480d65464442599d","0xaa5b90007d36de7c57235756d39aac060ee48e8a910f0a0c815e71414a0d53e7b0659242079253fdeb32ad18ab90beb9","0x851faec0a50c3df9918d1ab44fe7f63f8105d671d8fb83f3a59d291e6d4dc86cf47a6e9402973bfbd7db535b3dc4350b","0x933dc2f8d407d4f85a1d54953ac47a89c19808eca0d38b0ec85b376ce17c3ef1edebb518a4dce8e976155cb6561a849f","0x8f7069f51912347df8b721903bd9340ff49e9d436239ea0f4f176e360c4a91aede7657037ae00dcb08a9d7abe9b48d5a","0xb876db47bf1d1868b3a39cdba4171adde47eae91b3631dcb5c59d28cb100ecda604a446ffcb000448c462d72526ebdf1","0x9666598b3eaade229b7b255866d279009ac0b42dc55cbec207f3842d51501e2fcd318ce7d2fc40a766382703c8a0ef00","0xb2b4c1b1777970826b6683ceed5b72da7bec1f6f7cdfae6a599ae0d0d6d912098678327ee31fe383fc2b95bfed48bfce","0x91cecc34498496a68dc7630a6184b1cd7b977772a94d7d704c64284cdc14aa3f4d7c6eadb3bf62eda1a43f2f8d547a2d","0x89dc8480e9d48c7e5a39c3ced17e65170f56f86a96e4bb131e88c3d6eda3daa65265df5445e0ce52090cf34d7fd1116e","0x8219db7b86441850836ae4e27a030e8378e594e5f1d7ee08dac7bc054653d178e6949476887c83a20a213b2bf39e16f7","0xb9ea48794c02725e69d9f6435382b31b3e975de5ead999a09e13746e0ae5a63115af3a3043cd71ebc94c9b051b5b595e","0xadae379b50e15e5f80810abfc544eb28e26301438cfaf8a8a5569f9bfd76c4e653d0da710bb5d34687d47669f6999257","0xb451fc2c4236ca2393853980019f5da0e5f7d93df90bab1ae34ddb583d0ce3cdece25f23bc1736e065a1f2af1ee2bd34","0xb8c6b853d7f3766c881f4eb0c9986b800188b9f9ab40a492d49e64e8c1e98cefc27ecfe225ff9d5781c0193bca2f77e3","0x923b10adafbd70ac83cfde90a85bd38e5e919348285b311e020721bc96adc9e9b7e45f8052d1b3ef97301947cbc6d3e9","0x8860a33d75543d49ad04bdcffdfdf7fcef7228076d4e8150d80c3cda14651963544a683355e256166d995dd3f6b4ad35","0x805de41e2e03f52993f465c0cba3886c40488c0ebe7fbbbe65f016e5e6ff971efe2968e09b0d62263cde4c70f6cf8540","0xa367b7c50ce66726561d5f4190607e9c1d3feab41f624b9ecfadb6f52e1b300ef98e8913e8fffb2b65cdbb889ff5fb6b","0xaf379c89e4f4bec6b942c9e2d8fa6ccd2ec13cf421d80c987af53d5217c932483c4ed17cd1a9c9d7174e2546ab16ebb4","0xb6c5b136625178a485ee2eba1ddadc84b55e42c0e5a7ebfc8e5e2db651baf3c0a7cff6fb8e94dfccb1ca0a0d48b7496f","0xac210cfd8d8d9547120ba0a786a93318beb172471e9711b764db71376898bc28037160396e32be311a1823e585e8f524","0x8771e8df435244648533c638f725d292deaa9ef3e098ccce30255f860156f9101aea2ab56199d5a8cd2042af7ea57e33","0xa3c94a3ec9d463a4929513b426cc91887c7e09fd038314ada8e5e7a8ce204a7a20247319f91c0746de0e241550aef4bb","0xa647de716dfe7d82e529344bf832f2ac603d7067a515ebb7148fe69cc4330c1c12d3caaf16d6df3a3483574d49a296dd","0x97dae6c47e2b695734163c4e12ff709e7d63879fda8192ca26a35501dce45fd8748b5ed04519e829d61e5e7a3e379dfd","0x897c752e1ed45c3ab22146fe595fd08175a828c69e1e3243e6e1e644792b0bc979924123c0cca7dea405b074e214880e","0x90e6673aa3258396ea9b5e5d4c53b076fc93d4f408008343e44f5d4e49e408942c764d454b435be080ed8e4328ddcf1f","0xa7f7669994d4503c6390a44e7b64103861f78d60283580e19d0898948ed55a0b16b6c8fcd86e14341fd9a5974e4eda5d","0xb8ad8a758c02b9a1769a5f883a41eee5a516165cd2ae19749d60ff634f1175940ea569244830265b2f59b2aeaa434478","0x95037a05a0a6a90acadb5cc2156117378faa1c1eb79cacf3b91835e268d7855960e638dc34bbc192cc6b8ca6b942be04","0xab152bc78eada258d68785ad491422f64ffece7e462ac59ba92ca919f6e2ecb3c3707b34d6159a967b4dd7590c4321e0","0x847230d7b775a10cb13cbe8b80b7d2e5e613043af2913729fde2404485cb4dcff11fbb08487c860125c9d4828686818e","0x811f122742c9f58ceff4b9b75ef59d8a8b5553313c027e18a21f417206d72b66d225c30d9f9f5dbb648d68e537a95cd8","0x875b740b7de5cd6db43823c3dabb3e0652b132a2b0c7593383420f31c452c3e772885f083932eee347c94ff2411367fe","0xacbfea617a3cbc5df59da38133fee49b25a4a27aee878184acbd8cad6c72a2ffd5cf31812e4ded11d7a73c6c7a9a7cb8","0xaae696196c2730c93099a70860ca5efa86f84e5841e05aaeab2619a772f23eec46d4c72a31b0e458c85409b511b498a3","0xae0825786e4f5ada18f212b067a394b52e60b37c98bb22ccdf0416d27b33029678de976370eea92c384ae44bca79386c","0x95ef906a741f50b59bf8fb77c134abc0534fbe7d0c432832d2d1c0ff9bd20090b424df54ffadebb9cc43e5f3812a7968","0xac3a33ffd0eb0ecdb7baf1a5a4d8fdbd7c2e7558aa073269d2f9b7e9e5c7a1402c30efdb34fd7d268ec5f64db92a76c3","0x8b1d9ba63bdc005529f0f6e2f442e6649adcec11e0db1d643b3d3e09307cc8c5b3fb84049941b8692f10799011c246c9","0x8f9ec3c7b0f5793f3056fee53b16af2874bef12a90bd0ecf6282d55ce6ba70a07071df4e3861ad99da8753677a2a74a3","0xb083923ec58581ce049677eb0df25ff6ea0e29938881a9e03ecedf4c7482ccd25dbd2f8a15d6bbdf8eca74a74f444e40","0xa41e4e990ba7effeb504f4f0c27924c90c76ec433f2cc59d65619ce9796b80db1b2a6c3fdcd3a3b5ae798c65433ff911","0x8fb481a72fde68d6b21d0f679bcf64c9986e88acd27874cdfb4d2ae7a84e7dac89ca6afd072bdc503b15342ddc899b94","0x9792ac6f48e8f90fdabf06dd862bfa48612c72685f259f7f69ce201889daf43e220bbe3795554d1973b497360b81311d","0x8db6b709638a90a292ecc760d425bd26855a8b67e34286987f3c6aefa0811573e106f54b088b3afa8436156fb36f783e","0x93ad251e308b778815f925a6de6b11bb7f3d4d8d710cafd66cab8be0b91ef0ada350c2ca2d8f5fbc3ff4f002445680f9","0xa31e15bea68f0f555e2eb0552f74bb78a755ee77e242799cfeb8a380507d994cf24f46fd86568f46c4ecc7ddcf359ba6","0xafb329bae0ec756fd1be3ee1eac93550b77177d96558deeec2a6a131e35ccdee653189d4f5bb744f492371605c44a9bc","0xb62df9c59793d5e3a553e9f5b9da4c928105e221898f11847e7ec9a60c091a1a56e0f141d64bb5bac13d424a49798917","0x810ab821a4d4a0707e0f70eb7dbf78a528e2503749e462fda69969ef1aeee9ad2b8d37c77056bdb0feecdf206313d2e9","0x80f23973b414503e2ba0a53f67463f332b23fe5fd5466f1a770a6d548fdf4421d9370ae890b54be1cbeacb7a9e31d166","0x95ce181db92ea8695c006896d2bb9faada9e157a896cf06b5466c304ccc6b09f7b8b10044b9b0689265ee97a6388dcd7","0x8e322c2995e2472a7981466eb4b890d753b2016798cf640ed4b7ea7a3d53e5644361f404c5eec4baa1a55da860b7981c","0xb6f68789c60d1348b5e24bd6b7ccc18500be7b6ef0099895547a83f63eca37ca4f26fa3517d5bc71bc4a2fb186149179","0xb50d3fc8e36d2f2eb544c16b959b500160c2b176298e4e16ae5d928856406c86605b8ea6bd802ca1a2d1c9210d6bce61","0xa72612ca8f454d74489512d0637191bcac72124f4111f7cd52de8920ee3ea804ee895201ed74527407159220ed00712b","0xabdcd975ccfab19f10d7ec535f7c0e9e269a34f5eeb653d15ee0505f383274e5a20b3b71bdba0f369e36cea0eae1f5b1","0x83dbae1b08eea5bf0a89eb1d0b61e9e0c4e1142610ac8d88d9f3bdef550e3264b54bd47052d481738b92ffbcf6e36f67","0xb628c432d9d76dd6483ed50938fc4c369bd24b6e3c1a41cc4620f7b513148fb242a76c7577f8766a14770ae597c36aa4","0xa36425294d9fe4f803acb3ce90947ea5f20cb1c06c4899b80129d8fd7e491f0128d86f98aa987a1578ec1244ae3d5f17","0xac55318cef8cd8f015f2493d09be7556066e235f618971a3325368f3deba029bae60fba85171762827f1f70c6883a467","0x9966dc1de264da86652de12f70b4d6c7271026be0b081797589ba126108809b6264e2ec18cd59e90dd2c639bcd9986c2","0xb5a83ace1a9e683361435bb484295c11e371316800c073c8beaf1ee1900d5589966ac8266ee11b10b24f671231584302","0x8428f1acb3bf75a11ca3ff7b9fcb2af1f0c43ae22f08d4ceb586c96f97f5d999273739d348900e2424cd375e5ef68f35","0x8e73eafaa8fb6863473e55ef578c4764d9330996a62132a9329ab43f2a45ef2e68637cf48f674c8a0d127d9fb2738229","0xae451c6d18b7a14585dc96423f078be6b46742dde9be4d52907fff934956ebb2332e82c66cc2354eeb2da821e80ab7bb","0x953ecb430dfe4f91510dbb8166f07a557881c19112e41a8b1b8b0aa2c3d95c061cdff951044255a3e4df6f529302beff","0xae629cdd3ee2278a8993feb4e163a9127c4a09857981704fad31e3fbf2e7668136f2943987c7b5619d7e362d1bf9d9ee","0x963564994c2f8935ab03230c47dbd3596ca372a892a616c28ed80a582b9ca4a43e6ef58cd2fb2a3f3c03ac02eb272a82","0x893f6809ed7bfd91951ba78b29c2eed9e8147ed63f01749380a0b6bba9bfd3c7654f05d2aa77fb7a096b981745615055","0x868207372934c6e8133df3c6a1d4a993cca26a06616d8f3de0c593a4cca3005d6e1a73b41620b05a31eb44841fc20932","0xafa8898fca81793be528c433c00c9838be077b05b7fee5c82c2ff1bea10834f3aae64e2d5b8e3cb3e4a8104127f2b99e","0x9685e2fb1018a705d32745ac6bd64d7bc5861679753d5f886a9439c1f8f85cc247b392035fcae82233aa39a6be24515a","0xb41c965012fdbf74f551e0a1372202f5814cedfe541336f5954020ee2ef23043efa6baa200cbd22b34acc5462ca3e9cd","0xa8a7015ac1ac3ec6678478167302dade9eedced09f899a60decc8060f972141a88be910f959aa155cceea322f375ae72","0x83a7860b2ff27518453860637b50ed63adfbda9a2f36432e949268cdbd5a6cc10985acf9bbb57391393823d71328c85a","0xb7458d704a414e012c62a3d19c27da6b0ed9dc77dbc1a328e736043e156eef0af395853ba915bb246a2a4178febc7ad9","0x8a6785d9912cb5be712bf51c08da89f9a3c7942869176d1a24f114f430715064f48c35d37c1c1d1eb9b9322ecfdcedb0","0xb855cac3f2635d485914e4b25b953b066dd5942215b38677d16d3fa6aac5b7f8d0849398ef946674e88514fc83c42491","0xae8aa6029e2318a91b3b6ff77e2792905a690d7ad0ac1f97a7887ca4891642d267b7e208f6bddf407fd8c4e10caab2a5","0x98a5e4ffd62c3b8eb39f6230d242efb74701f42380663af26fcbf106ad1b0f02339aa6d9eb5f2f073b01f2c85062d89c","0xa7723c37795ac53e3ebc25b9dd55af10080490e872a18724b0bd3c7fecf8ab18f7d6abd1b49bc755048a3f9b1bb136ed","0x865f9a725b49135bae6c011f778bb311a514a73911924e4630a5fedac29e1b4d127308ac8b0d623e7f246c668b827f35","0xa663aaabc4aae867b7bc4feb03558f9c906be74fbd1cfa931b88191a1817c8393778ef45b5cb107cbf860e9cce540212","0x970d2002cd899a503a0a007d6b5cc6f8ea9fc7e7db1de06b5297daa7f365d066e69cfd179197229508bdf93161904330","0x81fc32376cd95ab4456f645030a9ccba182da956571ee1136916fe655c8bf08f05244e204bfbc87f696472b3cf3bab83","0xa42f4e4ec8732b5a4fbffea9e17a6c208db024f36a899f90671b1910a1dff4b18996b517050f4aacb548640bdf8fe844","0xb4368a6946801366550e764247f27c24bed3c5830a49be21ddeee79a67d71e0aff3d5cc0a9b1e18bad5c9e655ad23502","0xa4a216ff9a365d29e027a557ae3d4f52bf4fa11654c4314d65a319810fd799c8fb2d129692d7d68f6c134cde9de5d2c6","0xa814035503cb1adcfdef259521573a5193dfa1e8d74e22649ad1b2b01a44fc6c2352100bc42d6c48584ff1d3a430537d","0xaaa334a2fb779ce6de3c557025ff9bf17243deb3f09a37f6719356b54afd9be09a7b82cd589758779544a08cfd3ed5cc","0xaac004b4b25584ba8c906671196db57d7a4f159cfb430b1590d61d94c5c22cb694c25bb6ee850421db260d063e096145","0xad7b6b1ba1f7950cc8e2b5b0cb9041666361eb023b1deff783420482970cf58213497d64cfc91cf06762dd511b0aac31","0x846f3af6ac23b648a5ea3cdb60b2086e18e42b2837a9d689625af534792f9489a1b22cab64476533993f34149fed1a0b","0xa8784f36c1a8c6e739b090d982480712ff04c9231190b97121c86c84a35cbd561d3372902017ea71fb99ce2a6582f362","0xa398c76ca4aff66b20dfea97e1bbea311a5491b6de44cbcc979bd368818eaef834f188ad6fb413c3120b1af141637cdc","0xaf54a32535604e042dc5a7e296a762f3ddc1fe00741eda9acb8f54be49a8244750d6d8f15a10d9384afbd26bccb662af","0xaa41628c60365750c75cf91a8d4097047d61c624b01d4f298ac90a66409cada1bb99cf42a2577ba173a94745dd73d6d2","0xa4623cedd189249799b7c9afb49960dd86f31572a6edd594dc9d147bd11b368b66afaff6a2dcdecfa873f88991e5a8d6","0xa58a5d3d29c1331b6f4f977ee08afdf95c067db26c21a591b15db682f93d223acd4e031c98434ec7be34922496ec8ec1","0xa31ecb88e06673a2c3ea98a969827babdd0c6a8fc9569d70c024640f31084c7fc2bc8f00eb65023a008e0b47b3d2e364","0xae32f510734cfe1a05f1a49888185191777008667a62a3b5d71f4b249a5a0421d762c98c0dd0626e17f6326ff525e63b","0x9407a54a336fb7632ed16da2929c6ed1e2a8a969990d15f9f322734ee60c00757dec74e4c0224e813efeb1c9be42c09e","0x8fe3971515fb25cbe62a03e4a593dfb4cc3563bc5b7866dfe300b958a53f07fdde463fc7abfe349a2eedf38d569cd126","0xae99451101dde8ce7d7f1b784fe2a1fe0974cd3d7e8d2d3c775892cdc2dfc021eb9f7a5b60681fe7369ec88884e6299a","0xb5dd36fb996d68fb9dff117081435088b54509db6c3bdcbe58bb3711fd21b62f22f7ffef9b8ead2031c0c187717ca738","0x9376161dba759909776ec807351e1cdafbff9a9d817babba680c953344a80dcaa38378ac6a7fb3079d909f5907310336","0x8d92d91ccf259f1c3df11d2e4e92cbe047a9b278ab9ee1341835a08da4c957950a70f51d62bbefd4c6f3c01511e39796","0xa95aa6bfc756de15cb1a21d05b465afd5bf806faee4e662ec335d1e093299632f9498dff50c71844e28d98b0d2cb9e29","0x89f4dc26316e4037269b4afd3d92f7aa9d768be37dd951829657941f2220f7546071ac46a72d715a1af71689982afe61","0x812c4ef835a77db7ead5b86773755711051cbc34cfdc4be7eb41a99ce5094f7d12412a7215275cd9ae8d8426eb91dfb4","0x8cfd6c4fe7aee61657f1d6e5cff1d41d24bafab7ceea78d2f5d680f8b51aeea83ddbb39bf6978bbf1327a2d240012551","0xae7c6ebb4d7b5f462da2004698a6dc54f1e55ef0f3ecd0bc155c9b58f67a038422e209492c86c986d8f24f5261126f51","0xa4ee2d6f77a08089c71194ab48c338632c6b1041c326a483033aecd1bac1baf5de221053ea15c9fbdb8584edec6a731f","0x82d62ceb1242d6dc6527d8f885fe301f4313b87e7e336a34a8d3a898ffca180dbc624f45e1dc07695cecc54023207400","0x9337d74573784dae1f5badff018e4f1c5a2f19d1b57ac07a2f12dd628ed97a4b3a4c84ff4c7d291063f78ec15ec163ca","0x91fa5a8682921fa6dce932b8a9cd3e58ac485c03ef81202f69635f463ced2b366a85a3b6aff905542840c05b5739d7d4","0x8631b733c42dcdc91e0852655e1513864b50fd75ca1078a205205afd3d2c0de2cb2da63c06f4f547212132fd66bd7d16","0x965258ea99b6f1eefc8d8196fad346c44b559e00fb31baf7cdda18e25b185eaafa91e3e366712514ab3ab855f41c9600","0xaff02f3635554e57d140069596a9c3463e85408521b2349b6d1d5c4223874086dfa5a58f8ca73256ebfccc63fb88e58b","0xa166c85614c5b0d5af165a42ab98515c009b6eccb740213e6ec1268e35aebaa73b8c9b22711aac0d5087f2534604eb36","0x967633e5396683a4d51ac8e531194d8243fb808b3237c5ff635afcc0c6ab3fab8443cf9bc7268c25c85d5c9d3b42463c","0xb3dab04913697100af2268f8d71e4daaa6475d08785b4ab816d1a9d209703abdb3e890dcec518c88cb5983d30e977408","0xa4bdf84013dca6a9af8d56d0bec9767a969d7b0b88802ef0eac99a9551dcbc7e03336e63943d8cd072be2d2915d9db25","0xb83a5503f8875dba99bfb8077c50b56120456f836cbb8b89a24e17d88c76071ed9b08a54500ad8e24382a43fa67df89a","0x83e32149769b6c9091f8921195802c8948cfd2b6c9bf9760e70641757719e028d0e65c85bd0fccbc10b81cbad1c87d9a","0xb3b60189b0b7dec69db000719fc89cc811c60e70b80d764af86a9dde1c4becba8e561d9f4ca5437481f01b0d7d1fc807","0xa290656399af969e0a3c03ab8529b6b0173e40c049101115120628fc09d549256f3a358f4cd858e02a9bd025a3e01dd7","0x8633815ef4ecf32dfd3e6221d877176ef1460f7147edae206349cc816431f1a2d60fc547e6dcf0bd31111fce6a822328","0xad5539f19d8358478970caa4fb524b274867ca7449141a21fbd07e6b6291177200e9dca369b665e12ed40dea80b69cce","0x981a72fc476e4f532a10da80f235deb940e4cb6597c8e0f868171488f0eeb5fcc988048dd9ea3bef015aaec0cd79081a","0x9282d6526651dc5e7caf69877a2209d4346bb231b3caed98fec1c95ce3eed284da0617c4d1722e7c316eecebf73601f4","0x836f2b3e00dfa069e4f315454cca69a56a36b6d32514ac81d168e34beabc42ea8a27918d60fe14a8c93ccf040faab02d","0xb4d3e8864dc26809ed314a03e60c7fbe63ce8921dcb52affa19837e59639513782a1e526823f77fc9564d8fcc15bb0ba","0xb35c3469a78ea17878cbb166377b8aaea461a0f7d58cc5f77862cb9a232c5a95452d523362808b661cd24a1e0baa67ab","0x800044ce43a3eec0738b16300361bc744173822642fdf7184a7ac58f6b315478c03f8b57efc36b37c262e08b66260dbc","0xa3fe94ea52c28c985a901f8d895f8d2493dd1d939da8f775c7e595379431d557b83efce814b3f2d9b5a463c8ab5234d0","0xb04bbe642a86b34459811d60affa8c72efaa288a34d4f2e5799807ced34747ef09ca47f90645d36c0a43fd9ce592e41f","0x80609da89da3d8a011674d17aacc7378a9ed907455c914c3adfe80d9d5ff1b903cf0195f7999cd27af91de5177af295d","0xb929600f99e80e834dd9220a02e8b395bdd8cdfd9f93f201e6cd89ae1950e0789f93862082f0c7efd45e4b69224bd92a","0x9052bae965368c78db0d638faf2ea9beb0e42b469adabbba09f85936f948a1cd77cf811a20ae759498770855068adae3","0xa7c693916f59a0ee41b13d045632d4c5e8703a0e1431b50ba0450834747e41a6634ab9c0c1efa6af140f2072c29cf7a6","0x83a40895d9005f007df9ed7fdb17d820d3d66fe419480cede7518e1f54e4c1e2a97ffd71fe2f01187c3707cde5bf9915","0x8ee8e926da165b8f34d249d194864a3994278aa4b829295480edac18395167fa016b2a4ffb0b0f3c89d18622bec2409c","0xadd60d6bf2abc6935ffebfe463c9b305ed2c898a00e2a84b997c014e140a7b254dfddc5be39e406ef0a893c4d67dd1ba","0x8f48795cda6795e9af514489989a9f9e8b6db2b52a36881e4ba166327153d6db922e5148db044b27efe1831b54e16270","0xb43ccddb32f15baaa32d69abf4b298d38e835607fd74aac5b25b5b161e8c865744a06526594faf39521e51fe44d66658","0x83249b11efc76fba2ab77df9b5ffc607e6e2265c7f761dbb3099f3b4ff74ad8b9570036cb04942898f8c33b8442adfcc","0xb049dc45fd585ef8bc67831dc47690f95e466cf11127def6ef9fdfc43017518752aff3df93c3e5f68083f590f554f3dc","0xb0f4dcd488f6725946e1a384d9ae9cd6a12824dafb426e15f4b848b6dabd46ec1177fccd0fa5c0c2260fc57aaadf1e7d","0xb400b2f5705dbd2905c5d9fe3b2f29cedb380954a60b4fab0e55009c47e1908a30bf286f7e01b7125985c9007015f37c","0x97580566e3ddcde5b3e0cedf688aede17a8b738a21f96a0c2efff77061e232ad877e6bc71649d0fbb3ec0dde584bb8e8","0x9504350e6a3ad1a5f711d9e5904bd25b1f6571bcaa66403f1da9fc8200ebd8073308dcf462371073bd8b076fd25df949","0x94184bf24da31a8ca6561c17aa36b6933f07d4966063972bfcc6c97d8daeefd05b7c22d41fa5133327cc0dd000139175","0xb88add150c36e8c338f7ff8efa8efb4e302a5a01afb8e331282eb075ffc3f2f5e5e783a4cef6a0d9c65dbedea48cc093","0xb25827b6746a0ed3bf133beb7e465ba08c39e1960c4555a81384502d6c244bdd7ca19f521c6d192436d71dfafa64b4a6","0xb5ed6e77bd6f1661a5ab3f2e13743385c7ee99dc240e9575b3e7639b4f73a017cf4edbd0932e02577acd2bec274be3fc","0xa25579ff3efe83b344ac7ca26d45d5aac4fd4fdb1809f20e4e48026e154e95d7ea8c7abf6e91628f8448a6a798dd07f3","0x81dc3529a283023f70fec5eb65ef8e3b394b0239bfe40095574a881c5dbe536a6b119e6cc95668b62d6e5944386c07ca","0x93da5217b698dcee39d36c25bd79f2a152e5053add9e4b17cf60cc5dadc0e2d1713d05f7b5917840b6748d25d68f4878","0xb54437d1547e9a87476f03c094c86465f36376c09ef3c8fba0c8906fdeb0421d523a20ab6ce6ee18da9fbab39ede3bee","0xaa5367fff8db3ba5017bc601e9f9ceb867d54c3b17ade967b0bc905f644f6aadc8aa53d3e9ed0e278bf3fc2b0b56a7b2","0x874305f7d11e69b74164cad10ab88ea7df22208c954fcb6872f34a5f9c8292341f85a6250716270563a19b5a112761d4","0x96917c5ff8bd2debf697fbc64455d19cf1efc4e1327b3dde2eef7db7cab762effb43025c4162db0008a0b43b4d060748","0xae77044f5f689ef3c59fbb1afc7fa2e33c5406121f9c2eb1dd089cb320b9d82ab51d6fadb545327dfcc2688c201e9e07","0xa174a13601df492b77a263ff54d9e30a0d9b248a1bfc559a4bbeb251fead9b72790f08bed89dbf224c1cb5548c44abab","0x88a09d6756a015068efa04c8fca73dd96e2314e4f6e9d1aefdf19ef139eccb2000c3f382a18a3ade202641ed2c4b4267","0xb41b17006e2a6a6bce8055ee459557cf835fccaa851885903846dc190adc223f6cad199446ca225b6a65d40382344227","0xaf9a969a70272ac2871fd689f13c0b478e27bdc5127f02c41efabd5814a902dc1e3ed8b3ca1786aafb8f112aa3c87db7","0x8faef0de1c486a7638c2a50af8f34e42b7f11bc1168c03678408702f8d11637f1faf893955a39897d797c851d1e6267e","0x95bff09876e40fee59003b08bab452d9bd2dfae2c6411e153c4fc531f4aa26af8966049cf303865472d56643e3a3ad70","0xa186ad3532db69f509d3f38223e388c9300031630ae02c5e13e6b55db6094554647fe52dbad51f931678c43d97f6b4c6","0x976ecc14c14c93f8d0bcd6ee0a6f829de29fc13e167204e83d9c13d69065994af9c38424443114913e3142ca96138094","0x847ec3a8b963b0a40506ad2e2a2f9119456d36150eeb64856f12c85a85e12d59b295d953d845246be5aeccfb70c1dc04","0xa6be6fc30a561b92e84333e413ce5be1d83de64ff5cef73611840fde672bf26763901912b37dfd8f1af85c3af87c8718","0xb1ea18e5c0a7424d06a9e77c65f2ff5047b5c4530e34e700c0d1bf15579e2afad228a8213c68eff8c14353d2e1f10053","0x8fff13510ac685f51ae914b7177bdf296ecd757385442ea0dbfc8841685b79b7d52c780a40e07723ea34d6179c6f3ee8","0xad2d0e0c00b5a16d50a4ae56a3c0cf2e1b2263e2dd53ddad54679cdbf338300e1003af5ecb73ac3dacb8636661e142d5","0xb854086bc1f668ad8ccc4ed3a7a52eab65210717c3f8b9e6ebc27c1cf27ccba0a4056311c69cfefe875fa45e2cd26e69","0x95000d5a88212033fcc30690e930c2128685b97f26a9e2c52b75e1fb562a1db1b9af071207823ef1927db3ca65ee00ef","0x929ab4e52386b139d32da163a4e1be5760f1d97bcfdaaa146f8b0348c94896b33fdbc3083ff3a41063e1b969a1f84080","0xb126e91bd72a3289a04fa01e108f3ab4b77f2d20a93edc1c70f8ceda1df286461e92f73b7d2f85874abb1454ae1ef535","0x8fe3f04f04422bb2c76f5cfddf80a7a2b01bef7170af5f52c94e64ba1f8f523ff18d09af9235e37d10b3ac8ba3cc6ac4","0xaaf6cc6cfc559ca26b82790935d4919ccc630438032b76874a40c25d77e4b87db2401cef8ad1871011569061ec7badcc","0x8533f1c4e38a4f72c3593ab28ccb163bfb429242a8c23e731478e57950f563b62101b06882f25c8133ea357fad66522c","0xa20e3bcb6b38b66c2de7a7b3d1731cf430ebb94e38897d9ab9a9463bfe813ecf65f39297d2a3daa803f66bff80d6b653","0x8cd7d05a46ad2e98ea82c438f12dc9fad70fa0b8cff2a731847efedc0efadef9a3f4d9e12cf8e9469d157d106f12626d","0xab5fec7f75687d50f35f4336b7ac78108834f98d9979f0327cd11b1557b6ad9dc119889003384b3940b10f0af7b8314e","0xaa93eab6f16b0bee0a2eaf3d548d354a716e1bfa4047ffae14af55bb49bb994310265e10c7ab47ffa33d1c3eceadbb4b","0xae363ffe8d6c6858d3c32967150ef670a2262ab9f46b3f2e3e4ae8910092bad1e7208ff9ba3f28b151dfab12f3474a19","0x83ae23912c04f49176c912a5d728224c3bbfac588e2203e37c6ca7520b01c6225b2830b0d37c8eb641d9abb44a648e28","0x86d99bd43392d34879ff4409aaa44f1a42b34471a59136ff2fc2c5d0f3bee905108958f4a0de383597476b6f8fa380eb","0xae47eed8ebfbd33bf1e92f52fc40d16f4b2b5e0cf4f54f2463af76f83cf0fef26475dff6c5b9d78f81925ca7d51190ed","0x9286bfc698dd8f807748245c4d13de02910fcd8bc9b375a308d8a2bc7c73a05c8254b73931e448fbb2cf2d24f8b42f56","0x98857d698710dbc26a57f167d463de3fc8e15fa4221d8ef6d8853c7843b04d2119a865215075f52674340300e1ff58a7","0xabb8d751f2f97cd345688187accda8e00395503e500bd727b82b0be88484587776c225d64ca72703c186d6d0cb248e76","0xb88f1156883e6edf6df2f4f94079d373992e2d236ddf7003cd8cf84d73e371d16d4397fc20163eb4d8b5ff134beb4b51","0xb37a06d51bf2a06b938b2a1d84fc0e9a0d45e753401035d0c7557b01d200c302169a06c5276ed77b7b832a885376522e","0xb960a785f7ea8fc1d9886ff43e3b736cf7fab383087b6f1d85727473d909a91215ec515fe72783d703e8d214cc72dbde","0xac748de8d5418285e99661d22ef888ee9b19fee4e3bb2db1fbd4404ac32fabf9ba2d41450c2f2ba42bd97cdf28a349b8","0xa89895024ffe3c247d5515a8f2cf3e5275dec9c1c3143d7a4dbabe1aa16761ca69225bd2921a4afee83e01cb4c83c25f","0x8e0cd6b49327ba93279e394f62cb84375fc63bbac7c72eb4f90cd5d71e4cf34f1fe0d92b82ce51e60d9255a0fe99e021","0xab195eaafc5a60c4c91722f53e19fce9c04ba9655f433a18f0472606ec826fbf77828d16f859297a9272d2b4fe50403b","0xaea50380eaca9b09e5baec21e5f522c964b0ac8d4aebb8e1a1a196a01fb5c2c87f524be56a57d2f80274d1a0d2ed7fa6","0xb68a35785d29094de3457406b8f974581ab72e2aea2c3ec1ffd21b0326297f09a838b669e3e1409e127a3bc3eaa8cb72","0xb90a59e63d66d20d5e9a3b45be51fa7963da5ee137a126740036f432c50eecaade78c4a5bc92fe1908a153b15ad92a25","0x9826a9986a35754dfdc31e69bb8b073eb7293aaa747b0990da43c2c04bc001c78257ab3a1a91d3c7f2bb9c8395ed9424","0x854de57710b835c0253eef8a20d2e6f0ef8d260eb4443bbd5c38de0acd38035f0c1ad5d09994744588a497f8eb3b747e","0xadc1109ded58e828f3c992b3d367b8e8d9d5cbe102fb171b4f4dfa66a181ab040f13d15a38b10e50c8c87432904b6e1c","0x87068fec51465d586d65ff531b32fe20d2e02535c08883721654338878b1aee8479fab486a19de804da1f301443f69d0","0x95322a22f4abe8eb0a0f4cf8876c31abeb3684ed984f6b595b9f3b9527b60c5f730d03d4960f5094210a3f6383691348","0xb43fcdad30bb652a82ce6033d6cdd6b004f58eb102d54f4de5a59c17c774c66637e7ed8078b19afe55ed34ac2b969fc7","0x801125a4149f3b2ae29f7745ed91492ebd9de91da253f0a267f864302044310c1f9decede6b1b5a9e1719c36841aff5d","0xa7852f47c6391e4ea0854d59b4a69ac72be49f7f798c19146a787dcc25a48a183ac3902001d0225f242ced6cc09aa378","0xb0c1eb313f3894f5f19ddd7cb3472f015ccf51c24bf4316fae3e8502d3b65132a8d2ac58f7d17eec0a644ef31afda14d","0x8c6ccdc900d78ef20d5b22ad540e73864c858baf068349dafc397cd31c571708ec6ee6afef9e5711a587e3e97f1a50a0","0xa8aa5faaa4bbda5b5e7d610746f27c09bdee3a3f057550bca600ebe1c83749525a135829669a0162c3339ea40dc5525a","0xa7c107c72118446d1dc3c5c1c42f95ca2471dddd61c1461dd8ce028a1dae7656c98c3eca5f6dbeae8f9594e3e652a4d3","0x899eaf183acd5beee0899a58c8ee5fff1dc76df143028d9871d231e8a3999d92098538d070fd1c9db5d9db60f23dfd4a","0x8771579633474fb50075b4c801124f63c4a786e7a618bc50c00122f4fe8c18d1edc123ce9be8436b9bc8159c5d2061ec","0x8416902c51bdb3933ff4e87558121d3fbab9f116f9a5b0ae9cc30c4d145c39dc988f5c0b754da3daeec71fa68144f9b3","0x83f8eb02f40f6369cb8836d521390b06ba91c72618056cd103ede2b6204069ff94c7364c2f24ca1db500ef627be3f1b2","0xb08c6eef8be13656c3963726dc3be95a5087e363fd5e72301322ea73a8840520d51f142cd9d94d0da3b7a6f22d111fd4","0x8374c6a0d41b2da67f26a62120128838ab64f3928769a4280d0650ff18d6262b584e8f68a915bf8e4d1f6e18d72a6ecd","0xb98aeef39fb7eecc46e6cff2632a543757a8bd80bebe409b5d0eafe2922583040749cee9f130cf12eebf85c1dfc0adb4","0x8f9e00f60b9b830e72b7d0b45a3dab2cda1f678880db3b5dc5107e07850dc5146afe8b0999102d4a8bca5cbc27cd8a2c","0xb42800735102f10b3e09c11e9113e0f4955bd19d0c5174f587d446de44230b10c3e8b439fbfc2e47f9e82ac2ade917b3","0x877968c73d43465feea583c7bde8270773fbcdcf9d1e3e4fe492a208e788bb56b329174b0d2539d96877e9d6f5bf1b41","0x915fdf1928be84527b07ceccbc4a278f1e9e010d6f716d8c3a4666bf649411744355ef25b22276c2ab51b3af29c67119","0xa99b23673a9c02a8da9e44fda564aaacabc12fac43b600884e06ff21ca2ece8fb8ca28c593d3966ec6ff427f8f497c05","0x8759613fcfec38cf67297fc0b956382eb403f1b9126d1de3a26e0ee7142346d5457f09c7765d82d49f51726293b3cf7e","0xa0ab65230a0c9a2e2ec267918366deaa93d80068b14e691de2dff126c604e755b72d0865099078870d6a3d47a2f56d14","0xa76186ca2743b7149ab7b5ab83c843d2d724ed85ef13a9e0e23a697ba048cea17acc68d9dda73d1f4ef97b9747e491ec","0xa70362ba9834a49f9f1ffdccf221fc2eb1f7a5cb584bded1d79c44e7e7890ab28d787004c5cc6a45d0e941ae27f1fe39","0xac66effd5784f677ff6fa5cb96d9cf14552d5888a8cd78ff54581b9fb35d3980c9b34cab41f565288812d77e3a44cceb","0x933146088cae286d7d0c2759fab13c1f3e7cea13c05504c006e2ac25f322a779905fe4466f0db965620767d6270ac324","0xb31a6cb5ab165f4b7b66bee6fcab77e410a3c7d7049ca5a6a7bc64b30a1c49bef4a1ed72454b87c8b879c00c57212ac2","0x9570f6171cbc78d58dd8afd84cc2f803ab049dcc15566b4c16406f798b65346f3bb36c45aff846e4604ab79ddba8125f","0x871e9ef179706974e0423fb0a6f17673dd3d91ac9625a5c034d2797c396698489dff3c53abea15b7b5604919fd36acf6","0x879391eff950beb2720f83aa628e43b313ec26e20cad9b75457bd8de5b1883fad8c5f28533ebebac4e377d82145d75da","0xb03bdf830d2cf1c1d8f0bb100fb3d4d399b48ca2e67e8f8513809bdf49beeb4b710438d64bdd9f4d4aebc3cc844e9302","0xadf6fceba8b405cb2a0e853da1a8db38799eaf868a91294a297f0ba4601731a438f1f7a8b15c91cbc7b4f07734d74ac0","0xa931ae0ef4447284cad9e27b334924088b87f489d1c1eb49883cd2f35e4cd445dfac88e564605b32d471b56b4d98a4cb","0xb304ff0820279e94ad069248706d39bddb36cb1ef69e1031f2f0683c69b4e8fe5bee35a64a7d160f8f207253bf6a1080","0xb51c0882970b04879282a60dcfda6577abd62328859c811ad190b4a77b824e4ef7dcfa544f7e76ad0d0c53372e9ba43f","0xa24dd1ce8d1d5af40401a2c2d47027de989313ead893a646456eb4ea9d6e38cf8cd37f75e2dfa631beed89970848a39c","0x943c88ab60e1b649772ebefea93e27bdc89bae1901cb8f181fb813a753861bf7e3c460b909566f30be2ad7ecc7e345aa","0xa2eea192ab4a2213efc58879ce008f8684c3b8da24d7a0124ed33c6ee9d3d12adcac702a938e2ccad79fde467fa413c4","0xa1792fc5047546bc98391908b80fc9b4a790018b580836cfa593426624ab1785d11449a03c93759f34645d277e9f26ee","0xb2f64f70753f79fc04398f220f2ee1a54d14c8bd31c1b27105aae559d5006434135e516e975f57c7a41241ac74ab6aaa","0x86195e4462e04f6e0f4c2545ecc9c0fa812f1ffd6cde31bef2f59c5806d839937d60bd8180c2362555f73aadf6591965","0x8a6d7746a13800bc06e455dc52786c35065e2b08054ab8e569e28391dbef3d2527eea72aa60e1b53a54dc477055bccf2","0x961cc399896c8daecb0784f91943dd32077c9ad661f460f27f048ffc557010b4bd9a4a692306b6f70ff0f597fd31ecbe","0x8edb799cc0407cf8db901082d7fcd613b7dd4ea03caef14073841e54531bdcdf3f661d551edae045b960b506e70b8dc8","0x8eab84a4394a69ff45dad4a17d4a8ce3bb04948c68bc70abbdebdd76c2156507a319d5bf9cfcaf750fe3b4d5c66723ee","0xb4c37ed40d2d3d2ace8ba3e1d0bb1b0651d3d21c3dc5e8a4ef42513d649fc14d6dcd1ba7c8b893a2205f6afc870feb75","0xb02b650ec8c8a75cdb3c8cc64b612c5180aa31e0345ce16b1d9d8e5c7ce28d4feb8ed6bab0be68c13a5acd71f326fab8","0x890bbabc36dc93557dffada73af2e71bd15481fb5345d7b4755498ddb1bd8733f0140cc40007c76ccc8764ba42678d1e","0x96061e58e6b6cf1b5398912930b1057b98d586f2370549ae905cc430a0bec98f76a5729f0cdb63a4933030839c4949dd","0xb166ce131524e5acc6192c82de39b97ca6412fe62aa1b26113823dd55c3009c22d5d5fee4b9ab3981d6450d7f700340b","0x9894e414ed3912498deb586812876675eeb5d5eeeab7252c704d695ab04c81a346dd8782534818cc4214f2391f103f0f","0x9989346f8b01b4b2d7f00fb43d2e4eda4f565f41df29eaef8daab1aa4409eea8bf9250c0c6a36424dcd9cf2958435668","0xa915016106634506203d30e38a5ab8751ea4be224d51be363f1ea0d162d4b75cc525db00c15e5cd7ce83c9ae64633eb9","0xa15bcb0ef07112d1415b02fdca011c99e5d35422c32949599432f7d1757383e75b5a1b7ecd167db9606e9484b06717a5","0xb3e9eda82747c66f6cae59d6a2ea09e4d364dd0830900ea9847f772ddae92fc39cb5d14aac8b48740b641459a7ec3ee6","0x998712b394ce6b7a8a7a7ad4ce6e4b290387ce9990004eaf6ebb7ea1c20805970c8b90aca78f387ba3dc93d3276be42f","0xa2c2ceba40ce54544af9d1099458a2ef710175877760461b2ea9334359d9f70572e22a8c38c5919a4ac2ada1ac5bd1ad","0xb5e2acb50c38a763f2bb0b5bca4a0530e042430343b49b565e6ff56c45b9decc7f67f38a1ca482bc9bc5b33165e54ee8","0xa7f12eb23800a3af56161a0ab018114bea3e4e3c046f2711f874bb9c79644eb9a7c5c08f6934aff7a52379326ed5b171","0x978e57ad92676315c2b7736b65ea541ca89fb0237b4ce2800b8b3f3193a148390fbe643e5967e8aa6902d09a0a21f02f","0xb7f0d726257456220a58a0fd1d8ec91e8962ad932b325ee74138b6aad7c5c8c40b3f36b323664c9b709880a9ba78163f","0xb949f8e7e937ecdadfc27100f4efc6ce1b840c960f35ec764ef11e837e3419abd33ad4dcd492d1913b14b861770353da","0xab032b66e09b758f49da1d83d1394a9761d5743d14eb90cf30789927ecba1937dc126d64e137a9a08da7e8ded80144a2","0x91ca805bd2768bb265b01cdad30b52f08fddbc3155c17d0f7dbc26c1b38a33bd14f0bfb920f2fa0369fa9d0dbfa486e7","0x89a9f8a31560db9cb16d42c0a5ca581221f6cca0f806b32152590a4e897bb06f556cb46b5b23f498e3c7e8d545170dd3","0xa387f5b34928519a8c05d54cbf4d1c1bfe5a5fbbf1c842f672ece0d6ce73239b7aa206f5a4c3ef7e4129f5fc8e388c0c","0xb9d504f24cf511062f258d1127ceea75b084d1f487c31b6f734e3f03f3cf925d3a2d66dd30c9052dd5ad20612aee3f7f","0x96f0128a982790116ea77948685416591745501bb6fd1629406cd789ceeace834f25d77c946e88ede13f39557f62edab","0x99831ca6fd72c35ab80e0619804bd1370410d7d3b609ec3b979fc8f0593605fb5113e3a981f8ea9bc6192bb5e57be5df","0x84dd9adf9b94e13b325db67c6e13db5368ca9ec98e66e1906c3e4490dcd20647a50b9cb731d27d9a639f0583d5b3a3ee","0xa47ccd75dbe51faa5efe352e73d92a08054fd115ee960449fd717474c72a61e6f5ce7202d7e953f86b7ec483c7a986ee","0xa5e998183fc08c82ea64fa1af9a50a47047b32f0108a3b2f7a08b3dde117731198499413d1d814e978d3a6b5ca8f8c27","0x87b8cb388a9623f9a970af2de4ccbf08827e978c80cc16b91ee5799b5c5d8b72ef5ef8d8b665ea8bc880c3b580e6fae2","0x87dfb8b5eb20a5095b1136ae1a89486997408c9193a188182c32b4eca2e5be459f081bd84763549cb2bb427662d42fee","0x94051225785ea7b13217f793908da409baaef4f65945783a1b84b660d6ecfb93a35780b14fc586ab1444e09479ea7c3a","0xb2c76038f9a231f89d0c66f594dcda35f4cc7638d36d479059b501529e05f3efd76d0b01942e36179679eb40532640cc","0xa448045af3317f607a34f360311aa5b1237c95e05b6208e8d30d8f828489859c550bf07e00df070aa8664370fd110bef","0xa58de34620fb581ee38f0d99027d2bbd88572c6b9cab7eb48f63800c5e3865a83609e144d6388c3610a55c391c077a7c","0xb4cf9a6ea854bf675275ad7a086f77e2faf99408ba5faf63ca35ec169597dbc50dce44a5b57de3778e8aca7c3d7f6564","0x8170a1bd07fea2dbe8f3abecc0edf12c60992851779ea15c4016931880194d52948960a657d7afa034f2a277fd1ffb32","0xa1ba0f18456da3185ae3a655b0407f4bfef64c1862a45af5ddba4d8592c5cc846fc43a297693027f3c9f34065dcd0bb0","0x8574a5bfa6a5fc897336edfd6f9453509a18c2a4948c0d4056126d72b5fa800b75f9d8dc6a277419c0dc9a05e47ef41e","0xb01876b3a29bb97cdf0ae11e7af139d6e4e28cfb0084806545fab1b20e089f6f2bd98860bb966dec929d4950a522b241","0x8b7b5c5a7eabd57cd0f08880e2aef49213f97fb39051b28cdf34f6d744e28befadd2b053d8e6708ed80733cbaa8de8ea","0xb8870781b556d3770aec2d7ce9003955edd343e94986a016f6aa1e7c2ccf9df55a145be3fc485a82e9b119db58179e67","0xaee63b007c8f8b265cd31dd37a3e4866665bac33df9a9aa450250f037ebffacf787ca3b6a643a433767df791d8ef5550","0xacce5f47fba81824e9c613fdbb6413c24bf85a13e03eeba8bb64e5b457c090f381fcbe9319f84e0826ca1e985478ddf2","0x86481fbee68cee11ca74159b7be4e917eabaabe99a8fcd278add8d4839bc2e58d1edbf4651058658893549e05f1adf7c","0xaee0348b1bcd4f659fa0c76985a25e9780a5f7e6c6e1ac3d655b11b379bb5156abbbe290b1d906d00099da899712f277","0xa4db9f534dcd25720ca0f08c8b54a53dc8fdf644eb2fa4c1368d80e0a9688a86b89ce1675a0cca9fe9ec183ed891604e","0x97ad93d56e452fa112298ba96bc3210ea5aadb6ea465443c088fc3de40247b7a713343326e7886388be4cbe3fc39229f","0xa694407122e1ebfa70b2f645d7c789e33ef99af07e32c292dd310c01929232f5cb55a05e4e9fb5d66dd83c01e7eeacdf","0x94b14b018f14b7a51b87dc0cb7300c8a9f3da554fc82579076443d33c7e9d63fb44d81b7bedb5c31265d969b1e711e71","0xa1c19af1a3783875d9b80849971572f7d340f9bf751bb63eed1ced8b7af7f738145d759c0f83db58edd6405877373d02","0xb59ff0ece97e227bec75b2515bf44e2ba4cb256e5a416fe35b837c88ff74551d5ac568dfe4a8ad73e39b283328acebd0","0xa78c049b9a18154fe5212cb4146a5956e136bd1b5b61ed720607269bee99b177b242412d8a4bd9af2cfebbc95d3969c7","0xa6b2781b95cd1c1f526fddda190fb0ac6342cec350a1f0779fc29617ff3209c9c8737a32175e451f60627644885aef64","0x8dfb38b5532cf88bed78659cd53357026fcc2156c20dd2f8d31544f68b1dd323517e577bc4a035916d635e27299bc42a","0x8bdabd4699c90df7f6fc0a76ce0457e599d9ea2c43b0c0c89a05973c6216f0d3cac8836a7e2948cbb5299175ee55bdee","0x8566a86c611e7daefa5441ea8e735226a74f9edc13867de83724943f09952351f339e34938156802e643a3976edf0f91","0x8624eae7ba6886cca9f16dff865814d473845d45c86bd8ec05ed5990586c9015c944eacdcb295accbab8e0278510b897","0xb4587f1af30dc3a8f24dbf4fb9a43d2391cb46819baebbeeb0b4fcbaf9f88799fd35ebd6b13aa8c98b21e32d1be1871c","0xb6270c8ce64d3e23a4d4b262be82324582fbc9f04800acd7ff7b8113889a05983054a96aed0f2b93a0c1d93bc42e1cd2","0xb8739c84520607dbc5732f80586377f5bd3e934fb6f48220aa0846109bd153aa69f3355326ad3c57aeea3cf6060f3ea1","0xb823a720b25b142678fb5b6a7a05709e91966658c6ce8f15ee0c42e0d1d68dcf2cfab3f4ef118a6d5cfdae6543c4bc97","0x85e61afbb730394dae24051bd1189fdd85cb6889bc7a9ca488fc79188ed28eb38c02991d5d3c52f5be196eec737100e0","0x89b37168325be36cf56b92ee1a8118d2ba7e0b7e8c498ce99c4aee0032a54a27e7b951983d713a0852d92af15e2e438f","0x923398e9c1d6c7b3025ca0f71954d3856560cf6d87d62ee70f28f633304b7db74679f14eca01421917f1587c5c2dc135","0xb974e763b57fcde9c466013513a6803b322a6aca3c22e230621f16f151d995cace1425bfe6bf576e773383727c59ec5a","0x9673f4131c4aa9cb36684364322e3316f94c284ea371d93c4b039d2f066e38989a296fe7b0cd634dd744d2a1497bbee4","0xa5fd9f411beb7e0fcd20641a5ad278a05d95e0b20231086e6c61fe187ffa810503317b0b2d0cb113d0a0763763fb60bd","0xad90c92e78f64e08de38177add4ed4a2fe8f838e9344e6124dc777208685d9a1c90e8c3ec0beec266c960a5498de5646","0xb3efa9d14b88e6b5b6d3a0c957edb7ce40fde26af22e591532b5d13ee34d456ae93266d413db52e6c3244befa675c590","0x96c8b6d6600d2d2c5cb9779f2113985f951ea3cf83a7affbb103fd3eb136655062d5a9a493df29e41e9840d40846f873","0x8a19a6f3918a3a7dd3c3ea76f7919d9900b1973f5df7799626fa82bd31777b2e22646c02cfde54a619f2c8baa263659b","0xa2a1eb8e6be99d69190a797653c838da0e5c4305793367f3d024b0b3b9b01c16063431f4710d61bb35f418d9b550e322","0x95ab9b1d88f56afa2e6d16ea557c0c44a77c64610028439661dc6b336b7d083034d5be782a1e76cb8520bf983eddf1c5","0x930c2d6c2653a8fbd49f7f2c2d0202fbb522a34046806c454484926d452748305419448d382966db54e6a27492b6a728","0x8c867632336766623157959e72510cd1aaed937fdcccf90a1ca2055f0058c50f8fed3422505dedbb690d1dafd1501642","0xb9015e7a58b982b72537667e6d00a650b320eef7c388446acd8d31d87f928d04c3fa93dbaea9f2e566cbbc4bea0a96ff","0x8271b3b205bbb08f13a3a0215699de3ad0139826887391de60cd39e028203cf17d0241facce6145111d436b605a81ed8","0xb009e942dadf45a31e69c3a28bd57b20c5fcee022e6f8dd1728cb9652b62f105dbc88c3d581ef208398cbe4c6938db5c","0xb712e75583218ec704c9d6a4b146c9986d33a6cf32c28baac572578605b03833bbf0aa0646f69eb12cd55dea09aef3f7","0x8590e5c53dabd98a65626b19bdef06c3098426c188508ebb15715c3ebb6079e631e259bcb816b8127d9389b91526a16a","0x8a5cc9dcfd436beab048837b7c0c5cd92a92324324148e0ac2f08a50f0553a0f0009e073fb67b89a4387b0e69ba176e7","0x838851f6715a19bc9b0bfe471e345d4c6265a7f255f7fdf82b0d46299b40bbc340ce62c4a92e4eac68552d44f6647abf","0x82c4f9a84a599666db094b7a8515df41de26b5ed5f3b43f7339e7b91e42e8ae1700e1afe695d1a2a9f68b85053574307","0x937991213204dab471c839af878fc2a70470af6b5c9e6682f0292d4022f755ffe5d13b929cc973f8556f7c328e82f34a","0xb36b30c2082bf4c0da4c2a52014865d88c7d656b5ffa35fe30a795b9ae8d56483c53b6e4464d2c3473973bd1237db93b","0xb51fde363551b48f24c4f5fc20c189b445023ddeb9befd2bd4020e1bbad2811ee2a89162ef2d1cd83f5bf2a9a4036b68","0x97f973b638ebc117a714353cd429763a814005f1316ed963c4472a45afde412ed3df2774c94bf2c071da47bae9219aa7","0x981c49abb7931aa2a93dfa3173310b0505be3c70f83acce94d1f26fdfdcd430e753dda33e2f2d7367d601e4e872b86ed","0xb8eb683dbd32add765b472229cd76295aedc889d3cf5f5cb82b086b2558b1c5eb306147cc513184bf0c372b66c732144","0xae643cf95a2453c39cd3648bbaa29d97190b8db1f8442c5c8cecd79444087f25d5d135a1a38fe49eafbd67f48336bea9","0xa43f5af932903dde90ebac2f68a91a8d55d24b8fd4371e5dbcc9b64dd1a40d47855efd53f86c109e3675faee34df4a43","0x8a4fcf8e554bb6af424f3f4813edd923f03d4241c9fb4d4170f3eda749fe8f7b5e0a204a79f8e4034f507ed299e8649f","0x8a619abcf480fb3ec7869778ee3afd0385481f6e99761a36b71e4d6542d0b15b32f5b15cbc423b19a9daae38c5bab100","0x8a8de8596690aadd1ffa677278116e6f17ba47d94d3255bd9ecd5e2e0aeed9b747fc305f89142f860495e1012f77758a","0x8d01560e099d8e0eeeb60302c6d3d6927f356648104c23ddce92e13b32acce24501a718ed73bd65ea5e04085f046ef8e","0x97a7500877abdba5110bb8c0cb8895dd3a0dca3b4e0f59380dd68ee565b3c4e3d73ddafd812dae20d661d1623eb85bc4","0x8bc90b76d13ce97e782db58eb53bdb6442ffcfc8b3b4f4cb45de089c75262f1488c30c6351b8b50a7964e0ec63cd758c","0xab8cfa9bf2435a76968a5c9707ec9d6be9348b6b6394db59ad099c61dc6c87120d6224da163a761b23277fa9b608f806","0xa0421f35e7ffbd3dfd4040e5fd493495a6e419619d15fb4bb2206d3c6a1558d0f91e0cd67ae127f9258ead6d632d8013","0x921354b18ae4e89f099a86eaf29142848e08169a7353564b3e169d21379189162a678fc6909a863bed875b2ae7421485","0xb069633a469f7db1a0f4e68d80bd92ab669d71d7915438ee3b51cb870e1517d6df11e36b2871065129ebc7a6c9ffe20d","0xa772269eb988371ae38aa6e0a66930a95f69c58bd0970961463fd020cf0d6d977372e3c9707d4da73883c7a91aed7893","0x83037ff276ef58e1ff921bd4b59361344d2acfc92f251a50d835966072ccc3aa4122358ff54f5c1cee3c6b6ccf290f2c","0xb5f2498c661c1d10954586efbff5df013ae8f478bd2633f3808177ee27bdbf2ab87963ebb292e023a9fb894d6373da84","0xa596f6ad14dd6acb288bcb14cd60be0dc99e405b23d5adff21b87e43a063b0492d2dc4a94b0957d04b03becf8444dff1","0x82b423bf98d8b203813337140d3a5670da23f6dc5fa3723e56bf760c88eb7397d0fd52865cc35d8f7b779839ed841768","0x9096ec69d763efdbce5e9f68e74f5af8efab19d03e10a09d101d47258a806bbc765162d38833bfa0a8202ac5a48974e5","0xb67eefb905aff44cf7b55a14e845705d6093f29612389cdf8bb3e372893abd0f262fb59bf3413e3a187db61c1e1842a9","0x93b371fb243b5639885f0abf19b03b9e3585617488e0e677440cbff0a427e850e8f84e33beea4ae421222d501989826c","0x9231dfde9c24fed592e1d16ddf0dab17aafe8b85c87d3b86e910a0854d22c69082bcb1d33d63d480a4a2bbfc8d721e07","0x9100e8f78b14469fa14188b3b72adbc6ab9cab5a4a0b4e10de159ca1fc17840d66eea135c034f5414f33a7660918ca43","0xac8e28fef102e92b124a14df2655773470e72b714477ec1df6ec623373281098a6c91cf733ea06be6b5cebd98328e8cc","0x86a2f4b470c679a0712296665282fdb094691e6db1cf4f1728e2dcc621590a325de3cf7397e1dc949012ffa98acfe4e0","0xac5c580dfa27994521b1151ea0c8407a406002007bf518d4749f036ada390c372c9a02147a3f2bc2f0878da6e23e7b9c","0x97f99d0777e91a6e2d088369e172a3cbe70d1921371acf5aed939591cc028f9682ec6f66262438c61933090053ca3a2d","0xac5d0caccbcdac7f97a519b54a410aa6fc4b5f5d47d06a22873152a845f082e2f0499ed44450d7b64f133b9fbd39e17d","0x95b0c031030747749a6a85448b993c79cfe3a971dc860e230fb7689c336337bfae233dc19edc34131962d3832afe79c2","0x81cf068cc1d55028aa70c6c1f1a50508a2fe996c26b77a9ecfe72cdb156003536f5d738d2633cfe7b105159cbfc54ae9","0xb21327e842169add44e0f971b37b70bd7732de8b6dffe736a02f35f77432e324d75a949782b51a11f4e9e62a69f38b7b","0xa0b434508d69940103ad990c535a15f90e415292804b524e74d724bca7fa729322dd64f00c690367f7e06d517201fd28","0x8b95f7c53cd90d4708e4d88a0ae4b1127f8096f491e0796c345e86327d0a40604f49cc3110a16c5ad6a0bb937e43766a","0xb90c444ef2edfe040796d6a40ccfcf371d7a92f464bd301243626fb0c83ae99c7c5c5fc806bd5206399f2270f2c273d4","0xaa18f926fb00f3a5fb015121db499ad1146dc0bb7f5a62ef1f194393838fca7fc9d34c7f085d6e67bfa2200b02611959","0xb40abfd178ff02d1fb54e8697138928caf02d18f6ba4e2d33fb7ce927e3207e5e2a2d7517a2ceb09ab81154279213686","0x84304ab1af56bc2fe2bbb4f1dec5c53b8ba8c860d5ff498895892f8e06a2f55d0b5a3a9449a6aa246a2b2a28f5e4149d","0xb62b948f676e80167e64e1d8695fb6a0d3ba7a75ab34f81da9c5876cab250772b6f609701e3f8a68ae92fa2263a04059","0x870426ad727177818c4f2de6a1773b97a1ed7098d3d2c68c77a6752f69809e9438b92e00ec8574663836ed407de72f28","0xb774b316003ffed1d80b78bf186488a66eb2e796187de163176e5bcfbf4005dfd6e41ae9b36d31a4c687a9f5d6c3296f","0xa4fc59049b7f556ac759e024d218028fba5bea1800f425391a355bb0730fcdb7555c46cbe20003189e2a0b2549ea6f6e","0x8ca712758e7fbc747e2c7b6c003911b1ed08d3ae43e7c1fb602407eff014562816fbaf20fd3b6a6ddde0453583a073dc","0xb5cac0d2994eb283045fe9ecdb421bc66e55cabe20234394372b83ee1f19b84d8717fe6020ca931ff0f9ad299bbb56f6","0xa2a576a9ead4b1280ecd99309a8e5a9d80fc8b4bbd3d4602d1295e60307c4c8fc816db09f60aa61b9350eb295e348be8","0xb1cf8f030f5df8fb4182ea92f1fb4f0fa70942a3dee6663da460fa20d399ca9b7232c4220122215723b4cc83fb702791","0x81ae478f575d58b8dcdcf29281bcc8701e20530a69a91ae6610a18a34cd12ea0c1b3f65cf8873b5d71922c4771393122","0x83bdd7a1040518322bd5f7ccb3efe6bc2f3150e498bfaf0abdf1af3840145894b5343ce0760ebd2a7b0d181db33e82d4","0x8f34e217f2fc0f8984c08c0cf1e316ab3d037e76a26f045c6054f26482e073dda7544a9d6a91e4f8aa77a09d42630493","0xb7a956389403888dc348d70ff310f7b71c520c194086ab3a9a1f9fa137843db33e8e44262dfe14eb8acf47826a27ed6b","0xad020ff8011e2e20be8f5c1f4d04fbea42542ead5ec0e5ab879154fe65e9fdd97d6ec1b3357e2ac43a6a7427593a44c0","0xa7d4e4c28c0bca7aaa5e6946ced572b99bf09eb78d946d9664c474ed243ee991074a752cdb55c9b037716b59b1a5f407","0xad8567f5bf75697091a955cdcb4b8b0e12effa995d3473ee898c0e18ba94c6562b8c6dbcce891e718b8e31e6bb43c0f3","0xabf9e92f40ff82091e208a9aaa947fcbe77ac988b3229117dc33871f6d5c195ef5dc45992a43d8fe9dc9114cd2c60cb4","0xb79d63cad83b09bd6647ee86f1eb6ee06ea1b5e910d1e11475f4511b6b1cab0fca29063b55f1ddd59e853b2a5c0a0804","0xa5f9e86af087c3e707621d154ae469131e86726899542abbc1be698c68d44514fbe744a11a21ba383a52d320c9ba6b53","0x8c119b84828d8bb080500f6896a761aa6b824167a52d36b5b926ef4f61fd3b66ba3783e39ebfaa02ffc33fa5184960a2","0x8e9d31c30faf8f7937dca3c6796dfb17eb923471c680e3b8d6f1527ff3e75e3f3d78d722c50bfe3ea4049bf627113d6e","0xab96e0b39e043007511d541b979d1bab010005b008edf3e60d1fe27e777b3e8910df65ca04ccc9884050df4907af37e6","0x8d395e19538a8bdfea6e14a743310d26d5b6da7414fa6e2691d787ad948ea458928401068f11bbe0fe1304a04177d967","0xaf5b436d83e00ca4565a9392465fc8d34403fa5d7bd8eac765bd8720f5b6c872588198ae66704381833d17730cbb559e","0xaff69d647c3f472c165328b7cb4523a4b810e814d976d47feeb19a3e35a35b184f5ef7212d4a369989304f40a055404d","0x888a7809b46eaa89cdfb46cc2d03e871b082e1bb17549fd1bf112c8407c680af359da64fa8a2fa9205037538b77e9a09","0x88a262465bd4e0094b06e116843efa239b2fa19688307ca8b0f286c959330c22472b160a910f57c75a6d31a07fd1f862","0xb6aa7a0e904c274df33e9fca9820b68c96a410b5cecaa32f57396c43ed45028adb92240a002974ef1637bedfd8fdec73","0x8a588dc8986a4752c560bdb25d353106c2df8b97c86e4676cd92bff7b260f7aa06a6e98fd77956d13a17eefcbd0f3597","0xae03ac68e7acc04a384db3b59fe3525779c3ccedaf09db21bb262b429904cce780c270fd7891b27a190bd1b0dc969a8f","0x83c4e68ba008f8415e1d98817f3df0d3300351a781c68038a56256d73bc8c29109afaa34a96f8214f535170c4f156967","0x870b4c6b2b5e28c23b87113dc9d795adfdac2852d33b39184576cb3b8b5cdf38059b0727d0e3eede77693d38c8f9d5bc","0x84f5785930d19fcc140b4b75d9c07fcc819bd7ad6a6e39f741df8327680e4bf4a0a5fcefbfe353e43a34133262a59d6c","0x8f78fe779f858f9e21497f049c5a929794587d918a81c481394d0ec5265256f18a57a418244f4ae6df8e8b1a22aafe42","0x92a863802943e52b6ea1fb29f17a156fc36dbf3e233ab013292533d15e829a65bb5df9c9f20d52afb754a8feacb16b70","0x85741bd3c673a5d5d45e5cada2d22847b96c961a46fa75691d71713e44f10c0bb5a9c54572a7aad549a94f3a519745d7","0xa7a6c4f8d5e4333a6f691b98bb2311c3c7f38bba5ab3c3153973767d3a4ac68a55b26170734485abd8792dca7b5b3a70","0x80e5cd0510e287f388e71e0004f9ec59200f79163596232c3c820e82dce36a91257e47200f3e4e2f53241f01c6240cc7","0xaf5f83a3e6d2bff6368f05a2a35073e1df0aed044f9321779c519a737d9b983c31f828c06793de01c2a7d901d619338d","0xb438d3278041ace015666eca507dda323fb43a41b3e0131a7cbc7fd318ae10e0c643dcf3a8144b27ab6619ef14667d96","0xa8ec27bfef715ec017c31f1ac964d8033086fd683abeb928f4e1e38cb5f652351a90cd1432ef2e65008f209b8a35cb3d","0xb3488109ffb4a772f16f336aa79e2804a916b8ab77883c45c71ef33b37546e76cfdc9e6bbf25fb0718c66e1d38a22ec0","0xa05210ce96cc45836fa10d0ba89612bd4e76724ba967c6fd9ac696dc18a6f360e9229f55895d3930c163314817cb02f9","0x84cda2ea22dd2b6792c8471b08334605ed41c4d79aa43d333cadb8b8b0af2822bcc152a5d525163759350ae6ce55ebd1","0x808d84e60232b4713b0c35a1e394ee93155ecd5e136abacc0028227230b980e156955d9076bd3100a00187aec1d39de9","0xaa6b3a298cdcaa29548b17a7e6e218fcd5da8d83e01b2e3a68a908b380e6c5f1a24d4a8a2bf20d1bcc54c935eb740a5f","0x89c21ecc1179d61c65b80a12930aace32ddf3a339a6bddffd7c175f7d59dfacfd0414c5b68180137cb6681ee4d4b9d18","0x87ab91fea8139aea8b6a11330bdd5b65514f82c99ad47d93572555054b96a577c358dcfdd52bdcb0efd48fba3125a9c4","0x8f39fafcd77c7ca2d3ab141682e830dd9b81710a39cee7b88589dc4d379476d6a888d2fd584894ec194c6a632168124b","0x86538214d5b4832202e3a3a6a41f5950e8e53a8ec77f2c96e109ea29b2a1b0823965d035ea9942e9921f6869b1e10db9","0xab508195bcc85d3b0958306c18a929de8953831e45b9c345f22927c7055436f59848ef7f2ed2444be986151fbedf1461","0xae431581b1325b90ec201e9fd1d8af5f421eec972bb3ec0a9b245aef66e935732115d5c59c355488e52faee0bca68c69","0xaf379326d5530a338e79f187d292c492871f422b23404b237f1a08ad73257207b5e5c18ead72646f0b01004b5f13af24","0x86d5aa717edb73b6de1dd02f5bb68a4e458deb2afcc374e6004e70a9f049b93c1247cfb6c1e979dddd85b0687f5770c4","0x80eded5c5c4f03a03f3fd02af0af4219bba009908c0f39ef9b1f0890eb01ef95e54908beb227cdfe3b9a1ee3a522eaa0","0xa31d15c7206afc3a04c5439317f49eef4be2af6ccf6981833f4cc3a359d7df7b409d89611c8cc012dde9fc17bccc20a9","0x8a8c60e831cbdbee7d798decb6c9d8d9ac047ac6fddd7006ff7928bb2ba5c860483d416cbdb5d1b860f007cfb5b370ec","0xad61e9196cc1bf09b4486bf10d09a2db99824e4b50801781a61c001411339250eae64ef4e64b9c579af2a24854dfb1c0","0x94c1a664baedf11d3f1b83de5f5e59e5c2e402dc6963f09e04c51534238c989aad757e9f541a72aa21b17803bc46ce91","0x98532f05bfa936a24e309e5d6e7175a51f1c5f9d65eefd178db360b898a5f7a2b00576ebb518e98751e3a5677dafd824","0x8ed0da9b41aad297b12f6e25312a8d9e8d812fd150a8474cde9cb9cee60e1f1fe4f1cd7438a9a592fb4ed294f9230828","0xafc39b673c34feeac204b6a612f05457668dfeba1a5ad9277d4dba47ef1a4da3695601656e3ab2672f8d4012ef9cb722","0x9280cf2af16b02dc66b056260ec4f2ede46d344179c42adb0ed06c14069ee064a152006bc8c0da8439f1092cd5e491ad","0xa009c0b7a10162701f6cbd1b9004b29101d426efcdfd3bba85a153b96b5d598f89015ec8c7e9c6044f34fa446680829e","0xb45ee2d0223718476ae639f6029e55258c035134adc44e3865a5dd51d7c514365754d223c21313cac3ab3462641e1b4e","0x8d60c0561d7c071a22889f2dd5b8289705bf39b333f92958588ca4e376ffeed2397fab285631fc665c9bad315db91825","0xac16a5c241ecb7894bbb81e4b95952ab022a3b5ee218b7c979cc6a7be30a30d1a2e237dc0d2a5597cfba539a5cb6a94e","0xaa9e61a8f207e6e235973bb41d920f7b1c5efa0b398a03593ba01e59f47009e4c73ae778876857b91936aa30c6364533","0xad04c0250aee30be66666e607cedd7d298576229b7fb91a8d4828117769d42399dcd556539060a74faddad437ea1cb66","0xae5a912a9b99056a52206f9f3593546543f697c18a4d8c35130eb9fb20588be305354e9714206f679c0efcabcad1883b","0x80336a3065aa5e2c79bab2979fac51eec557f4b741530e1b827c2ae7422c59625b12f33db38e4bdce54cbe884a0db0a9","0xa7e5c4e28db27c4ae971b09fbf73f127da1f1facb2c93a0c0b2a1331d4af20d10b5aecc2809677ab9f736a7e24182fb5","0x8c9801971814d47dbda4e83ad6cffb1fc86e02c1f923cacbc759ff63f699dd56514535a293213741e63c029036813580","0xa81185f03e171c8e3297b08baabd66c5f0183544c0576a79490a0010626a7fa7a75141be452f2c17ca6895fbc0fe4bb0","0x9145efd7ca8aacd6e6777947e8f193694c0806fb531a97e0218b14c809506dc3d47e70dd719030b18b00875ac60c1c68","0xa92d238cc7db4dba48013f16ce1dcb5c17b9458f8d049b724e8e926ba8249a0db9d711de6afd1bc867105d765b56989c","0xaf8079386964ece109bc4f4ea5d080d478f62e01fd99696ed9b9db18788cfa6182ab22df9be31378a68d42d304239c12","0x959066d910d5721b4b08312a5503544c769cd6bf2b82fb1c000cb99e306eb0feaf79c95579beedd672d8ceac22d27aa4","0xa17e4effb819554251b0594f7d13fca22d71956e21773b902d801c240345e00f88eab114c2f00533830517d544d2039b","0x84f42162e2ebf1d0e115a9796932950abac083e22a77c0d3d82d19bfc56b73b3136da20fb388caa5b4abeb830cd29a99","0xb0752bfc0da4deb504484909e269f13e2f93c6a8c7cbff6b5da1901057fcea8b8abaf39d7d33bb8348a3f6deeff16a1a","0xa9be5e2655f4cb99dacf863195ea5c7f1664f9154404aaeb88205e6bc0acad7937bc3f7333a1c62d5c845e8cc7148eda","0xb7fdd6712a147adef2520e03c9c96bbf722e116a3ca30832f0f4102c3462cad6bdef6741b82a8ffb8426644cad4f9c26","0xb5816b63cbd43a7ad4d73df5caf603428b70841af3d0e975b6d64008118f141bc13364ed68e2ca6a3d226a116c1f2901","0xa2893462c0355e9bb6eb68b27832aec455e3533fc9444e1ebc3c80e4537062dc2ad17360c7ec27808af726daed896180","0xb42bdf87b29faa9ed0f171515f1a148895912bcab281bfee995ec7b6b46659981978e744a35024c9459a7189ebd7c6e0","0xad6017ff33ec4e8230c851c3808573b4a4effa220cb8113d2347dd4250057863416b105daad079df6d70856e563ec475","0xb01470bea2001a95cb6b3e235387874c3b67d0ccef2d6539c64215176008a84255051edfe1eba1ea892a90716d775f55","0x81e08206e9dd5eb4ac0ffa9f7af42ec157422efc5315ebbab35101ed322dab53fe86cecbb636a71050c5c9f412ee0dfc","0x80f0109a647b4b3c569ee543094282108be091849e864d1a78a5e342354e6ff9b5ae1cd846549ee283ad1aea94baf0a3","0x821a7069c833236130d2c624b5e790e37b95c476cc5bef9301f6997da4afbcde359079269f1ca1cfd9e544bb6ed12ab1","0x963e4ac0e696c6331f590432cd5ef6a10522e458d4eca435f098a4fc0669a60efab42dbb0ea85e9cd4792c5099f81321","0x95b5b5dbe08a93f3abdaff583d1770b8757c0aed2dfe0bfe3efafeebf0a08ae713044da7d41c4259a3f1ebacb33f9758","0x87566d317f1df11768c2d690af4fa63641380ed375e72b67dbab3d5031d4cf6cb31236c4612212584f1769eeb00275a8","0xa07834ed14cc06b3a39d9d9dd020eec4ef2ea57d5ae4a485b9008c9497c4933e9df87dd58ebab215df70011eec7744c5","0xa3c24bb72dec3645abe44ca9feb94cecd212bffeb8670dbf07f04d071c6f45b0b969375a87605c3cd1de8d96388bdb2e","0xb7c820ecb1e38d173b88e3b8408d3df9b8c974fe909a252a8827e050242bf0972822974b41e51acba31ec9c15705012a","0x86d0052f02d3eb4398973f157c093c1e8586c4d6de60d70ceff7b0bd5e833ae36e44502f145a7ccb62e4777affb1e274","0x91f2d484af522229f4d9f11fec800bb3ef9e71b097afc372ee4cd683b9ad611d5d90f6acb3fd5b2515e05319d2916812","0x8b3af026f6c0ab8cc92c460ded037619b16bf2391fe9347a9167802b23f393ff944248db88891a260919f1f012586ece","0xa81d42083faa3064c063a508af3b3a693acd79ec8c02dddb791bc09f6147c55ce52a63e82b7a95c934e9e3ecbeb310f0","0x98828e113cf86a93715cb880e43eab289ead074032677e7fffa98854536694df733157194b6d28e51b6125f1ec1742ea","0x93d861249a0b2af351746736a88e23e9d7d668016b853f3812420686e256aef348bd62161e7b3c81c76ce8b6fd49a05f","0xb8ea1d379cd4da2bc1f983784ecff29500ed2a96b3b4884d560832e2a18429741067c8ccc20f3b4b8399e33994def2a9","0x98f65cbdd29f62ebc910b5b338ee14e10970dc34044b32e1232eb831c6ecca69480d2b9ec3aa2bbf2ad298d687040d73","0x984e617340af88c602a0ec828b9342bd5bff38b33884f7457ecfa8c23c559bfa507f6897334d5f466c54144d0763621e","0x8e4c2d3f8e5882f9d9d7773ecc86cd4baa6a884b3e96ea5c3947195ab52df18c6fb4b22cb7e8b5fe58fab41d03f8c899","0x81c5ee117844c70bbb6996fff3b8271c8ccdbbc5cef686ebcc0be9b172770eff51e48d38519b1e9b7b780d34af4f5242","0xaba46ae5407a4268d0d8da854da81cfdfe1dd650ee2560543cc27a6c603d9a9722487a2a90d12b748f7387960f83c347","0xa9e397adab8186481ae5c33ffda3f1630966304454ccfd6769fee999c8c252b3cc54df09a88a44b6da42f2fb2c24104b","0x877c1fc380e9f8f8541dc27e80bd25fbcf1dd7edc8b0d21960508c8761a84ead62f6fc21a52f7c17f37d367e284e7e50","0x8e2a69ac872f06474c3b89147102da6e3e5d030882d878c21cc10a106e275a0448b6208d326f777a5e4ae9c056a87f35","0x82127987b085133f39fd18c98355c5c09ab0497b17462e23f9a06d9b99f25a7d5f13564edd395c99cc2ae5df67a6be84","0xa6e99d89d33ad05d24ee8f8e972ddf8fa3be5173eef5b183d120e32667496a8ff463439cf9364f86003cfb5f332eac69","0x9656918f46113d37284e862368f787f689ea674d1947a5e18ed97a5ed22f9ddc495ff067ef59d5a7f5824f50b4871460","0x943193323645f1b9ca7ad796695fa1786be0b783116afe247a132c2da1386a0f7479b61778cf8e7631845781ded35cca","0x8129c94579dc7a76eed6ba59e87a34f65144fc268341f2b79ef89b253621e25d6e10f072b40f934c500108d54e5cffb8","0xa143fb67159ae0bdd307f4a66860cbc007580077f3795a808857190d88aedf777b67a7a0c2f14854726fa4c12db6c1c3","0x85ec2233df23fa3d93a03779c9c755aa19c42cbfe4e85dc91a0966e33c5a37d98fab4a80125652f8a094e162399807f4","0x99bd0d460a43d4f25fba032255436bb04650e82fd9a1814c8fa1e30c470a0263c0328ee3594cf4ffa57aabc4b49651dd","0xacd32896ef56dfaa274951fd370d113bfc375a99673ef198d9ca55866db13d17c866650a872e0d2ed2092b001fb84427","0x82dd320f5096102a153326c9deb53459ded7b44def51a0e9af1a114353baaae2aa8c8e99f9e407be6b38ddc533eac05b","0xa00cb65c5de8e038ac121653c6dd0caf3a2e78b8774e6122ad83022235541a5f1a3c8272eddb843ce6f71d15b1717204","0xb2c105802282c42e684810ecbfbdf2ce2a98e18c2d73d8f0bbaaa9832d0006b3a57843097fec24e9aaab33ac735d0a39","0x8453c8df814a92088008d3ff6e72e647dad3ea823cf452140e4c80e2d541a199ee3dd3015c6d18877c6ed3c04a817c91","0xab876cb63549a6e511cc493d4d78eec1f02e2aa37ba8ad09c1caa5abb9e751ced6da168a397e6ca11260fec5fb027b07","0xb9976a270acedcfca1c0b70428f2ec4d4b5466308296e022fdb46d64dba2c7a29bbf3bf8487f66d725a7184298ab7d6f","0x944ef129d72bfd764c8e859d7e88914626cd8b2b54491b5a2ca83321996254eb316bbe3fec3c1250578b06bd48812034","0x8d0445b6222f705ce95b6690747b34ae856ca5b14f4f57471121f7779c776e6af127bb14f7c47cc2cc25f5d6ce83b4a0","0xb1f1bf19d16b5d44d7325b50aeba2ceb9ad6974abaf6e140bd3b53536e436a2192130ccbb2453c533e64759a0e0c25e9","0xb911ec98863acbccc04b2435cc21ab9eb16d7917f6e2e30347b4b0f80db2c989e27994600747e6265af8b7b552195f07","0x8f4180e20cc149b552aeb30cec2c3c7ec9ce9d60c855188676feb1740f8d1d3805c8917a83888a33b2f3ad1fa3422e8d","0x906af7add69c4647f54a8181d4ab0df5dea7e40e259532553e8b94d9ca397f4497f115c3c49fd2e41f2f1c38b0ac7d68","0x95243d9911b7c4ce9a6ba5cf4ae0604e39a28ef62fbb7a8d04500d2fdcf109cfb6a76012b6df105cdb6d05047507908b","0x9212d7259d5154f3f0943d96881b3edf854167670cae85bafacbf2c63f61c03c0d6fcdfc506ef9b6f8a3605c523e1f7c","0x8b0a86517327a1feba276b5488291884e883229023448522d2061b6b0d3b8673310f32b8d68b350e1f6afc3adef15567","0xb690e7f2ea48e598664466475fe85da1ed8511d1faef9e918b2f5c8c3b73d39893127de4047dcb562ad90fb5bfcaef91","0xaec3512fce1059db77c4bb4feece0d5ccd231c6d37eb207348efd2e6707f124503e9561efaa77565a54df3195f6d456e","0xa420a6652965fbfed465fd9f7790bbb5e5106a2d9bd06ddf1679157b63ef4f7e646f253e2f294d4450469ac832942b29","0x870bf57f9163c5f9d534acd2e871e384c9111eb8236d609ab19819b3772d45ae7eee0ff2163d205a6223603c2f328b49","0x87749fb07f360aa530266adac5dcb84829efb2b4bfd6d0f58fc8d8ae7b9f33e3dd21570843813ec57ae7b6fa8dc652df","0x809d6d8577c47028a85e0af4c5645f17accd58b45f304d9584f8515c37c36ea4b5a795bd423406f6d2c9d94f15c68eba","0xa19fce025afc4d956648aaa7add05eb1c9da5c0edc16f175729d03936bf5cbc94894885306d652003a3e12dd4b25e267","0xac7d094e12e438c9ca0afd22d9fc2e466e16cf5687cf07c23b3a2660a89ef9603d55ffa77e790159766c4344b73e2527","0xa4541de7df152980d9462e62aff7dd9de1c2d63458b060b67c27fd6f159b5fff41ce01bd9c692c8bad4004aca7c67052","0xa6d3e4f2b3e53bac9b73a5d1153448934e3fef9ae45172ee91a0f9a6af6b18fbcc0dc1a934512b7cf0df6e5d1c8159a0","0x94ecad234a4fbb8a838dc7e8695c05d8e508bb9a1d945855cb90be9406d5c5fef41f1ed1dc8df913fcb6b90739fea364","0xa08c127b90a3498f23cf6c77c217192312c9b5391de7961ff65bd8fc3fe5e859a05dae2dd1ea260c21e13b45b581723e","0x8679cc9207ca2e97bd6ea38089881512b3a1ee85522902f88b6d64b15dda9fa00955fe2d84a84fad5e414bcf3ae63759","0x803c6efc5c66fd3513d48ebb525616fc0f1c16942ffe77a77b9f3131cd1976da3d043c64968f5594c91372e4796257bb","0xac48692eb7911e1003b90dc4aaabeae76c0851071fd2b7de6ef6f8110728937d8e913934230a1f8c7cc27b92871e2d5d","0x84ac58334f971b2017241ebee1bb184496ca9ff4b94c1e39731e9ce294fa30e64df90f065376638bfdf0f965b51f7623","0x8098d9d251aa2bab7aab14b361414607841a65c284fd024f0ffb7674752e5f1353d422e212360b150d4ce11d3aad3888","0x8b1c304322463c9d6e7024e0796b41ce23916e5e6c17015449fa89cb418fd2b3d72225007ec49b6762f8b24d3c765c79","0xa436e829a0f93dc2060e93d9c5128eb2905b77c549da49a656e47c6e17418348e0527e765ef8ec42da77ddd9e455825e","0x946e930237746ccc6eee176da723b03328e300b8d94393b2e9a4feca602f86dfe4ac61d42f32f0163c54e877da95169d","0x8c5a2ea7f2f0dad73be3d8a10ec9d6109296ecc0d4adbd5740807f187c82ecd647e18e67554b6d63ec163844842bce0a","0xb1ff25d9449cf15e06c3ecfba92005bccabcbee3494ab263b1aeffe9f438980b3406c1ee93bf19efed84e9e0c3913438","0x8169f56ac458478494288506754e55a56377d1bc4317a73aa11083819b26aae80671c3919e9f6d27b7aebc1dad4888a0","0xa48a76985dad5fc43ae0d8af47e48d066de889eab0940b0f3103862366660730c446168cf969f09f353c4ea94f03c18e","0x897345c6ec8d11cc87382b7f886abee53eff547c24307cf4d4c278e6310ea9b003252715a5464201e3719aa3fa48df00","0x8e2f326a13b53c60a5ef3a2e40b37f11b00ad479b80a263343593950ff424095a6f70a0799945b61b42d11bd6032fde2","0xae77f74bf82c4fb0fcf510e2da6273c428ebebc20aa42b51737e44983c89d2d41b6295352fde84af62704eef34039b5d","0xb0f73e95efe10e01c2f642ef89a85489b4033a0b289736a3ede08adefff5e046115b89dd4f0d697253208c70e268f734","0xa6fd12e72893efff97c86488e0e0f7d0dbe7f6f0529867a7598e028c1fb7ca6ee3805b62a4c3cffdc45ed73b1031590a","0x8e29a3cb8675b6e747b99197bd53d9e6152fa0f5ffac66c39b1e506d0aaee381dca01185b6f2ee10e5b708e64a0bfd0f","0x803217cb8b2e05f9f4856308e8887bdcdb8ebc4973da7843d642763c7675ba46ed4ad19da9c8c3a8d7ba4be200eaa84f","0xb92e62b358bbebab8e015bf0f9c4751ccb0f5dc328f457ff14870c3240629ec7b18c3d2b1fed0ca819340a7602e16587","0x86bbf0b212b330c59344ebe0c3da4cc0310722d57a220cb7e11bc30f3990972e1c2df57405251c7a4fb4c7d5c1802c03","0xaa948dc63e172671d675e27c2ffc8bf1496658f6c0ccb0dc7deb6e77a52e23312288363dfa8b9b1fd38efc176c62d9b6","0xb585a95bff51bd026c0a3c3e684b40b9e0089e3864fe8e0ca66467e8e25d4779c7459621a9c1462ee4c64af159c24b26","0x8afa094a06863f8fcea887b37f92134170c8e28f746f5c5e496c9e32758ffa0b5d131f50d83f00fb33c1b815c8dd62fb","0x9327a5007dc2e1589fd585937d6debaf4a8fc105eb899fda2f805ed8c238a24cf0e3cf556b3dda2ca023ba6d8acf6e48","0xaaa5be2779997264af05bbd05d07b82f85b61dcfc8c632b500540a37c66e7608cba03272b665074fc7b6e361ef9b08fb","0x96ef91e8e10e2958cf6560cdcfe37caa5570e5c2698ba841176f709feb8b7746ad18fdd01027b421cab990e995202080","0xb78a09e229d5e395be3c248edb221da6e3bd4bb2f1bfae0421b522888a5262ddddc925ce9c1768320b5965644de3c449","0xa708ec06245cda4ee94e3858f15a4f7fa5e496d0599fca3af76b79309b6c69cd1570dbdf0242688e9ef3dbf5a827812d","0xafed45ae17e354ba9453766e5a75498990213789323963b6a63d9b81a37a363df6fb837d577f461866a24a5f606eb714","0x957b742ec7ad05c72a819c56de063bec0653b1259cb2991557d01ef7bc5cb8dfefb927b303754f22c1f68dba473332cf","0x8f857a189027b4795f046867e7e9a64dfa291815c5dd7f9bcf6ca5e76247e19e65904ed5ca0f08706980f03fe2f7214f","0xb22b6645d1db847e61a4919859512373b9551db5726a55b47f035ba6ecc095c4b9ae0debd2cc9874eaac32b24f5ddfee","0x914848e5b0227921417776fd7d4a88e31f91b5f2cd1851174b9e48d8595a3f42cbc275b7f9be737568f563c25cb9f535","0x8431d93aa5fec04b120e48b8afe0c80b5dbac34e90cbbce11332b7d5888210f0d566618a42e697ef9e276def8319c947","0x85c6b4c39f3aeaab16caf655a77437a731c45847e1239dca05f2626f5a3d68207c4f718147082dcb45d75875d7e3ab50","0x939fa1d10d74209f393dec0f636f35d696e1e7fc9a2602647f8fba3b55075a166d84c7fdaeb3e0d7671559a6af0ee024","0x80b9ca4374339499d170d463359a04d35f935386dd1a70d82918770a45fa11828880d8566db7967e07020c6a0a65586e","0xa43484d63b9c3ffa3a977bece93e29da84c36b13280cafc05f304ad525a83ae0b7c5fdfe0232df040144a111305596e2","0xb225945c1495eab4d17fa7856f20c5cd0b0563731d10b05b94e96d76bac1f54f0fea7db75b769f128984cf4d875379e6","0xac0cf832fc3d786f09d93d79d352e60a44e0173941545d389d7f9c6d4c165946dcaf8ee98250ea16b5f268b5ab292b32","0x822b8df1139b112d007786be8bcd1ae42ec8e4ae82ab17877140d787ad043cc65c692b193cb5302f68e85b34dbe08341","0xad0fbef2982aedc342a2fc04841afcddeae11ea31e18fcfbdbd022bb7beca710804c61ffbe537d4b486472377dc9808a","0x93cc16184224ac01f78bc2d3f52e6ac09d8927ea4b019319774f44c2a117fa1b3e6091c7acc0b04e43d1850c6d0e6b57","0xaa7ed874004770226f26d7b9cf6fd6b2e5b31ce27af72dabd70bca0761fcc89ad2e0dc321d4d009faf61486a0091f684","0x99b8e401b0db8af7151a84f9b8341594daf1956195cba7aca7a6bcecff29afc183557cd60e5de1ec144d0d577efec2bd","0x92815f348f46add4338adc506988c1bb028137afbc30e7036138bc7a19be214bbabf2ec5c77d46f7e38ae05a026c52b7","0x8a165ba4f7d1cdf1be8fb63982af2d042bf221472242aef62bd170edac272d707dbfd044c54249ac6dd2d1e99a00edc0","0x800f49e46baa1489af0abb912e100246ea04ad2d952fb94ef7f13ac6a9661af41c2316728ff5e9944d8cd2528a32c6bb","0xae1d8a0da0182f3bbe314dc101b04bcac042151e27a8eb9c749ff1a64ff73b1a4a0a8555ca56ceea30a08c2045edf6c8","0x8c6ea4ff88fc47356e8f5434a600b8033e1e23f29e486d890e278d3775d28ba4966819e5f2097b69d60285ea8aa0ad90","0xac02b47815e3f0c819a7a15efc00d3b9ff17440f39a2052c0b6c9ae6f4e22a172903281cd884d0363db7301801194a0c","0x89aae8ad04e1c1ab1ede1bd69a0960e2e3513d6244533928cb92439b1057563608a98e20a70e8bf60582118617586a00","0x830edbd9c57f1f2e4c387f3eaf333a6f9b44df3aee4a0d62e41f84c353150478665d27dc67fb380cd582cc5f31892e31","0xb68eb3600870777b0b1223fa385db8bce1cb19b471587befe4e8ff902e9b68bea9246f080fb6a92db215dc09ed9a9c19","0x88d9abffa36a7eaf885a750c7d03cc94265c7a11aa472e7fbc86d90bd71e1aff397ddaba22277e639e181804cda1736f","0xafd1a2febd7f57f7182a75786b69ea45bce910b142a5b0d58e349a4d70e478caf73a8b8604497a695caf3080d06c2f78","0x8deaca21c9468a676d4c42f89e74895dbce225e5e0d7582a13e7511bc382df8271355dd1a906f2d7cb764f50b8ce898b","0x8f7a6ff3186497e98078e9d1413ad3f7bee2da127961e6aeccf9f52e0da6fa0d28db5264636390eb24c1a7d7c1b0f302","0xb7513baf6449d5812c37a58580cdeb602c8f094f7a27d1b8e47495a31588853ec733a6c8ce0522677cae4479cb3dab74","0x901449b598d05686d5a2425abb0545bab011cbd826cad997a5bee0b58bbadca5a4413888181ffe9a2d02a400a92df385","0x8be8c9304ea5af857b70ede691a26007483a0d2176712f0579577e951803b6df84ed55a564dab13cc8159cbd2b56a650","0xa2b14c8069aade827f48e9381f2b0fb895ed66f5c40363145cfeb7206ebb346207b69c2c665a38978e7bacd23a397fe1","0xa7a9087d06f7b3e8ca96c85fd452a8150c8b658397001c17076036e43949f6344cd8d4c201668c0327b38eef77e04f36","0xa61ac27210d0e94fa8de7d46d1a57983d6e32cc928354d1f248d370181eef263c8d24cc39608cc5a84966c0010dda4ee","0x916ecc3080c1461d0f4cfb78243a28d3e4b31e82133074877c63434ddc651c40ecdb0105eb2321a2b03bed5a0544731b","0xa0221cc52830a69db4b8a2362d93aa75142ca4f502057b2a84e47350809b4be650d515428d7f9b42171f59c59dadffd2","0xaf70aa572e19e09ac985c9928b6038bf9e8cd7e5b8ed6bdbeb8933810c6e327a69d7ce0a633a84c5a9d859819e0f311f","0x81c728a618cb9ba739878971caa6d080e2ca4d24f3cd0b88c56c42d912c5c4007d67b106c58e7534a733e94e2c5916b1","0xb3bf16d77adee279a5676519e7e5ca914fd42dd76acaec9b6256f737bb98b75d860740afd0f1e413df8d3657e4a080fb","0x8a0795abf312f187d553620c0d1a39682d0a480ece97bb55151829f8b9ad88edd017c75345727cf1744397f91648fdae","0xb7d1eb9f503824688a6cefec8977d65dde2afc438467ffab3b3c574e8174de4bbd453260a8616232fb9090a3882e5cc0","0xaa3f8553b604e03d6e9b6ae034b355eac8180aa57e636c353afefca951b99fef90238b6510e74eafed11ad1e6c270165","0xa0cc9972257193cce6d7781d5b9e2abcc49ddcb371f9a07c2b4ecaa86f3b8e3802b37ac3ef6eaef9eb5502370ae38245","0x966c444d8cf412000270ccc27809fe3d81713702cdd42fa6ddb89ed2209a5eb88b705c5c86ea05ddfa06cfa3b720c79d","0xb902937082ffe9943bd98532a4edfd122eae8bad2f747e42dd23b3c6f8c5e618a966d329c7db021777108844bd9eaaec","0x8eb8faff6d0e8c27e8a498db77a10d8b0cf89872d860b5f895a321df66277146de285a7f67dc8633f7e0561b92515c35","0x882cd7a379d1ae7d764f78695ca7feff7de25f1cc42e4abda91e34f42f513baf38437bdad26a399da47b158cb0762a1f","0x82d38329f5c109c872be9e8e6beabcf8008599dec5efeadb4f03f413f2cf7b55f1746cc2086496010dafffaaafed9b17","0x8054c826f93e46871c5b7afc462a501b08b3bb48b3aa85ecbc3efabc5769b82ca490875d91a00b8496527224b90b3157","0xac213634c63cc34b680ae58cc68607c02dc20382471e598053bf266b7899f005415381f843022952040926bdef9d47da","0xa462cc3e1c6f7c663e122e2a7d9cde1f6299ea7369067f859d9e2c6b3ec3170663364336d566335d87c678c438e8287c","0x84f981f4f82dd129279ce6df137daab72dcb8996c6735c9df67787aedc270c3292c59230c3ac49e48ca338bb7198d9be","0x8442e35138b751760c902b0d182c198c70e525d3e34dd93e08f452da8b7d42603d1ab8b23b9d527d4041773b2685586f","0xadc95106d3b949a661ff9b449c9fa34b82f78cec018532ab72701a9ba4d680f9d62e74966404fa8f36d7b017ea52b8a5","0x81527f462f4b5bc0aa85fec3beeae1d76902d9c63dec68585be09f14327d097607018bfee745c37ea06c4eb5e7d857f4","0xb4ca6307ef0b7e33e8923467a596040c6445568f4c6ab0306f5d042ed69b2940874b674313ecd4cb4d621a3020ab03dd","0xb8176ef19874a66a6f52621797e05fda566cff41355e608403f05ebf59803fc75c9dd31f6288aa76f37b05a58cfb7a1e","0x920603e7c83925a7779535a59ff7eb02c123982d94bf96d34f8c89a8ede1fbc089ac568443e946231035f37ca00d914f","0xaba42736234e56ecc3a74a650d76c1879810e71a2ef94fd1d846e2c7e16a1c76872fc2c1f919a5ea9a8f62d7b272873d","0xafeae8ce7b00ea530f11550d29d228881188e84468a2b1d6d3f6ec7562d23c55af06f6318b25ace27f5c6f59d090ec51","0x80bdbba09c161032cd96ab947b124c35729f0c497d115f1d730a43ccef060122bcc8e7ac6c9b6291c5d96fdbd3b9ccdb","0xa2922e3020f110a40bc7edee2e530f83bebe3a16cd2101e6b31ba09a4e67ceb8b80d8c837fdcc16be0a10b70baf39beb","0x8a623c292fd8fd79aae742426b1c819a6945b959890489e1cdeaa27697ce64013806d7ec7213d17cf7c02c708689c2bc","0x8a81c13c57c32354b8ee5fb12ead506e905ddced4d4cf453c3d6f30e1c446e8082ffe5e457dbe513caf90dbe8269dde2","0x8ed95a0d81ffc72c2f2329ddf6571ac7d7ca1882b3daa745bc9671b891bd73e5d9c82cad140bc2ab30c63fa45370ebf4","0x8498ff56e64748a0f6f9aeeddcb4f5b811809213785cde4ec695ff692c9f70c4b612ad7e4ca2dad2b714c2359cf25f8e","0x904bad2889636ce25332c1c46058bee339436d13cd32fb9c9498ccf8afdedaca6763f1605e3dbbeba9c16448bf4a5c5b","0x978dcb07f32b3b0a91dd138e6211daaf011ab944a87efb6594eeb5c18694dfd58806bc2f3aa441930cfaadd1eaa885ec","0xb341a80a61116b9e48747bf64112a98da3e981c90560cb320b67faad31c985ca8676c793e4f961d45814b571bb90e45a","0xa10a4f5082e62ccb7a5efa49d04b13950c3e494c7051ae28e075d2fbc6bc708d91bb0d3cc53803c73ab697d6c2281f8a","0xb2d56fd91ef2c7de62d0c06aa921350694f8b070f05a1daa89a3db2ec9a883f74d5b249f7e05df692e0f12f751dd8a40","0xb1defb247403692756c65598f1d4466a8c7e6d44923c2aa56528a5756adbba49e1c9250cff9f5a960a2047b4fc23840d","0xb2775e5bb8584e3a95f44a5ec40bae3ddc58d1a3706d9c4199ea6272303cb562042b8a926b5a8feb370caf57d030ecdb","0xb980a11f848938eff60b645213b4e25108122f58c4fa9af7aca1ba7c1ab919462f563133680bb479da72a3bbfed2ce71","0x9233bd4a89b3f3d0130850ff0c2861ad5313ef9d7264ec65986e41363a5396ef255f505ca04e4249d9d6c7e004d85599","0x87dcc3d5ff1985bceb27226a6292dc35e8cb67cbe0382453e3188a7406c3ddfa99f9fedda2ac0128ea1458fbbccab13a","0x9928ef8e0888efea39f6ad2a799863b9c1e661c2d8361960cd42e5729446663edf4483a0d711066fb6c971eedabc5f67","0x87b14833e2d50e983547f4eea18297770e0deec4d2520f46c4d497ae306c99010cb40c2aa0463453a8c693612a956f0d","0xb1dcd92d0a691c2b0e83b2c7a1a7cb7a9067b166012a2221e0938ecc7e505e492630e43323c6caad8e2b08166ea7e9a1","0xb0bdd9eea8eaf68c7521408cad276bf8124bf4fffe1b25e7dfd6ea7194d495adf829119f53b12fbc33746945273d6c7a","0xa482052749b82a53720dd0ca009ba623eacf3861fb29af3bf1717c1cc40dc48db8a7bdd4f1f83ebf31766b1dc3cb80aa","0xb9f5c800dbe8c903c7ea1b00075251fed15dff86b3968734152b30fe74288aa2e642b6610aa14dfaac5bc8a36b79bfa1","0xb5372849ba989178da4affb3f42a8d895ae8b2e547e2342f321c8b19c15a8e196005560f57a8ad5756eb9f19650ff700","0x951f4ae96b38ff817bcc1407ebb41a0ddd581fd8e13e752fbeb2814817f04d3de31c065294e3ab0b9b5add1f4e36035f","0x86ec4a5b06a7393e9eedeedd0f1dedfeb971bb8167a3d37ea9ad18d7dad350bf22cca26a0163e10f0a1b93c87ecac6fc","0xb998053bc715985a2c3620efe8f3a7a0595358de79d596e518dff47d1c3cfb56cde121135ca6b5d2ee5b3b5038a148de","0x97a121b9080e2cb83b42311423a0e72272260a076ced4d79f58324c79c6093dc2c6bddd710d69e2c44f1745d347826eb","0xadb4648e82708660145cf5402ffd26243d9a5b48f4682eaafacc3687c907feccea7d5f3633e66cf953dfc8e6cdfb6ab3","0xa81e2d65aac37ff752041c59103001357453a01e9620ae777917cb447cbb16a1b65abe3a1caacdd21884d24388dcbb88","0x806b4674417bc368d20cfd79c19382a9d26756d1659a9970e9167679fe3ac783655c622e05c75b2662707014a558eff0","0xa97b4262e04343688206f3b0d09c37865d041fdec0f0f777cabd7342f9a7cd8ead4daa2cdece40a0ab745c6bb8468d79","0xaed8d527e46433f1e83161583083be1458eb032d4aeacefb20673769156c8479ffaaf5e2be91297b41a208efc9e1b6f2","0xb5c059f84bc64c99508f24ce5b9aece5540a0be0ae00a22c8544f1ad0b9249f86519e58f7969886a5468feef55cf69e7","0xb37b17ee9772277af5f8c3ea003711472bb64b3b8ec69601eaf5eb256bd79dd92f91d8526ee0865694b6d2a894c96bd3","0x960eaf082c79203eb8ca34e73a416a7fada41f134381725e8dcca40b792fa566b289af10323b1e661111c3836107a40b","0xb846f01dca27dd5781e34a0bcb14813e8eaabd4fabc21181993da5938945b0ea595814a1712641b38675a8818b0632f7","0xa99fad87b88fc035a046e560e74c27f493b385b70257eda82ac86387f0acd9efe8836c686d147650bb69f4f3726d864a","0xa5831eae6fae87ed78cc63b55f5e8c6811de60909cbc095987d58212844e225d3740209653dc124b3ad50239b13e0280","0xa2320fecb0130cb923087399340f00b012dfe90ed2a845d201a75f985a043d2c09c67e4f882518441ad520f181e6b213","0x83df1413167d1cab673749ce937b96b5e759881f43c18270c08206a0d6af14e44a02af09bce328f063b16e110a81c662","0xa03adeaffdb2344aaad346d03d1cab9408a4fa8aaa6e9329cffd63fbe8c6042935ce3818a9725d7ee6aa85a236604a16","0x92047837832b8b051d50e7e73dc4921f84259dd6638450c451ef0a3d8369566d41ed3c0fdc189e2c69b846b58da8ee43","0xb1ff0d0753c543f73a9bb47b0edf20853d587425ac28f8a1a1651161a93b2c5a3ba614ed2a8ddeaab370627e44d0ea70","0xa66143123ac4343dfbe2da065e1169c6c5fd24bfeea09ff1ca52e82cd848be815988a87276170a709e794f0715438503","0xa517887596abf357f91a02da15008b61de3b3e59274aa9e54cb0325a03c235d86a4e2d59b08d9f96fc6937f64e7c748f","0xb1940198dadbd4326e296620d44bc2bece02920b3a4c2337a4f12a4428f091edf96ac9dd33b65c0841b682bb55d6660b","0xb16a03cc87ebc3fe54863d6d19d2040275184039ceb0b18c656f9cc92b9053286ee23d694734f11404af8014b6bca12d","0x99fd3078d2526b01c526e9d18e8f37cce5977ca208ae2bdbfe6b97f8363d89179780836110ea3bca3226ee6790daa6ec","0x95dafb3752ee33813eefeba921073feeb5b52108f7bf17616033276284a7768c79decd5a990a4f64eb973ea4df5456f9","0x89f8939ea6e1ec59359fd85675166fb473761bd4d2af87444eb8f6bae33ab4ed21dc99aeb282ff5506ec5cf1c042d2b7","0x895e61f7d3c064b92b4ee7b7989d774f6941a6bc82fb6d152764f67d2b22cadaa70f97e812625221673f2abc6fe9e3d0","0x98ea3fdb4aea5a8462c7eb84df196910a1d4f56a31a63272c1b27a27d4e5ea086fc2404436dc266df788707e3aff666c","0x9582be72e22144245fa0eed7934574ba686f48c8dbd65be01a25ec1720b873ba5e42d524a5499802a40e800f27803b13","0x911374523f11a5588e5067473b893902564789f62589124e783fcbc0b6ad577a18590cc36d965f8b4f83cce9a0173800","0xac0ba650bdcb6b75217f7e18909fe5e28d082e01eb620a9bcde4c592ca767c89a3cba6fe8bdbadb3c42e9f06e2ad041a","0x91da2433ba4a778456212076306b70cdb5a69adb73700888dae22600361b4d3ec69157bcf4affa0f8e314f1ee1ff2331","0xadf257fb09aab6e112b3a90da9a8825d25fe7c7da6303ea0930454492f49a22aeccf99f0e960a3ed63a65b5578cbff02","0xae379cd27fa5ab486172fbe1f55c2236171f4d6c4c3b4ac1d5c05ab26967462f1e9a2439124d1ba5692d3fde8343c943","0xaa1fd5500dfb05a5978ab65fc7de1c833971e574f32eaad3902f967e8ecf50b7c2ded5352c057cffe394804cd46b8f72","0x816041fcbab78bbf0ba2574d8f9557801b5241079475b9c168800c0af8bc0f2c33171c2698c009da39af29345d06426b","0x8029853effecf106e4ce53f0a97be8b7a608fc1af10972e9de657f4c5392a62aff379ae27426b4bf035e8767ec491e13","0xa1a4510231e461fca99277e8122c0f040024d4126b246fce628c911902a3f0894bf57cf5e4daad41567bba8acacd54c4","0xb090aff6e74dd8fc1eae1aac33940243db12ecf095070928096c9257dea8cd756964b96eb4fae517161b441bb7d98b67","0x80c5f0c4b5c799a817a5e988f478d73d69f62112e5a0f29e2e91cf2144a6aa8e7b1b6e3a693ab3660e8d75a53e15a2a7","0x98898d3122063b141f9af75033fe7102238daf1fce58979fa3869d592a992af4b775ecd0a6a94283120ba8b5fe10172b","0xb54392f48f10c76706095d184eec0b311d3de77fbd42a02357c7609b77b311105fe51fff3f77487e0a533723421cb271","0x83fff06c3c6dc1303904f4774bdfb01c8e8c60ebf15371a629a35f3c44cf77be2bfe62370b44f177ae0510f1493ae84d","0xa7103e935ca20f54578f6d9bd329ea34b773eb7b882aa9de7bfe4fdea167029237e197271323a938ed9e49dafb2172fe","0xa90ddd99276f8f3b8c0620cac4ace16bb71346e138102834682d2ec756bdbae74fa27e22e0badc5e3db108a485875e03","0xaf9a61e6d9be48b95b932be38a9741fbf5aa258b372728f2c70fc11b2106d722356a4b527762a5aa72e647fec41e0f9f","0xb723fb6833c70d4f639f3dfd3c7f2b44a37b88ca3c0da6d56a896f80e892ece9651a59a40a31b7ee85527722e7e74709","0x93c7c504c872424575078f3a1685f08d59bf26b3f9793b0a2574d95e074829c513f9584ce93471f3995162be73cf90d4","0xa06d08000904500bb0be30e8b0f583782de9c14ad8bbb7f96f40c5b9a572f3949527897045404079f6107a52559bbdc7","0xae079a3f02a1480a49d5c7804e82e0b487d65c879cd663067e2622c3e0360399379a59d4e976378283775e5e557fb190","0x8f396933f305d5701f3d0762c7f6cd63bd2709d3e54e4b01d85f31d15a52b2a244eaed62f1174edb8816edd97852914e","0xb74e0117323f043501458dc9cba58103400f47e940ef40a5e49d0ae894d80bf84b21188ad3b27c653d1615d24f3b5265","0x928d2b6b1e8bf10454a53bc521d0aa7e78753ae5d85842eb304373a040788a75caf23674c3a0aa869b377539d231889b","0x9071341ed46e6c3a7a6a4d54f1fd312802ffd3dfcaf42c9b662b02d82bdbaf3d0fc3f173a73a0b68a3b634a5f70422c3","0x92b1e0d6ce2a43b0b19a412816f5820a3c8f21aec2001159d288e6b14cc45117bdb7aca5d91c74f130d91e3c0d19ec52","0xa40022724b42bbd845ea511d96f178f9ac0b7c54fe823442b0ed570a428449f2aca5eae3e92bc392dd2b4c33eeb8ed7c","0x9690a8624578b8a6b7403ca0564629f6c3148dd1b5d40ed93937da9459bfbfabb70908ba4a819426c4fcfce11c3f68c9","0xad6a9d22d01ae53a7ca971c036f62da065797fe3f95db57dd5d224fd3213ae8a55e64647a2e25c9faf9b6e0b88b207aa","0x8e02d4d2501b409dd531aef377562b4b05ab2298bacee5e05e19ccb696195fb7d9e0c9aedf47a9c37b2b7369fcc765da","0xb513ef169adf5ed5afc898bcc1d7724ff43d40ad5cc5fe3f365811392fb077de9b93e946c5ce80c98f3fc3023a9235fa","0xb8fdf6661617a05f59729a08cacb4acfa0bf6173e0eb8c41987c163ac02f7e8a9f874a192ba4ec8ee9d26604ceb1780b","0x886b6ed4e8fffac890c6ed715516332a58001c68718952e183f2514b711d50e3980a43dfef167403058fd10f8e07670b","0x807aaac03d96f718ed0f9b272645bb83016bec41b9fd78c735137168505d1eecbcfc3b91db557bfd2e4a33123ca48496","0x82733727ca654118afb093fbef870f9ea857a6aee70f5c2dd64de4537f6bc5b55ec5493e7fd9751c898aaf6604e167c6","0xa069d8c83f71c7f8f20833c097bc4f5ea242663b772314aba8535901963b2026bfd4e398ba697b39085aadf5f2050b86","0x80c930eab7697d76b336b1c18714ab1413da1d9915d8aec757e88049fced6f1edb9ea16e4ebc49f07f71dc23f158a364","0xabe31758433513714fb459ea1c73fc635bb5a2c3c02fb6b03ae28f833362f9147e9de283c989fbe95e235f268ef81466","0xacb14401de0496a9864d2274f18b390ded7f2ab94d25aad2fca7d5ab577d8d6d385d8aae8b5bc666cf5568037bd5ca7a","0xb34076ed45b0dbe102e14ad043695ef2523212b00439221bfa33295ba3e1846bb2ee572910b2d4cfb561c0cb2b218a3d","0x986cd45c432de4d9aaaeb391ddfe472683eddf98192525562ca587ced25f1b404ef33173f85bbceac29cbd7bc0496098","0x90fb3b0af9a47a2119efb300d6d28cded027d449dedb50972d3f5cc4ccf5ab6719d5cf4dcdc81f3a8326a8a76b0e93ea","0xa5c370978a916b521e2626552f115e91d7da168d27c4129988a0540d31c221793433e79ec0c59ac74ca168ef1cc082a9","0x8e2732b1c760076ad10072174c71f74f69cdc085a8974b37dc45dfdf392b6aa5920a1abc445805274977dc83c621974b","0xb15f7a98d705c460dda1f89b3071c85d797aa6fc6043aa92c4fac91f29eafdbee72428e24c65812cd9786b522396ff08","0xb727951d43f98074707d57f07fc6edf7a9f38a29fe2faed92b473d244582759ca1217c20dde38d0f6b28e86668d40050","0x80a711b8048a2d02c299b72e36862dc6a763a4e19dc90876980cb392bcd77e1b766d927da5229b623e978660e1bb8377","0xaa0e7717aab33707e6060e256978317acfa58781004b43d77e7d31f54f1d784c33a8ac2f903a8588819062b39af6dc96","0xaa7a8a0cf99c7f4de95d3e78a56b67206592817da723c0638f5c7a4098b28e9ea9175dccdcead7b237e3f97e68996e36","0x800ddc5f11a1ce405d8f208b83e605282fe483738156542e601fe9f35dbac45e84787e621e6ca75a5da7e84bba412f11","0x9963b88c388d79a92c4bd698928774610e9ff5ce903af1d2d5cad36bee55231f311d73a4222c7ae5ce71c432e361d7e3","0xa65d0e483d5936accf56577e542062db5f9efcd0adf619ed947ea2ea7a1f2f8adf45629676ee7df26c444229c48f8f1d","0x8c15b8af08b275ca0d117920644e1d4266afc89ecdf5b207f143f0d67b8f6d012b278f2fa54bb7702260943777826586","0x86a2f1a572c77d791973415f381e0fa4e8d4b776b0ba66a758eecaa3526505da5435819e6502aad2aadce29f941e3391","0x896cc7ff37f9ec72fd5d9ff623293c4507a367944aad6415ad8cae429ec66e57031d6f4db111aeade1289d4a9aff1ed3","0xb881d9e1491cba7fb2a52f655bd79e910bf9ef6d686c19d0ec83341d6f575b0f392dd03aea27cc0bc33d3a4d11aad568","0x864d0442829dd83cf73000305a42cf5ed425a9a42d4bba539f1046c1ffd8c42e6e5f8b068b278de0f1b053f8763bc35c","0xa0c7a72e6f0e1e809eade96aa1dc9892ce1f89539444d73bfeb71d5b9978adf0f394f408be76d144ee5816b507bb8c62","0x8f8d69b2c795156a74b852b7067e9551ece87c4a512148bbab67a2752ae08bdcbce2e764b67b3bb880fd368f61401fb5","0x872e4aa1ae19ba488f108ee958bf0205fff5581d9fdd1271f18bebc959e646771dccd8ba3a8c8333dcd17dcf7f3cd624","0xa32be0c4873afeecad1227bd6d7e73e72deccc61653ef787e69f43ea9f3831ae57f161451aecf663fa1a35f894d38458","0x93f7d1caa5972749b6c45537778d29d0c4e0a9cb67ad308b65ea3a611265fda1212080a2c938bfe57f8ba710ca9b3dc0","0xb917896ff99e89e1931f0253e415683adb9974b7ba8389a52b9ca5e16ecb30d4b548d43043268110442c367fa9c2fe80","0x8efa1ca32aedefe5ca7956ad30dca5f8def5e3f8e666e23030056eb5bfe94914d7a987f1a124eb9b61a4c6924987334a","0x886dbf2becc87c72b7c4aec784f5989b9fc3539bdfe89117b9edfb2189d308580daec09e2660f153ce5b4321aa2d9396","0x954751ccd98dcbe1637a8d791deafa710ef07a0b3e827a7eada4e3d2989183e3383c74b3edd852fc47264849f8ffc21e","0xa6ce16d93959123a53f0440be61f96f28fda306bfdb8dc4343b7dbde7215defb9d24a49810d95d8fcdca8476673bced8","0xa6493881f39166dcae4b7c8d2022fdfc9db8bdcc3a28ae399e70d9f74ada903356ca4d07ff9a99fab288ece03346769f","0xa3e6901bbac915d5a98c1e74fca4b0a4d8995ef39f2c13fcee3cab03e2d9310d72cfdf6619128860d9c36d6600637354","0x980cab0a4aa2a9cc35efe1c88fa1044e5f2c33599f454a0a24214fb815a1748dd3a349f5361f9c34691f7c1064a9e6ad","0x863ef9bf55bb8880dd0d299b09e4d2188fc2469cb346ee7c62073a862fc6a795484db8c0e2f9c3b78fff548ecaca2c3c","0xb5fc8ec8a57a2edd75c5cec79da8b722452f1f01b0cf7020d33c295a8943f2d05841c8635ef80ea3df7d7f9c16e69f14","0xa59a9665dfded6e330fc0e8f15652ebc477cd3e7e0b8098a072125c980891ce897e1d07333e501c254a59327bd6480ac","0xa3ee79339ef4e35384bf396e68aa5945d6996be6ec0d408ab3cfe863f0ef8af52232365dbe3308ecdbd865549055c28a","0x8620dc6b2e87c9ce2cde004bffacdd33656b33e394096a0c941045249584fb66a0bca3692ca015ff3e5e16e71094d447","0xa699a9ae245f4718563f6f240d04cb0768ac6ca415f60a1cf93cbb4249b5ea60e653939d8a8dbbe4ad13eaa9f49e02da","0x939f65151b9f3f2e048e7da4152b6c94107bb6a11dbd205d3ca1f9eec901b080cc0bb9792d671e007e49f23a7a0c2f7e","0xae2fd481203f180decd87cd7acd4dac7b4ea918186cbac90fea7121d908aef57fed0b11ba44efabfb44a8925c6dafe61","0xaa06f941d781cfa574fe5adcd0b5c190fb2d6ad806e8ef2d5ae556edfc2ea0baf21c7fdeda6aeabf1f5e1f54ce77766f","0x8527a65839a60d810488379f977a38626a695d8ed69bc3fe307db6b5ea26bd8222e71ae134ae074625a1efef736613e2","0xaef3751b49b5e2819180c2f0044464a8e005c6874bd1a9fbc8d5e082eb36d8ca247f875d02432af0b3649e61ad967fd9","0xadea6ece67fba03fef67b8777b84d4f2ed200792523d13b402d6e7113ce5a396ba3837e22be4a96759eb7d5c16ca256c","0xa1e8d60c636886825f760212738ef80e7a6f31df35605fb7e80c9d447fb4d16ea6fa12be4fa479fc97bb9deb18b0da1a","0x86abcb6ea663ce7165ff7cabbcd84dc2ea47701a01308a7c5559535edaf4fbfe3d24ddff265aaa1394b38bdc8e853946","0xa6d8db76614b4c511c72531fb61412eb2841a2a1ab67e2440f212d38a2526cfee21c7365cd67d6860c2422ddf99ae777","0x8c519d67f35b33fdb8bf8de777362c91228309503f4e5ccaad6db142be56dbc0631f67aa84c2f01506de8c190d4438e3","0x8e6e7e9854e5b38217041746aecc333e2f720b367a6250d32aa6133a296d602a74f89fec202e6cf88278cb78519b2abe","0x962f5e1fc1c714d475362faa9305fae55c3f83256a51561a25172a421658ec0d0489d49fd579091ab1d4e703304fae12","0x90306bb466f4e541afe630f174c168a44d38ec6bb768e2e43a423d16baef79084b02c9924fd45de52c21a7e42114c087","0x8a1c5cb3a0dad463190c7315ce47a40efbe6c6c7e0cf29676c773e95c668269607544e72704e182a5f3af738d0ae3745","0xb7892368747f8dfca6c845430e307b8345eba977d6f5a64f26c880ca8c13f0999e7d2ac141e79e8e2aa798bb2a7ae048","0x836e49254c9a6742b18cf86d7da67d741cc9329b3666ada9a28b89f950f4d44f4accb3793c88c5ac9e18299834ea6168","0x87137a9fab1566e3d1e02dcb83b202844ae7c57dec7ecc04947f0c7037f3a8570fa0ea687c16c44a5a3b5618df4b7a62","0x870bd24347476135cfffcf52d4a1464dabd4e8eec4fd55e72f47315b194aecf2602628a35262ecf616de11f9fc5349a3","0xa3f7e5d19027541be0168093ede1fd18b730f92b8bd484136c3649ea7d0d83965b2b7c36c138db6f3953034d992df5ce","0x865904ca3e4389fd74e56f59ea984869b7bfbc188b6037ca62435a9b2f1748573132455df16d71d542cfac1fd14d40ff","0x8d0ecbffc9589278bb61d5a281765ff30dd1d5576ae7fced6c2b4b844f81e0219ac466d8da3f84651e93a717f8d7eebb","0x97c297c7c52359fdeb0283346fbf8b14d9bce20cc1424bb72c76ed8989995ec2a07cefdd91c91e51a25156c5341d8170","0xb14db764d9f17f458bf1dc3f0b182d2b4eddbb831ff197f150b10418e8742e7d9fc313b8cacfba45838fd45a179cebed"],"aggregate_pubkey":"0xab964f788f3b0fa9d9345804f3b8d8fe01cac12b0b0a0168325b6e151c1475b929aa1c0957e1a801bb4725ed17a41dc8"}`), - err: "incorrect length for public keys", - }, - { - name: "PubKeysLong", - input: []byte(`{"pubkeys":["0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b","0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b","0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e","0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e","0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34","0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373","0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac","0xa6d310dbbfab9a22450f59993f87a4ce5db6223f3b5f1f30d2c4ec718922d400e0b3c7741de8e59960f72411a0ee10a7","0x9893413c00283a3f9ed9fd9845dda1cea38228d22567f9541dccc357e54a2d6a6e204103c92564cbc05f4905ac7c493a","0x876dd4705157eb66dc71bc2e07fb151ea53e1a62a0bb980a7ce72d15f58944a8a3752d754f52f4a60dbfc7b18169f268","0xaec922bd7a9b7b1dc21993133b586b0c3041c1e2e04b513e862227b9d7aecaf9444222f7e78282a449622ffc6278915d","0x9314c6de0386635e2799af798884c2ea09c63b9f079e572acc00b06a7faccce501ea4dfc0b1a23b8603680a5e3481327","0x903e2989e7442ee0a8958d020507a8bd985d3974f5e8273093be00db3935f0500e141b252bd09e3728892c7a8443863c","0x84398f539a64cbe01cfcd8c485ea51cd6657b94df93ee9b5dc61e1f18f69da6ca9d4dba63c956a81c68d5d4d4277a60f","0x872c61b4a7f8510ec809e5b023f5fdda2105d024c470ddbbeca4bc74e8280af0d178d749853e8f6a841083ac1b4db98f","0x8f467e5723deac7659e1ca273e28410cbaa6d495ab66ae77014f4cd21c64b6b5ab9987c9b5537fe0279bd063fe609be7","0x8dde8306920812b32def3b663f7c540b49180345d3bcb8d3770790b7dc80030ebc06497feebd1bcf017d918f00bfa88f","0xab8d3a9bcc160e518fac0756d3e192c74789588ed4a2b1debf0c78f78479ca8edb05b12ce21103076df6af4eb8756ff9","0x8d5d3672a233db513df7ad1e8beafeae99a9f0199ed4d949bbedbb6f394030c0416bd99b910e14f73c65b6a11fe6b62e","0xa1c76af1545d7901214bb6be06be5d9e458f8e989c19373a920f0018327c83982f6a2ac138260b8def732cb366411ddc","0x8dd74e1bb5228fc1fca274fda02b971c1003a4f409bbdfbcfec6426bf2f52addcbbebccdbf45eee6ae11eb5b5ee7244d","0x954eb88ed1207f891dc3c28fa6cfdf8f53bf0ed3d838f3476c0900a61314d22d4f0a300da3cd010444dd5183e35a593c","0xaf344fce60dbd5fb850070e6e76a065e1a32485245ef4f413135a86ae703da88407c5d01c71f6bb06a151ff96cca7191","0xae241af60691fda1cf8ca44d49573c55818c53b6141800cca2d488b9a3fba71c0f869179fff50c084657831fbeb42bf4","0x96746aaba64dc87835ba709332f4d5d7837ada092b439c49d251aecf92aab5dc132e917bf6f59799bc093f976a7bc021","0xb9d1d914df3d4565465c3fd52b5b96e637f9980570cabf5b5d4aadf5a329ac36ad672819d997e735f5052e28b1f0c104","0x963528adb5322c2e2c54dc296ffddd2861bb103cbf64646781dfa8a3c2d8a8eda7079d2b3e95600028c44365afbf8879","0xb245d63d3f9d8ea1807a629fcb1b328cb4d542f35a3d5bc478be0df389dddd712fc4c816ba3fede9a96320ae6b24a7d8","0xa98ed496c2f464226500a6ce04602ff9ef133ed6316f372f6c744aee165149f7e578b12780e0eacec307ae6907351d99","0xae00fc3de831b09661a0ac02873c45c84cb2b58cffb6430a3f607e4c3fa1e0932397f11307cd169cdc6f79c463527260","0xa4855c83d868f772a579133d9f23818008417b743e8447e235d8eb78b1d8f8a9f63f98c551beb7de254400f89592314d","0xa9cf360aa15fb1d1d30ee2b578dc5884823c19661886ae8b892775ccb3bd96b7d7345569a2aa0b14e4d015c54a6a0c54","0xaef9162ee6f29ee82fbfe387756d84f9ac472eb8709217aaf28f5ef0ea273f6210e531496470b30d2b7747216e3672d5","0xb7e6e187ed813d950a9a17d1e70c03e4de2903596c4c5ff326848515c985deee38198efebc265300cd4f1d6bd7b5d264","0x81054bd51ce57a8415f0c8e0f2fbf94f5a8464552baa33263c20a4da062e5ed994a4d32c171106d2008cd063f48f6fe2","0xaecc56f2b1c4011d450214d3e1254479d583a6a5c2c06fbc049512731f76227d140df9f36a3f76b4ccb4df1342403573","0x9243ef5ed3bd28892d1ef4f7aaf29faeb9c0e725673cd38e308bd756f20a9ee09de5cd9822e5e77bd03b734ef8a92695","0x925b1fb57c06b5668567bd5aa196531032d6f8918dd4f702017c11b59288e3bdb98e3820ac22780f73580a4119de4bbc","0x9648b83a4f09b4ca2021f0c193c5c41df1465715761bca52671ca790a3e92d67686b97b3d54c6110409779df887bd9c6","0xa34febc12af07316580b480364f90a76313ccce7927bbe263e27ea270853b02ad4d1428caf55363f3ebebac622cb9fd6","0xb8cd1cef89aa1567a6058957442a698cf1b267130606f749451152959a5dfb50d243890d4adc2c3309f7696d54af1260","0x92a93728c252a45ef587ca53a037593912599d82e2b8aa1b734b99d500a0ac8c142092ea8b3c2c34a28dc8ddf337a249","0xb7ee0ef26144de04d9cc80864b869b7ecafbf1b7c0050403cc3c3b514368713b8bb708c464568a18c837e1fd21d09063","0xafc0fa2ed6a270de6122a19d4600380b7f9b5e974d16f095f1702f55792ecab0128b155a69f17ad64a6de0a7063642ec","0xa5869ba554d1432b09ee677c117511291b9901f169e870831f457caa6ccfab376cb1fe33813bdb495cf4afec9ea35fdf","0x92f43d79d9f488010b310a54f3fc2e7f4be191ca06d93e588c30c8abf59a52190e060b285ac626eb13cd95bbcc3a0a2a","0x9698d9519a02b64f230e5a2520401799c2ca7d69ab23a6d9817943147264bf00d409264b928718245efff4f7ee97dd5c","0xa852816b8e463178eea5acebb4b86d0acb6d8c6812cf313296bd271ea4d2fd89d281e5fc296df4df49019169bdf96922","0x8a298ee1ac0466ecaa04d5798048c6e192409af63217f32fd7e07794cfcdcd8deca055b9782dd1ad45a578a9ec10606c","0xae4d49364e4a36760cc74a675500055b9aed99bc19d31abb953ea156bb5a76dcf36769d15341b850114a30ffc8057780","0xb397692ccbf442bfe078174c85dbad7fd605e4ff1caf2904b31e4a4c79d6444813ad9b2093ac8fbd4dd59ec7a4c8c006","0x87c9f7605d07550b46c79add5ea4e39de5014c03833669257bd6666b7ec838f53800104779940d8cdd884275a0f6a3ef","0xb08f7feb86786c37661afb9951a959c9b465fd11ca98fcbc908fcf49144084051f6c363e2eb4459da2c2d03d84175692","0xa48cc260df1df875176cb17493a5b53d669c091da74d5075acb8952a641b1b7ef68d01f009c1a365d2fa80937c79dd6b","0xac9f4df3f20a16a9fefad08817fcbc9a6ee17f7512db006414b4aa6f234c2313585ef72c5776df55fa6284af4bc3f631","0x94f0c8535601596eb2165adb28ebe495891a3e4ea77ef501e7790cccb281827d377a5a8d4c200e3595d3f38f8633b480","0xb5bb0162a4f27d1bab4c7dc3d20f5a75d6ee98c56bcd309a1f0f307685ad47ffb8a35bfdf8431b9b954b59662a74c478","0x8826e820179fd321819e78ffee16f50ac528db2da71ad8c269f60b878bc4887c79c0545b3d750e86e490d5ba9083cb70","0x92977e71396633d442f61e16a0cfcf8ffad0af93c9f1b7fdf4f7ccb816de052925fc192922d6252d325ef9fa2e0595d2","0x91ae4686b0d20470409f020eaca826c3efc6c1926ed25d05e6f0f7916391ec89c2341917277c437ac8fffffe94b68111","0x8a0d241955104bedacb3b829162f2b457915c2beb9018ede8ef8ea80f401b471c42354358da9e62b51c38d54263a78a9","0x80a2be2c7dbce8ddc2eba03522697587c375a5a9e92d4b31ed9e3c34bee047095d93e3c70b1662b3faa301f5b19978e5","0x86a73886aa0114bbdbba346cb7c07376c81b549a4802c24d98ebbc54a6a1b5d2ac874ef657cfb27c3644fcb85f97a2b5","0xa98c264dfc3bc3ed635df5dbfd54909e77600cd68480ec201d9f5c416580591daaa9735b04743e10e7fc6370a8189775","0x8bb7aa61aa8bbd2b7825d28c340da89b625381232dcf2742276b4e3a2e4a0f42ef68794fdf005d94014636732fba2f40","0x8bb9e1693eab1496d7583bf22fb1f2a475934c63b4d94118940617aa187bc277f738223e0ec1ce8a5566035d9bcc5470","0xafe6eface52fb6de91055a81abf9aa6e42ce2ef36fd8ae0d09aec6e5d8bd40a065dfccda6104af94df3f7a5854559ef4","0xaa241b2afbb33f92a5d281aec9c8bac8997c1dddc051455fc0f334de48320f160b5029b552495aed21ed9ce252aab499","0x974b2aed17665e51c1c091998ca9649875330947de3d2733a5bd2eda69b0c593cdac2e416993a87f9a17aec1ccdc2368","0xa3177a98f653cea646f525f0f13348efb27e0d3d0cd824704c91d8d959096d259c9e577298f444acc629920c9619be50","0xa8a18565733e70663c77bc0c80e08f50de908cc048152f1e7dae85d8cc218afbdd337d7d33a44e25400be2f06907c64a","0x902ff56a7a4c5b6cc57708ea7b0b72cb54e4b821c95373f503648185f15208f6ca6281677fa0ecc14f911d7b7ca04f4e","0x98f011f9a4dff94eb0352ff6e21b7df45e2a112bd5d789b5729111b89b368e7ed554e4d1c16b72f4d105090173cafed2","0xabef42538a17a55804b634aac9d211b92b5768c4cc1263342ca287323bb3d5c768080451d1b5d652e9f8646fbb35f57c","0xa8e3c2d3ac4e0e3c83380577ff7b7b5b2a98571e0d04ddebc0a6c472ce3bc5cc6a6733be728a0ee17da74b7691d2679d","0x98f620aadc4e58392b5b583fed96c452b54c39ba3a9fe8c277f625fae7e1317d034f732995fd88c1461463edd0f2b86d","0xa7f5d408af436d71ec7acfe9a4592679649d326c00ac92c6f3332423be30c3601d232f265078f1f2a5d6d6cde08de7d7","0xa8be337b3d0e6be415dcb037b246831f9966aacef62b69d6b609e4ff8208bc536c6473bc9fe9e3bec9a8665c8caa05c5","0x93bb1c86717fa7303f65cb8c45c9fcc8fecb88428b7cd1dd59967a132109c25ab5c97888e46c5d471ff911c573f45a34","0x815042c33c1a43c1ee58a58ee074bc93a13c23a035dedee6879730220379d0c03ff4a3829240b6c34e56feb55cd322df","0x8be11e9ead2e1bb5be7e2ec066ff83589558a5d9373666b3fc518a6a6639b3baecb87f8f34895f63e8d09d270d93ce04","0x8bf2630491d2a480ec243b00d65d76e69615e67d3df5d8c14ca7506edd8e896a9083e8ee9e4129af0f6d896a3225c08c","0x914b56f41c411fbfca9dc9763f44daf253c103b162457d07954fd0af768b5e74692b4639c22455fb81d71f7ed6144514","0x8794388915e86e4988363cdd4289ad19182209c873cbbbf5a80ff5c99f93acb839807787a77ad2b603f074405d7ed08b","0xa3862121db5914d7272b0b705e6e3c5336b79e316735661873566245207329c30f9a33d4fb5f5857fc6fd0a368186972","0x96ef954b331a534199f4f113d993a50ec7a781fc5aa2a181ea0bdbfd4c5c557abfebfcc02604d5aef52ba64afbe0ff18","0x96c8d3dd08724624017f178393d176b425dab9dfa1cc3f62c7669337446baa601e0aa261c00c76bde07ba9a1a3582c0a","0x92bd81b8e9099b9ca87a2033fdd84475752dc34a0fae0a8e50aabf4d3baff9cd45ed56508c837023944350f53dbc4ac7","0x83802cd575a3cea7e3e38fc1a73d94a9e4fdb999b8494e7929309c009d79a23edb1ba091ac02588f130e0585fb106540","0xb451eb0ff4990917aba6e3d80c34aee91ea1ce49053f38ae174cef107cb9acc595d0ca3fefcb804c9dd04510c630cabe","0xa7f711233af57440e9ea700113fc4dbaef97e7da7741dd2e38ae668a7f2685d4585d54a9e6712ff1b87c69dbb181abf7","0xaca5e4979f281b5ab0ea0f549d6dcc34989607c335e94efedeffc7e73b393f42c7b11d76144a750f82600b21d10b6777","0x984620db3658a19769475080998db9e7f5bcd4255a89a70b5ecf7db01226f213836d091a3b37eb96e4937966b094a291","0x8f1ef3639aea57fef705847e251b785bb608a848f42d9107c494cbc696be35642f6552fb83174ca2e73632568a5667f4","0x8967da3c8071ba2bf632cd40ae08fbbf0a203c47c02af1948fc232a7a743c0c0cfbe51606b89f102f2f6de7f039fb155","0x8d58f7e2e58471b46d20a66a61f4cde3c78ab6c0505517c615e08d8ef5adf59b65fa2b01ea2395c84584a6f10d6cee2f","0x8db9f236d3483af79703244c7034b5267a0546c3c840d4e91fdcdd466373d62d960553982225ca5f7666dd7375a29c19","0xb7721412ae5a793f34ac8866698b221c67ef8272eba44d3030512ec3f7ed8ffcb620b58f17809690d5276423e849827f","0x99f6e5b80dc52407f0436d3474bd5da5ff23a19cb188b933af6312d9793cbfd54f9e72596c5d481a1ed8d705b81c1f0e","0x8931cd39ec3133b6ec91f26eec4de555cd7966086b1993dfe69c2b16e80adc62ce82d353b3356d8cc249e4e2d4254122","0xad01d0f23cb74fcc4c39a2d0827d22f4722f02076196350dff5dcc6be765009c66e29001001959d77b277c2f0fba0425","0xb300303a03b8eff26a25449169d1946b208d5240f011ca6f5db23cd7f2c004b63f60afe3c9e047b67f9e4c8970c71cf0","0xaca096c7f41cfa6b9317dff26c6c96878c9e5d5eed50afde44d8df206372ad4b4c45568f6671552029f4c3509e295bef","0x87bbd5574c17dbf80463d11f812a77306f67913c510b1b234f5bd80478c7da8e69476cd6711cd1f4c0e228a4e2e99636","0x89a80c9263a21ebb9b7b99e59e53edc9ac766a55da86a52d1098d57572999ebad7cb92800b1f15be8d7c43889ab71c5d","0x802408c2a1901d316637a3ec6d20447bb9ee105c8c088510bfbcf8cda3ffa9376779f36e12e960e7efa5f2aba45e6483","0xaccc213c82702adfd5c32b24a68863f16ab6ab46947d1d7b3829bc62cd5f2a87bcd0d3ef27d442f07ad4363be9fc12f8","0xb0af0bfa83f0922e6cbfd2bc8ec19ff0f692fcb87c4e35f30e1353b342ae2fdaea6056bc2759970fc2a1f561826f564e","0xa626de0451397075bf145e720691c9d5ed92eddf1f4e48155b455aac7a8e920d042f5635c7a74fe3a9175ffbfb7ce12e","0xb0933ec64b73c49071fb92028a8e3d1ad18019e177370d335fa03c61de5d01e1a7e154812f720c44109701e2b07068b0","0x8b47707a1f563d3b1034e20be2a663587f17fece6581fca156cf660575fde4b8de4d45f1fda7ade9167b953d4c93417d","0x8ce551755078927147bae52f683f962ca09cd68e2a14dc7444f98739fe5d27e3596314d78deedc87beb705bcf9532182","0xb363a57c600a0037d54d738037358aa686e27da3ea65be95f95fc04d5736fba6338c5d544c3cf2b11262bd20e7a42dd1","0xa5e05143d5034740cb9ad524bec81678b07223989d4534ad44ffad33ee2fc73e4ee6b297b68aef9de33f98e5487467b5","0xaf14e8626e043caed52d9dfe62046eaa698f8b95d25cedc8c63e472def8b6a59e64febfa00e95568538c1a382ac91d2b","0xb41a0d9f8f19be13395aa09711b492d20eaf4a56d2360cd6daa2fd665532d852cb9224a5a39e5abff389882f961f12a6","0xb242e56475dca34fe92de09daee3951d647c04ed7a483a5c5c5613676f5ca88d54ec64d1aee81fb0f085aa67c88ee6db","0x894798d09babc765b3ba22473d820465e713c1d7f78f3eaeade3d957bd412a742f498a9b91e55cba8e08c36c8ad4788f","0x93c65ba88f12ad22c761003cef7ffb155b9b17134ed871c0703fac60e80dbd2dd8d163bd28eba9dff88b1e9bd1ae4a76","0x8ab4d3a78c54107bd7e71a0a006cb90dec379d6d86c9b6e4b3b010ceb37236cf2566febe76f955dbf0512884215f9f86","0x982d829cab4f09be252a2c57b77c166679b7e9fdf6f5cc882462b8f4dc9a90beb303c85af56304fb79b975d3643e2ed1","0x908ad5c41ba5fc8bea0cd8f028806a823bda814fcf6c2c32b5656c42b5d3061cfb077ecde2a50bf374e055e8d5dad4c7","0xab4de8ffccf7b19aa6d7d4ccc4c82f091ebd5715b5dd6680edf9eb4f0dfc312e8999b89a78a8d4ed4512aec75a5e5906","0xb544d0df633f2334845f73a3921f2a716b9694baa6abcd7cedfa359ba3448029d5b874eef8b3f9f324f1ff4c0f997e97","0xab77bbaf0047e03ef4bb1ddaefb777f263c9dd556502f3078d51790653a59452f1455d23002e175ec5b541cb69007f8a","0xb56c50c51aa1ba14062d9a477ae78646c459bfe12fc1fa3362f0652077a0ba090a0b780ee0b58085ad2b885fa4a37d4e","0x8bc5c1b16286219f479f6d00b0b31b193811b499a86139c45ff4350d8c9b492421e854cf75fba1a0dd566e6ead8ad667","0xb7eaf282595bd590bde41f67783d12ccf7666aea2f1efbaeaa80c8478a157cf59ca7bf009e5a125163212b0b9f51c876","0xb404c5cda4dad57827e456beecf745b1ed9f2bf776ca0eb806010b80b8912b683c288b4f231bb67c29ddfcdeb16ca909","0x944c4c5147a6b263898f335d2d59177c829d55901e5a4e394c9253cfbba6f0f3ce6ac393aa7b123f7a15db2909aaa37d","0x97dfc5eb14556d1a85e34c069da71fc5e1bb5e17b421d9503f25d76a8f3cd0f2f9c5a1937e785e1c0e73edb6561dd176","0x9145e0920e276f19fe65b9ea81339a41dee6e21ca12512005701a014426322be4fe504f853d6ae48314902fe9ff50a43","0x836c4b67713b082c060003d8fc839e265c1aca7f9bb82ce07f71a459d39073ebfdca87609859c70e55a1b0e7a613b395","0xb5217af9139deb6be95a106c7651e1d8dcd8eaa04f3c6196dd52abad84c862724603686f90c7c2a985f2d75a1c8facdc","0xa38b021855057c62bac15b2de83156dc8649bad858327b10cbab68c8fa3613a3de698322826d2644652ca9ef92664cb3","0x828b5be17d71a278644b6fbe7ab5fd3a065312d1b03734e0b9d74703a566dc99815c81fc50b13725961376edc2f54405","0x956aeb449c6e00e75a7795ea552bb0a2c14e065bfc9fee78c5a337f9d0c1814045802ad4f2e3c60868e54cd381809cca","0xa0ab6917fd4c65ff95b1a5ed5f3c0d7cef103de58a90f2cc5383b4914566aa085f04e8505c862a29a0c914072746f83a","0x93e08f94b3c1e5e9e7454185c5493111db66673fa0f1ba86d7a395858a32fd2c2ccd0c4838affb453112f0e9a8e3a370","0x907c4f53d28167c96d711746d338b7428e7ffa389ec76497920c25445df3b1ce7e88648a5fa9f4e1b5d2d254938bb65a","0x987b620dd2ade22c44ac3a642d17ac9009da6c2d989028957da877e5178668216cb9ad2314a520ebeeb8b032614ca2f7","0xb4bb3db19f9162fb238ddbdbf5b8e819696e90783775249825d64767625f2b6e9c52edd859bf8afac8a87371e9100d24","0xaa083a83471b7938693e54b673d98f90340fe5cd2556b27eeb9c9069b7150e853391d47543dab155f6fdc8ab7f2e185a","0x916d306c24956c1a97678695330d240cb492062889dbfbaa6349cf53259c719ef83748b065e4a30fa6edf8a171af326b","0x89d9aef34711c5ea0787f591e4683f34727391729c0a402702a51de4d6a36a9324e1c77890a1b34c70a06d30bf9cb0c9","0xa3cc6919919abf050a3e64b6c5d826148ee3f766e6b67e7e8000645e51ebed1b9c6a20b9b7413a4eb835529cbe4f77a9","0xaa70cfdc554a8e67bbd3e6f3d2a0ef61c2a7ce1784acef01e9d7f08ee3a4723c2b7bd789c4bb687f19466a58e6e7bb34","0xa1a1b99827c25c1079d4ed035a31478a38c2141db49291d0fcd10b64eb6ee5b0d9e758a9b47f40b2092f1c150bc28e11","0x87af7702ff5e6e9a4416bbb516c3aeec7827408b75e3d1a8d420031157ba7a5a4d1eb565d29f100c5cdaddc05399bce1","0x8db57d195b1216309f3182f522ee9c6a724af5eebfc8faf058edb4e444a74f7ca9fb0f227a7960887abf8ec4697ef4d2","0x8cd26495562e8fa526dd3dd5ccf7706e0b802747a2858ca76e4be7e9188ecaaf095b7ba58cf504057c4039e990f88618","0x95d668e777610672265275332a570af04c1a6090d9caae5152b66d476a7ac895c120e68724bdf30d3a51ece24a76b225","0xb37c32301c15cf9a62fdf10ac221d751918f78ca95cf7f79b5a3828fe77c88561cdf863454133bc4bf56e6209b53d0d8","0xb923cab7abb3e0b5a8ca7b841662262014e59dd8ab24ef4513ef5fc1c85dc1860bf4fee2565a732a7df4dd73ff638403","0xa25d1dd7f5dc5ed5aaba0187d33ee72921d6455b6052c657d87e108aaeee9c31c53701e7b288ae0f9ca74cae34a1f49c","0x824904d20a5620ca46c015ff630e1e26fead9df53243354ace937f01a971916e8883687a8e5f087598c633a91d0d6fbd","0xaed2a3ef693d13698e77966b8125442ac40ee0a62e8d97f71493c966da3c8604932dcee09606c2394afed25f8ad4f31c","0x8f8ac057107bc490de273453730753b9e2b69df03917a0addbfb13c5152d93fa05702cf21d8b58ed7c08ac3295c1de3e","0x8fe63d0f0da14a975a69446571eaa08409b6b4d091c720ca26519156a1cbd9e0fd44de574d8486ff98ad4086e0d96f59","0xb249899bfe2b0b123c7a151b5041d5e994c57568a6b427e38b25f2ef04ef0c30b4577e66fa7b499ef14d8d24563ef06e","0x965ce54aa0e435602fe222441ea4ac7b227948ea37e927f9816d89d779dbeba426dc68ba6829ab8da33a565a6b879c65","0xaea84e54336d09257061a8b23f419438c2e3d2659de36b993033bb30e396d9c9ee8b6f1b66261a6a060c3ab706827afb","0xa90dfa8114a00b3fde7cdddfb2fab9a6d113500aee32f08786634bc5c99ccd7730417e4ae4a05299b62342c1ab98ada3","0x9346419f620830d6535546fe2ddd827b69156ea9c29194780c63a8f07b6fdcb0568282914ce3cc06a2ba44e2ee1a6e9e","0xa399755dad117a369409206196a9e3a1637a625dc22d0da18583827dbc487ab9a2ba6c995927df9d8560e07860ae8b0f","0xa4695dc25f6cd20e48edd948321a09ebe2884b1d6ebf622aa02a023e96f9a1d365be7f2c6668444b347aee678fc7bc5d","0xa8c0966a8c0869e28110ea5587321cb26af1bc49591fdaab24b37c77feed399439515d2aca8f2483a3d666be8b4eeef5","0xb210d799f2cc4d87df36b60fe1d7408d9e4b5124aeed740eb42227dc1f456d9e13bcecf309e068f9775996c71b55ca8d","0x83af2f04a869d856df934893edd7f15dae94ef74d78139e0556e1166e81f8ab2c294708af67f194e854946f2da4e87da","0xad69af5d2ee0d68b32e6c4ebafc348a0c509aeed7e4f5c24c236dad4a8f91129cb9f8ee521de07c8199807e36e6a84f9","0x93568c9c40bb362329367dfc26a65567481a03c35fcaab51f781c9f364b7e676cfc3d2c08633888b29715a6731dfb6b0","0x8509086b192c039cc84d145fd6a2b2cc3e3a3d46092e928cc1ca9a66dd663550a2782ab32d677785e02c23b6637df70d","0x89494e98d8cc4c763b3b138e21d6cc1c86f7eeb69315cf6a4b8b5b7018dd59e3b82c0b7c785a381ffd1b809e5bbf4625","0x8451860d32c95e30f685cf31fccb967b0cd172566ff7b7d2c5ff35130bd1232cb1a216c9f0cd355ad69a93469b78e8ba","0xb48c495c19082d892f38227bced89f7199f4e9b642bf94c7f2f1ccf29c0e6a6f54d653002513aa7cd3b56c88368797ec","0x8bd22839c85ec58af4303cde58674394247fbe1f51b4e30ebcdf86aa861ebef2ac9239aa21bd9b07fd03f28dc4806780","0xaace874118a4ea9cfec8d7979dbb4618f4833dde4cfc493a403ee5cedb67f294bcac4aaa2d626ff25f4fc7ee9fa61401","0x956851460cb809871966cc4dd44d0b58dc68a1c22110864f374cd3aca743ee63b0743999d35b473e3f95ea38a276eaea","0xb8cd27d87c94a69cecd953999908640b437f6215ddae069a1ad403f995dfde6e4ac46e5c85fdd8bd4fa655f74cc2bc80","0xae37d415dda04db4f1abcf52c080c1c7a1921a819181161c4c2c18f809cdcf695de3f0f793c78802bacc1f4a32bd921a","0xa7c674e6660a1930c546b4a7e345265a51527fbd53327f90cf7edce01ec2a9c9470c9d9f0a2e4dcfe4c0c5df4382aafa","0xb2c9669a6f3e64a5f8b37c210c88adb507ce396042921b1aefd5bf52a3089f0ab0b5695cddf9b1a1157fe5dd43558e54","0xb00c6d2cf271b167f17135bf7bd14b7df669194045eb6f09b9dec787c7b608dcd42613dab0f857fbfa3fb84792a3e63e","0xa5e5e5af2ef8b65bf9b7575606f81e99d1fa645078544b0fcd4e0b506670e6a75504e6ba4001e6cec25632633d050276","0xb7ad21b3cc61c96c4ea90e81cb5a39836f114dc477bb63da54af20f60d42dffb99aac4ae12ecb70288b1d226ca7c2522","0xb3eea1ef03b3cd28709513f691d9b7aefcb9908efc7114e20e302598cc8dfcea02fd9423045f246112e4db1bdcfa9e14","0xb0f147fdb3e17379f4933c18e6dd3e3c9e9414ed5920ab029dc5907c01f671f664e4bfde8a4bcfa273a57daeb824f695","0xae04fca0e06b256e03d4173d7f772e2106efe6f72d469243dba695179b5d2be8b61052c2844247ce49ec3b6cfd18c73d","0x98c4e0f20616fa174bb221011e731650cb841ec29305f074fdafbed1d04b761c107a854722d4a6d69d6a15f7bf85c7d0","0x8800aa633b5ab60ea1da84e04e4a2fe6fb19c1d90197791ae6212e5349d306ff58afe02d4dfad739b07171ab5757d26b","0x9474c26852bc2adfc52d093351dbf7ea822a2639d99db5b0d344e440e0ebbd1e856ae37daf3d91a05cf62f33342bd790","0x86c82451f5ea5981c9031b3871e1463b10875934eda1c2520752d03bd51e71d943037b1a902979b6821eee7bd5779f78","0x864a08f5f022ce7757cb73be7ebf54e387fb3d5d4b0371d01ed493270be3236c5bc3b1272e42d2628f8f3c000d60eeaf","0xa38e925dd3c45de24e8d73e9170168dc8206035ea711741d91a35c24fa71bb7981b89bdca545ee68e8680307a754e801","0xa626ce67a47dea646ca21759fb026c6a258cc6ea8db330ee68cbd2455d1c347bbab51f3c08423eedecfa9e36920ef80e","0xaae22c365554eb37e2f402f6e6e4bfb0aa9416d8dda0a2f8ea5647ba7dd32023089f4dcc111121e56b52b1fdc29067b3","0xa5c3572c3b770214c14beb4d403d00ffa981480eb850195c99f3b6a2418cef98df28b7f1543d48a2500bfbe25e18ad80","0x8e793a86453b578e9b2f4c252e9ff18a8fb1af36fdd09d9144aea8e2b172738fde30faff3e9391d00827df5efb534821","0x969ca05ea6e49aa9b35d41c3354096f022e9a86718ac454cc8140419dd2ef5c19af37d42733a434a0e77970117ab884f","0x8b4ff71ee947785f545c017bbb9ce84c3f6a90097368cf79663b2e11acc53e18e8f7159919784f4d28282cb39a7113f7","0x984a6c8f4b7545aabbe9e0341c5ff990a05508c94e3757da474daf1d70124c8213ba2457718ec2d1fc562fc0bb36213d","0xa14cc20155f6fce0f248f9c306a32cbff425272829f7d920073c599b48168fb018c82b2aaf7cbb8b5f6449340023c37b","0x89737986b89c213367ab0fb9a4eb998d9b0b713143cc8b0f209c9355607daa4f6e6c925dac3026890e291a9480463395","0xacd8a33698c0b95294943f0642c8b8919bdfbf1e92c61f26107f0f9ad989497742b58363e3d885e4d41a3bcfcc9c073c","0x964e84e1272dcea0fd79d698c1db18e847a5abe1406ef7988e61f39e3f1ef46371be5c25b6c2bf7e53788730f702b735","0xb406b1521362c206669d15b4e5448aae2f1854c707592abc612973b4726d47edf3bcd9ecea1a4b6cffc6a9f7b039921f","0x8ca1bfff2cea25ae77249cb18146a39b9630be5947b65d15044a5e5816b6d29dac9da83504083bb8e87dbe97dfb6451f","0x8c2e07abba50e0e1c624bae0dfff418f8f00502e377840f72e067cd33917a209c525fea7dcc7c44f0195a3b9a5dabbb5","0xa4c11513391dd190b1ac0cf8a1c2c1b9c39d925b38aecb950d357283beee49ab97b1d7dfb34396bcaf1c25658fdf7713","0x92afb506a8345b325a4fc1cf1135455eac709fe1c623bd8f0972cd9e51a763cc1e80bab1f7e01976d1c4f13af3c57caa","0x978b5194d96515146754465533db2d854e58371f26e78fe0eebc5c5b65917a3611947cab3bf7fc645e3cb870e4826019","0xa3f841f04d3410b06a4b4eb31b3fd92eadcf486af60986723d34ef7b8a9908541ab6e7e0ecf421f593f86afdf8cbe894","0x81fba887a59873ac21711818cc8a63b2d4be1a69627f8c70586a56328a96aff64b880f1a07c125eda24784dfea0bacd4","0xa9da8f5d1d62844df8f6fae763aa653127d6eaad1b4d8ba0b3b3417e9c486be3cc879ebad7fb182dcb364d3a292ab07f","0xadeb5ccef7679c5d26e97ac5d2c8222058bf8b7c5eaebd31db3f3ecbb8d00987e2b921711dc6953eff6852601c57b198","0xa4e2f5a419590f3d30cbcf9cac0b4a89b636458dd6d38aa763694d4edd787056536089077d8e71cc4b182f8e87dc7916","0xa365251e868fae8780f009c14c7ddc349389230b75c79e11628b798dad880d9704a10f3358bea40f4136fe37fdec13ca","0x91ad339cd616316e79470c8695cd83b3811eb762f292c9a67c802b84e8e074ef5d208704dc1d5fb4a8343e0e44b25807","0xa2d7d0d6f85894bda115022811b35ed5689143187a911fee5bcd0d6b1c78f4db3542223f496024fb2279b8ee76b5ea79","0x80029a26a45145f67892bfb25783d04f700e8917afc2b406695d4443fc3a45ab9c2c0572c357a33a9ed3877ebc479822","0xb6c8c112c7802a29579e14b228ae6a33fd7f0a3d33d06708b0f07cf7ec18f48e5ed7d5c47e7942c2aea2d1f4dd95557b","0xad4beca6ee84273739c03792e0a2096337c92fb096f7a902e0b09b8bf38d3f67c27a00b05d3ca69a0c9a43b491e8af4b","0xa9ec8e4f705f27e6991a43ce006155825776666664d03be89929c4e5c9a01c7b759c1751e16b7a5d12084c419e97878d","0x801a35e02410c44a3d81b564980738fc5a1d4d15b887c9477c8835c9038233fceddfac4c572226599b25fe3faefa85b1","0xa38b922e79533b5fbec5f710ad90837cfce8073c982c57597027e5b6facaabc1edac06c7014fb1bcf8e11aaca4049dbb","0xaf4cb80f788305b5c22f5a16bd3f5d2f2f50a403e4171b78e267a4e2d15b14beb04735b9ec206751a8163dae9ef3e96f","0x8e0d2214a6f4364590a4acbe3db7b3757b6f2f1eee526babc383e68fee4a7c9735a672f83aff5e9384d66b2fe264c9b1","0xb110c3a2e0100ca6338d66f81c4fa6eb5cdf0aaaf839ea8e0a67645d958fba5f13bba8b66f7f9d069d571f25cdb8e47f","0x879db2b2da4652de6f12a5a9e5f8665daaffa2e4c25fc8609af45b428dd2a35244b66ac2a910dd76c0961e56c660cf59","0xa4cc78a560437549a4924c1d355e81a3467aaf9d7e7e1b4c7df6b39528345bb950c51c5316abe27f8618e5c7ca7dc5b7","0xb0959a30fabda6f21ccfff1b9a4854fbd869e767b253c2f9bc08c4cbbaa3c24f37a7124dd8e67e2b0bdf4b052c2c9873","0xa050c5180ee6cd9daef723caa6367112bc4b06636c3da59c3377e5e7b536942417a29cd5d1dad73011db4492032caff6","0x96dddc7430e5f035c0c4d005ef950eea0b3cb8188fa1db85b947bfa69745d4cc0f8ca522b3880823154796fcfedd970b","0xb1eef7970c10f8bb2a2d70f566657cc0209b198011ee3a4aaec9e7ddaf571fecc03db1042997b1554286e52ea95cce27","0x85f65540cda46d23cf0ef948b5793b46a81771b4621ffb4b98c6dfa222208ffe3215bfdd436eed5ab124969704752e18","0x8d016fd1936593cb41b3e94c01ae213a770cfcc1e94e06bf90dd77dfb8721090cd17255aeb4b4da53bc2a70257d2bc5c","0x953e4c8ef12a42ae5376ba23e06cfabf11c5e3fa773a98b487723225f1a2df60be50a54a7d5621bd85be25ddeb73af38","0x90b3bf8ea91bae7c8d0e33974c65e1ce677328030cf63111d9ee5cbf6d300c72fc033c3c70d6afc21858fb9d2964875a","0x9412476b39b4c36ba977e5aa1bda710a773b48c95a6486d0201a978eaf58c51bce7c8b37e34f3bd61322c2f7caf53bc5","0x8202a977e0d543f09f5f4b010fe308031db9c022058591b4ecc22205853f96fab8a906e31659cec3f20c23deced33fb0","0xa6071c891f8c353b0ed693c039c54f8ceaef1862c23904ecfbd88b3ca9180a52d7c4ce95bb9673e98ba6ac93a2d5b462","0xb722d39c1d7d9c5ec39961f903efbf7bfd5faa1a3af41749874b52d9a6ecf554b022beebfd42b5d4bc00ecdc726a1c69","0x98bed18337602301002525627e99e62911e6bc491e2c2bbfa2eef2f4bcf173eb60e493b74e95c3b5256555f20535694e","0xb499f66668919d5f1d82e55171c5961e78aaa70e0fab3a2ccf14aa402379ac66e05d542060e550d8a1d03796ce703a3c","0x92c237d7fb491bcf70aa4e50e71b305bcf71bf5a438b0e08f03fc4f74d5c3c9b8c823049e314d15f8266179b1a90841d","0xa1f2eb8596281b7e85285bcee8a4156140e069c6f50c02a0dd3b0f40ed62b8e15e7b9c40f6755496e13a94d91faaa194","0x8f4d945fafc936414122945190a1983192259705205fa3e92b72443a93183eb140ad527d4b1449507a18cd64764c89b8","0x98a8e7af1994e3d8f383dc4ee6d32a01077694ec93ecfd7ffbc5cd9448938a6c6d35cbbbe8e01a49fa4782f389757b06","0xa7c051843950c482ea373ca3aa30e523911ccfe061c681b16fb8a35ec6e4ff0ada5a25fb2ae70433b18913652cc3c181","0x8f14a40f502a87214891c922345fc2abc6795c28d72f9deb7ebffd7b805888222f7b1d479db1142ed013902987394cad","0x8e486d8c9ca07b6c4dc1181161ab52508b70980e9af31c97286b55be3df3701d73891bf0aecc6eb7d2e028572bb5c25a","0x91402ee72dd351a735017f11da3176ae5fce3e92369972d0eee22a45d1cc2badd77f627c4a0a9d9c480d65464442599d","0xaa5b90007d36de7c57235756d39aac060ee48e8a910f0a0c815e71414a0d53e7b0659242079253fdeb32ad18ab90beb9","0x851faec0a50c3df9918d1ab44fe7f63f8105d671d8fb83f3a59d291e6d4dc86cf47a6e9402973bfbd7db535b3dc4350b","0x933dc2f8d407d4f85a1d54953ac47a89c19808eca0d38b0ec85b376ce17c3ef1edebb518a4dce8e976155cb6561a849f","0x8f7069f51912347df8b721903bd9340ff49e9d436239ea0f4f176e360c4a91aede7657037ae00dcb08a9d7abe9b48d5a","0xb876db47bf1d1868b3a39cdba4171adde47eae91b3631dcb5c59d28cb100ecda604a446ffcb000448c462d72526ebdf1","0x9666598b3eaade229b7b255866d279009ac0b42dc55cbec207f3842d51501e2fcd318ce7d2fc40a766382703c8a0ef00","0xb2b4c1b1777970826b6683ceed5b72da7bec1f6f7cdfae6a599ae0d0d6d912098678327ee31fe383fc2b95bfed48bfce","0x91cecc34498496a68dc7630a6184b1cd7b977772a94d7d704c64284cdc14aa3f4d7c6eadb3bf62eda1a43f2f8d547a2d","0x89dc8480e9d48c7e5a39c3ced17e65170f56f86a96e4bb131e88c3d6eda3daa65265df5445e0ce52090cf34d7fd1116e","0x8219db7b86441850836ae4e27a030e8378e594e5f1d7ee08dac7bc054653d178e6949476887c83a20a213b2bf39e16f7","0xb9ea48794c02725e69d9f6435382b31b3e975de5ead999a09e13746e0ae5a63115af3a3043cd71ebc94c9b051b5b595e","0xadae379b50e15e5f80810abfc544eb28e26301438cfaf8a8a5569f9bfd76c4e653d0da710bb5d34687d47669f6999257","0xb451fc2c4236ca2393853980019f5da0e5f7d93df90bab1ae34ddb583d0ce3cdece25f23bc1736e065a1f2af1ee2bd34","0xb8c6b853d7f3766c881f4eb0c9986b800188b9f9ab40a492d49e64e8c1e98cefc27ecfe225ff9d5781c0193bca2f77e3","0x923b10adafbd70ac83cfde90a85bd38e5e919348285b311e020721bc96adc9e9b7e45f8052d1b3ef97301947cbc6d3e9","0x8860a33d75543d49ad04bdcffdfdf7fcef7228076d4e8150d80c3cda14651963544a683355e256166d995dd3f6b4ad35","0x805de41e2e03f52993f465c0cba3886c40488c0ebe7fbbbe65f016e5e6ff971efe2968e09b0d62263cde4c70f6cf8540","0xa367b7c50ce66726561d5f4190607e9c1d3feab41f624b9ecfadb6f52e1b300ef98e8913e8fffb2b65cdbb889ff5fb6b","0xaf379c89e4f4bec6b942c9e2d8fa6ccd2ec13cf421d80c987af53d5217c932483c4ed17cd1a9c9d7174e2546ab16ebb4","0xb6c5b136625178a485ee2eba1ddadc84b55e42c0e5a7ebfc8e5e2db651baf3c0a7cff6fb8e94dfccb1ca0a0d48b7496f","0xac210cfd8d8d9547120ba0a786a93318beb172471e9711b764db71376898bc28037160396e32be311a1823e585e8f524","0x8771e8df435244648533c638f725d292deaa9ef3e098ccce30255f860156f9101aea2ab56199d5a8cd2042af7ea57e33","0xa3c94a3ec9d463a4929513b426cc91887c7e09fd038314ada8e5e7a8ce204a7a20247319f91c0746de0e241550aef4bb","0xa647de716dfe7d82e529344bf832f2ac603d7067a515ebb7148fe69cc4330c1c12d3caaf16d6df3a3483574d49a296dd","0x97dae6c47e2b695734163c4e12ff709e7d63879fda8192ca26a35501dce45fd8748b5ed04519e829d61e5e7a3e379dfd","0x897c752e1ed45c3ab22146fe595fd08175a828c69e1e3243e6e1e644792b0bc979924123c0cca7dea405b074e214880e","0x90e6673aa3258396ea9b5e5d4c53b076fc93d4f408008343e44f5d4e49e408942c764d454b435be080ed8e4328ddcf1f","0xa7f7669994d4503c6390a44e7b64103861f78d60283580e19d0898948ed55a0b16b6c8fcd86e14341fd9a5974e4eda5d","0xb8ad8a758c02b9a1769a5f883a41eee5a516165cd2ae19749d60ff634f1175940ea569244830265b2f59b2aeaa434478","0x95037a05a0a6a90acadb5cc2156117378faa1c1eb79cacf3b91835e268d7855960e638dc34bbc192cc6b8ca6b942be04","0xab152bc78eada258d68785ad491422f64ffece7e462ac59ba92ca919f6e2ecb3c3707b34d6159a967b4dd7590c4321e0","0x847230d7b775a10cb13cbe8b80b7d2e5e613043af2913729fde2404485cb4dcff11fbb08487c860125c9d4828686818e","0x811f122742c9f58ceff4b9b75ef59d8a8b5553313c027e18a21f417206d72b66d225c30d9f9f5dbb648d68e537a95cd8","0x875b740b7de5cd6db43823c3dabb3e0652b132a2b0c7593383420f31c452c3e772885f083932eee347c94ff2411367fe","0xacbfea617a3cbc5df59da38133fee49b25a4a27aee878184acbd8cad6c72a2ffd5cf31812e4ded11d7a73c6c7a9a7cb8","0xaae696196c2730c93099a70860ca5efa86f84e5841e05aaeab2619a772f23eec46d4c72a31b0e458c85409b511b498a3","0xae0825786e4f5ada18f212b067a394b52e60b37c98bb22ccdf0416d27b33029678de976370eea92c384ae44bca79386c","0x95ef906a741f50b59bf8fb77c134abc0534fbe7d0c432832d2d1c0ff9bd20090b424df54ffadebb9cc43e5f3812a7968","0xac3a33ffd0eb0ecdb7baf1a5a4d8fdbd7c2e7558aa073269d2f9b7e9e5c7a1402c30efdb34fd7d268ec5f64db92a76c3","0x8b1d9ba63bdc005529f0f6e2f442e6649adcec11e0db1d643b3d3e09307cc8c5b3fb84049941b8692f10799011c246c9","0x8f9ec3c7b0f5793f3056fee53b16af2874bef12a90bd0ecf6282d55ce6ba70a07071df4e3861ad99da8753677a2a74a3","0xb083923ec58581ce049677eb0df25ff6ea0e29938881a9e03ecedf4c7482ccd25dbd2f8a15d6bbdf8eca74a74f444e40","0xa41e4e990ba7effeb504f4f0c27924c90c76ec433f2cc59d65619ce9796b80db1b2a6c3fdcd3a3b5ae798c65433ff911","0x8fb481a72fde68d6b21d0f679bcf64c9986e88acd27874cdfb4d2ae7a84e7dac89ca6afd072bdc503b15342ddc899b94","0x9792ac6f48e8f90fdabf06dd862bfa48612c72685f259f7f69ce201889daf43e220bbe3795554d1973b497360b81311d","0x8db6b709638a90a292ecc760d425bd26855a8b67e34286987f3c6aefa0811573e106f54b088b3afa8436156fb36f783e","0x93ad251e308b778815f925a6de6b11bb7f3d4d8d710cafd66cab8be0b91ef0ada350c2ca2d8f5fbc3ff4f002445680f9","0xa31e15bea68f0f555e2eb0552f74bb78a755ee77e242799cfeb8a380507d994cf24f46fd86568f46c4ecc7ddcf359ba6","0xafb329bae0ec756fd1be3ee1eac93550b77177d96558deeec2a6a131e35ccdee653189d4f5bb744f492371605c44a9bc","0xb62df9c59793d5e3a553e9f5b9da4c928105e221898f11847e7ec9a60c091a1a56e0f141d64bb5bac13d424a49798917","0x810ab821a4d4a0707e0f70eb7dbf78a528e2503749e462fda69969ef1aeee9ad2b8d37c77056bdb0feecdf206313d2e9","0x80f23973b414503e2ba0a53f67463f332b23fe5fd5466f1a770a6d548fdf4421d9370ae890b54be1cbeacb7a9e31d166","0x95ce181db92ea8695c006896d2bb9faada9e157a896cf06b5466c304ccc6b09f7b8b10044b9b0689265ee97a6388dcd7","0x8e322c2995e2472a7981466eb4b890d753b2016798cf640ed4b7ea7a3d53e5644361f404c5eec4baa1a55da860b7981c","0xb6f68789c60d1348b5e24bd6b7ccc18500be7b6ef0099895547a83f63eca37ca4f26fa3517d5bc71bc4a2fb186149179","0xb50d3fc8e36d2f2eb544c16b959b500160c2b176298e4e16ae5d928856406c86605b8ea6bd802ca1a2d1c9210d6bce61","0xa72612ca8f454d74489512d0637191bcac72124f4111f7cd52de8920ee3ea804ee895201ed74527407159220ed00712b","0xabdcd975ccfab19f10d7ec535f7c0e9e269a34f5eeb653d15ee0505f383274e5a20b3b71bdba0f369e36cea0eae1f5b1","0x83dbae1b08eea5bf0a89eb1d0b61e9e0c4e1142610ac8d88d9f3bdef550e3264b54bd47052d481738b92ffbcf6e36f67","0xb628c432d9d76dd6483ed50938fc4c369bd24b6e3c1a41cc4620f7b513148fb242a76c7577f8766a14770ae597c36aa4","0xa36425294d9fe4f803acb3ce90947ea5f20cb1c06c4899b80129d8fd7e491f0128d86f98aa987a1578ec1244ae3d5f17","0xac55318cef8cd8f015f2493d09be7556066e235f618971a3325368f3deba029bae60fba85171762827f1f70c6883a467","0x9966dc1de264da86652de12f70b4d6c7271026be0b081797589ba126108809b6264e2ec18cd59e90dd2c639bcd9986c2","0xb5a83ace1a9e683361435bb484295c11e371316800c073c8beaf1ee1900d5589966ac8266ee11b10b24f671231584302","0x8428f1acb3bf75a11ca3ff7b9fcb2af1f0c43ae22f08d4ceb586c96f97f5d999273739d348900e2424cd375e5ef68f35","0x8e73eafaa8fb6863473e55ef578c4764d9330996a62132a9329ab43f2a45ef2e68637cf48f674c8a0d127d9fb2738229","0xae451c6d18b7a14585dc96423f078be6b46742dde9be4d52907fff934956ebb2332e82c66cc2354eeb2da821e80ab7bb","0x953ecb430dfe4f91510dbb8166f07a557881c19112e41a8b1b8b0aa2c3d95c061cdff951044255a3e4df6f529302beff","0xae629cdd3ee2278a8993feb4e163a9127c4a09857981704fad31e3fbf2e7668136f2943987c7b5619d7e362d1bf9d9ee","0x963564994c2f8935ab03230c47dbd3596ca372a892a616c28ed80a582b9ca4a43e6ef58cd2fb2a3f3c03ac02eb272a82","0x893f6809ed7bfd91951ba78b29c2eed9e8147ed63f01749380a0b6bba9bfd3c7654f05d2aa77fb7a096b981745615055","0x868207372934c6e8133df3c6a1d4a993cca26a06616d8f3de0c593a4cca3005d6e1a73b41620b05a31eb44841fc20932","0xafa8898fca81793be528c433c00c9838be077b05b7fee5c82c2ff1bea10834f3aae64e2d5b8e3cb3e4a8104127f2b99e","0x9685e2fb1018a705d32745ac6bd64d7bc5861679753d5f886a9439c1f8f85cc247b392035fcae82233aa39a6be24515a","0xb41c965012fdbf74f551e0a1372202f5814cedfe541336f5954020ee2ef23043efa6baa200cbd22b34acc5462ca3e9cd","0xa8a7015ac1ac3ec6678478167302dade9eedced09f899a60decc8060f972141a88be910f959aa155cceea322f375ae72","0x83a7860b2ff27518453860637b50ed63adfbda9a2f36432e949268cdbd5a6cc10985acf9bbb57391393823d71328c85a","0xb7458d704a414e012c62a3d19c27da6b0ed9dc77dbc1a328e736043e156eef0af395853ba915bb246a2a4178febc7ad9","0x8a6785d9912cb5be712bf51c08da89f9a3c7942869176d1a24f114f430715064f48c35d37c1c1d1eb9b9322ecfdcedb0","0xb855cac3f2635d485914e4b25b953b066dd5942215b38677d16d3fa6aac5b7f8d0849398ef946674e88514fc83c42491","0xae8aa6029e2318a91b3b6ff77e2792905a690d7ad0ac1f97a7887ca4891642d267b7e208f6bddf407fd8c4e10caab2a5","0x98a5e4ffd62c3b8eb39f6230d242efb74701f42380663af26fcbf106ad1b0f02339aa6d9eb5f2f073b01f2c85062d89c","0xa7723c37795ac53e3ebc25b9dd55af10080490e872a18724b0bd3c7fecf8ab18f7d6abd1b49bc755048a3f9b1bb136ed","0x865f9a725b49135bae6c011f778bb311a514a73911924e4630a5fedac29e1b4d127308ac8b0d623e7f246c668b827f35","0xa663aaabc4aae867b7bc4feb03558f9c906be74fbd1cfa931b88191a1817c8393778ef45b5cb107cbf860e9cce540212","0x970d2002cd899a503a0a007d6b5cc6f8ea9fc7e7db1de06b5297daa7f365d066e69cfd179197229508bdf93161904330","0x81fc32376cd95ab4456f645030a9ccba182da956571ee1136916fe655c8bf08f05244e204bfbc87f696472b3cf3bab83","0xa42f4e4ec8732b5a4fbffea9e17a6c208db024f36a899f90671b1910a1dff4b18996b517050f4aacb548640bdf8fe844","0xb4368a6946801366550e764247f27c24bed3c5830a49be21ddeee79a67d71e0aff3d5cc0a9b1e18bad5c9e655ad23502","0xa4a216ff9a365d29e027a557ae3d4f52bf4fa11654c4314d65a319810fd799c8fb2d129692d7d68f6c134cde9de5d2c6","0xa814035503cb1adcfdef259521573a5193dfa1e8d74e22649ad1b2b01a44fc6c2352100bc42d6c48584ff1d3a430537d","0xaaa334a2fb779ce6de3c557025ff9bf17243deb3f09a37f6719356b54afd9be09a7b82cd589758779544a08cfd3ed5cc","0xaac004b4b25584ba8c906671196db57d7a4f159cfb430b1590d61d94c5c22cb694c25bb6ee850421db260d063e096145","0xad7b6b1ba1f7950cc8e2b5b0cb9041666361eb023b1deff783420482970cf58213497d64cfc91cf06762dd511b0aac31","0x846f3af6ac23b648a5ea3cdb60b2086e18e42b2837a9d689625af534792f9489a1b22cab64476533993f34149fed1a0b","0xa8784f36c1a8c6e739b090d982480712ff04c9231190b97121c86c84a35cbd561d3372902017ea71fb99ce2a6582f362","0xa398c76ca4aff66b20dfea97e1bbea311a5491b6de44cbcc979bd368818eaef834f188ad6fb413c3120b1af141637cdc","0xaf54a32535604e042dc5a7e296a762f3ddc1fe00741eda9acb8f54be49a8244750d6d8f15a10d9384afbd26bccb662af","0xaa41628c60365750c75cf91a8d4097047d61c624b01d4f298ac90a66409cada1bb99cf42a2577ba173a94745dd73d6d2","0xa4623cedd189249799b7c9afb49960dd86f31572a6edd594dc9d147bd11b368b66afaff6a2dcdecfa873f88991e5a8d6","0xa58a5d3d29c1331b6f4f977ee08afdf95c067db26c21a591b15db682f93d223acd4e031c98434ec7be34922496ec8ec1","0xa31ecb88e06673a2c3ea98a969827babdd0c6a8fc9569d70c024640f31084c7fc2bc8f00eb65023a008e0b47b3d2e364","0xae32f510734cfe1a05f1a49888185191777008667a62a3b5d71f4b249a5a0421d762c98c0dd0626e17f6326ff525e63b","0x9407a54a336fb7632ed16da2929c6ed1e2a8a969990d15f9f322734ee60c00757dec74e4c0224e813efeb1c9be42c09e","0x8fe3971515fb25cbe62a03e4a593dfb4cc3563bc5b7866dfe300b958a53f07fdde463fc7abfe349a2eedf38d569cd126","0xae99451101dde8ce7d7f1b784fe2a1fe0974cd3d7e8d2d3c775892cdc2dfc021eb9f7a5b60681fe7369ec88884e6299a","0xb5dd36fb996d68fb9dff117081435088b54509db6c3bdcbe58bb3711fd21b62f22f7ffef9b8ead2031c0c187717ca738","0x9376161dba759909776ec807351e1cdafbff9a9d817babba680c953344a80dcaa38378ac6a7fb3079d909f5907310336","0x8d92d91ccf259f1c3df11d2e4e92cbe047a9b278ab9ee1341835a08da4c957950a70f51d62bbefd4c6f3c01511e39796","0xa95aa6bfc756de15cb1a21d05b465afd5bf806faee4e662ec335d1e093299632f9498dff50c71844e28d98b0d2cb9e29","0x89f4dc26316e4037269b4afd3d92f7aa9d768be37dd951829657941f2220f7546071ac46a72d715a1af71689982afe61","0x812c4ef835a77db7ead5b86773755711051cbc34cfdc4be7eb41a99ce5094f7d12412a7215275cd9ae8d8426eb91dfb4","0x8cfd6c4fe7aee61657f1d6e5cff1d41d24bafab7ceea78d2f5d680f8b51aeea83ddbb39bf6978bbf1327a2d240012551","0xae7c6ebb4d7b5f462da2004698a6dc54f1e55ef0f3ecd0bc155c9b58f67a038422e209492c86c986d8f24f5261126f51","0xa4ee2d6f77a08089c71194ab48c338632c6b1041c326a483033aecd1bac1baf5de221053ea15c9fbdb8584edec6a731f","0x82d62ceb1242d6dc6527d8f885fe301f4313b87e7e336a34a8d3a898ffca180dbc624f45e1dc07695cecc54023207400","0x9337d74573784dae1f5badff018e4f1c5a2f19d1b57ac07a2f12dd628ed97a4b3a4c84ff4c7d291063f78ec15ec163ca","0x91fa5a8682921fa6dce932b8a9cd3e58ac485c03ef81202f69635f463ced2b366a85a3b6aff905542840c05b5739d7d4","0x8631b733c42dcdc91e0852655e1513864b50fd75ca1078a205205afd3d2c0de2cb2da63c06f4f547212132fd66bd7d16","0x965258ea99b6f1eefc8d8196fad346c44b559e00fb31baf7cdda18e25b185eaafa91e3e366712514ab3ab855f41c9600","0xaff02f3635554e57d140069596a9c3463e85408521b2349b6d1d5c4223874086dfa5a58f8ca73256ebfccc63fb88e58b","0xa166c85614c5b0d5af165a42ab98515c009b6eccb740213e6ec1268e35aebaa73b8c9b22711aac0d5087f2534604eb36","0x967633e5396683a4d51ac8e531194d8243fb808b3237c5ff635afcc0c6ab3fab8443cf9bc7268c25c85d5c9d3b42463c","0xb3dab04913697100af2268f8d71e4daaa6475d08785b4ab816d1a9d209703abdb3e890dcec518c88cb5983d30e977408","0xa4bdf84013dca6a9af8d56d0bec9767a969d7b0b88802ef0eac99a9551dcbc7e03336e63943d8cd072be2d2915d9db25","0xb83a5503f8875dba99bfb8077c50b56120456f836cbb8b89a24e17d88c76071ed9b08a54500ad8e24382a43fa67df89a","0x83e32149769b6c9091f8921195802c8948cfd2b6c9bf9760e70641757719e028d0e65c85bd0fccbc10b81cbad1c87d9a","0xb3b60189b0b7dec69db000719fc89cc811c60e70b80d764af86a9dde1c4becba8e561d9f4ca5437481f01b0d7d1fc807","0xa290656399af969e0a3c03ab8529b6b0173e40c049101115120628fc09d549256f3a358f4cd858e02a9bd025a3e01dd7","0x8633815ef4ecf32dfd3e6221d877176ef1460f7147edae206349cc816431f1a2d60fc547e6dcf0bd31111fce6a822328","0xad5539f19d8358478970caa4fb524b274867ca7449141a21fbd07e6b6291177200e9dca369b665e12ed40dea80b69cce","0x981a72fc476e4f532a10da80f235deb940e4cb6597c8e0f868171488f0eeb5fcc988048dd9ea3bef015aaec0cd79081a","0x9282d6526651dc5e7caf69877a2209d4346bb231b3caed98fec1c95ce3eed284da0617c4d1722e7c316eecebf73601f4","0x836f2b3e00dfa069e4f315454cca69a56a36b6d32514ac81d168e34beabc42ea8a27918d60fe14a8c93ccf040faab02d","0xb4d3e8864dc26809ed314a03e60c7fbe63ce8921dcb52affa19837e59639513782a1e526823f77fc9564d8fcc15bb0ba","0xb35c3469a78ea17878cbb166377b8aaea461a0f7d58cc5f77862cb9a232c5a95452d523362808b661cd24a1e0baa67ab","0x800044ce43a3eec0738b16300361bc744173822642fdf7184a7ac58f6b315478c03f8b57efc36b37c262e08b66260dbc","0xa3fe94ea52c28c985a901f8d895f8d2493dd1d939da8f775c7e595379431d557b83efce814b3f2d9b5a463c8ab5234d0","0xb04bbe642a86b34459811d60affa8c72efaa288a34d4f2e5799807ced34747ef09ca47f90645d36c0a43fd9ce592e41f","0x80609da89da3d8a011674d17aacc7378a9ed907455c914c3adfe80d9d5ff1b903cf0195f7999cd27af91de5177af295d","0xb929600f99e80e834dd9220a02e8b395bdd8cdfd9f93f201e6cd89ae1950e0789f93862082f0c7efd45e4b69224bd92a","0x9052bae965368c78db0d638faf2ea9beb0e42b469adabbba09f85936f948a1cd77cf811a20ae759498770855068adae3","0xa7c693916f59a0ee41b13d045632d4c5e8703a0e1431b50ba0450834747e41a6634ab9c0c1efa6af140f2072c29cf7a6","0x83a40895d9005f007df9ed7fdb17d820d3d66fe419480cede7518e1f54e4c1e2a97ffd71fe2f01187c3707cde5bf9915","0x8ee8e926da165b8f34d249d194864a3994278aa4b829295480edac18395167fa016b2a4ffb0b0f3c89d18622bec2409c","0xadd60d6bf2abc6935ffebfe463c9b305ed2c898a00e2a84b997c014e140a7b254dfddc5be39e406ef0a893c4d67dd1ba","0x8f48795cda6795e9af514489989a9f9e8b6db2b52a36881e4ba166327153d6db922e5148db044b27efe1831b54e16270","0xb43ccddb32f15baaa32d69abf4b298d38e835607fd74aac5b25b5b161e8c865744a06526594faf39521e51fe44d66658","0x83249b11efc76fba2ab77df9b5ffc607e6e2265c7f761dbb3099f3b4ff74ad8b9570036cb04942898f8c33b8442adfcc","0xb049dc45fd585ef8bc67831dc47690f95e466cf11127def6ef9fdfc43017518752aff3df93c3e5f68083f590f554f3dc","0xb0f4dcd488f6725946e1a384d9ae9cd6a12824dafb426e15f4b848b6dabd46ec1177fccd0fa5c0c2260fc57aaadf1e7d","0xb400b2f5705dbd2905c5d9fe3b2f29cedb380954a60b4fab0e55009c47e1908a30bf286f7e01b7125985c9007015f37c","0x97580566e3ddcde5b3e0cedf688aede17a8b738a21f96a0c2efff77061e232ad877e6bc71649d0fbb3ec0dde584bb8e8","0x9504350e6a3ad1a5f711d9e5904bd25b1f6571bcaa66403f1da9fc8200ebd8073308dcf462371073bd8b076fd25df949","0x94184bf24da31a8ca6561c17aa36b6933f07d4966063972bfcc6c97d8daeefd05b7c22d41fa5133327cc0dd000139175","0xb88add150c36e8c338f7ff8efa8efb4e302a5a01afb8e331282eb075ffc3f2f5e5e783a4cef6a0d9c65dbedea48cc093","0xb25827b6746a0ed3bf133beb7e465ba08c39e1960c4555a81384502d6c244bdd7ca19f521c6d192436d71dfafa64b4a6","0xb5ed6e77bd6f1661a5ab3f2e13743385c7ee99dc240e9575b3e7639b4f73a017cf4edbd0932e02577acd2bec274be3fc","0xa25579ff3efe83b344ac7ca26d45d5aac4fd4fdb1809f20e4e48026e154e95d7ea8c7abf6e91628f8448a6a798dd07f3","0x81dc3529a283023f70fec5eb65ef8e3b394b0239bfe40095574a881c5dbe536a6b119e6cc95668b62d6e5944386c07ca","0x93da5217b698dcee39d36c25bd79f2a152e5053add9e4b17cf60cc5dadc0e2d1713d05f7b5917840b6748d25d68f4878","0xb54437d1547e9a87476f03c094c86465f36376c09ef3c8fba0c8906fdeb0421d523a20ab6ce6ee18da9fbab39ede3bee","0xaa5367fff8db3ba5017bc601e9f9ceb867d54c3b17ade967b0bc905f644f6aadc8aa53d3e9ed0e278bf3fc2b0b56a7b2","0x874305f7d11e69b74164cad10ab88ea7df22208c954fcb6872f34a5f9c8292341f85a6250716270563a19b5a112761d4","0x96917c5ff8bd2debf697fbc64455d19cf1efc4e1327b3dde2eef7db7cab762effb43025c4162db0008a0b43b4d060748","0xae77044f5f689ef3c59fbb1afc7fa2e33c5406121f9c2eb1dd089cb320b9d82ab51d6fadb545327dfcc2688c201e9e07","0xa174a13601df492b77a263ff54d9e30a0d9b248a1bfc559a4bbeb251fead9b72790f08bed89dbf224c1cb5548c44abab","0x88a09d6756a015068efa04c8fca73dd96e2314e4f6e9d1aefdf19ef139eccb2000c3f382a18a3ade202641ed2c4b4267","0xb41b17006e2a6a6bce8055ee459557cf835fccaa851885903846dc190adc223f6cad199446ca225b6a65d40382344227","0xaf9a969a70272ac2871fd689f13c0b478e27bdc5127f02c41efabd5814a902dc1e3ed8b3ca1786aafb8f112aa3c87db7","0x8faef0de1c486a7638c2a50af8f34e42b7f11bc1168c03678408702f8d11637f1faf893955a39897d797c851d1e6267e","0x95bff09876e40fee59003b08bab452d9bd2dfae2c6411e153c4fc531f4aa26af8966049cf303865472d56643e3a3ad70","0xa186ad3532db69f509d3f38223e388c9300031630ae02c5e13e6b55db6094554647fe52dbad51f931678c43d97f6b4c6","0x976ecc14c14c93f8d0bcd6ee0a6f829de29fc13e167204e83d9c13d69065994af9c38424443114913e3142ca96138094","0x847ec3a8b963b0a40506ad2e2a2f9119456d36150eeb64856f12c85a85e12d59b295d953d845246be5aeccfb70c1dc04","0xa6be6fc30a561b92e84333e413ce5be1d83de64ff5cef73611840fde672bf26763901912b37dfd8f1af85c3af87c8718","0xb1ea18e5c0a7424d06a9e77c65f2ff5047b5c4530e34e700c0d1bf15579e2afad228a8213c68eff8c14353d2e1f10053","0x8fff13510ac685f51ae914b7177bdf296ecd757385442ea0dbfc8841685b79b7d52c780a40e07723ea34d6179c6f3ee8","0xad2d0e0c00b5a16d50a4ae56a3c0cf2e1b2263e2dd53ddad54679cdbf338300e1003af5ecb73ac3dacb8636661e142d5","0xb854086bc1f668ad8ccc4ed3a7a52eab65210717c3f8b9e6ebc27c1cf27ccba0a4056311c69cfefe875fa45e2cd26e69","0x95000d5a88212033fcc30690e930c2128685b97f26a9e2c52b75e1fb562a1db1b9af071207823ef1927db3ca65ee00ef","0x929ab4e52386b139d32da163a4e1be5760f1d97bcfdaaa146f8b0348c94896b33fdbc3083ff3a41063e1b969a1f84080","0xb126e91bd72a3289a04fa01e108f3ab4b77f2d20a93edc1c70f8ceda1df286461e92f73b7d2f85874abb1454ae1ef535","0x8fe3f04f04422bb2c76f5cfddf80a7a2b01bef7170af5f52c94e64ba1f8f523ff18d09af9235e37d10b3ac8ba3cc6ac4","0xaaf6cc6cfc559ca26b82790935d4919ccc630438032b76874a40c25d77e4b87db2401cef8ad1871011569061ec7badcc","0x8533f1c4e38a4f72c3593ab28ccb163bfb429242a8c23e731478e57950f563b62101b06882f25c8133ea357fad66522c","0xa20e3bcb6b38b66c2de7a7b3d1731cf430ebb94e38897d9ab9a9463bfe813ecf65f39297d2a3daa803f66bff80d6b653","0x8cd7d05a46ad2e98ea82c438f12dc9fad70fa0b8cff2a731847efedc0efadef9a3f4d9e12cf8e9469d157d106f12626d","0xab5fec7f75687d50f35f4336b7ac78108834f98d9979f0327cd11b1557b6ad9dc119889003384b3940b10f0af7b8314e","0xaa93eab6f16b0bee0a2eaf3d548d354a716e1bfa4047ffae14af55bb49bb994310265e10c7ab47ffa33d1c3eceadbb4b","0xae363ffe8d6c6858d3c32967150ef670a2262ab9f46b3f2e3e4ae8910092bad1e7208ff9ba3f28b151dfab12f3474a19","0x83ae23912c04f49176c912a5d728224c3bbfac588e2203e37c6ca7520b01c6225b2830b0d37c8eb641d9abb44a648e28","0x86d99bd43392d34879ff4409aaa44f1a42b34471a59136ff2fc2c5d0f3bee905108958f4a0de383597476b6f8fa380eb","0xae47eed8ebfbd33bf1e92f52fc40d16f4b2b5e0cf4f54f2463af76f83cf0fef26475dff6c5b9d78f81925ca7d51190ed","0x9286bfc698dd8f807748245c4d13de02910fcd8bc9b375a308d8a2bc7c73a05c8254b73931e448fbb2cf2d24f8b42f56","0x98857d698710dbc26a57f167d463de3fc8e15fa4221d8ef6d8853c7843b04d2119a865215075f52674340300e1ff58a7","0xabb8d751f2f97cd345688187accda8e00395503e500bd727b82b0be88484587776c225d64ca72703c186d6d0cb248e76","0xb88f1156883e6edf6df2f4f94079d373992e2d236ddf7003cd8cf84d73e371d16d4397fc20163eb4d8b5ff134beb4b51","0xb37a06d51bf2a06b938b2a1d84fc0e9a0d45e753401035d0c7557b01d200c302169a06c5276ed77b7b832a885376522e","0xb960a785f7ea8fc1d9886ff43e3b736cf7fab383087b6f1d85727473d909a91215ec515fe72783d703e8d214cc72dbde","0xac748de8d5418285e99661d22ef888ee9b19fee4e3bb2db1fbd4404ac32fabf9ba2d41450c2f2ba42bd97cdf28a349b8","0xa89895024ffe3c247d5515a8f2cf3e5275dec9c1c3143d7a4dbabe1aa16761ca69225bd2921a4afee83e01cb4c83c25f","0x8e0cd6b49327ba93279e394f62cb84375fc63bbac7c72eb4f90cd5d71e4cf34f1fe0d92b82ce51e60d9255a0fe99e021","0xab195eaafc5a60c4c91722f53e19fce9c04ba9655f433a18f0472606ec826fbf77828d16f859297a9272d2b4fe50403b","0xaea50380eaca9b09e5baec21e5f522c964b0ac8d4aebb8e1a1a196a01fb5c2c87f524be56a57d2f80274d1a0d2ed7fa6","0xb68a35785d29094de3457406b8f974581ab72e2aea2c3ec1ffd21b0326297f09a838b669e3e1409e127a3bc3eaa8cb72","0xb90a59e63d66d20d5e9a3b45be51fa7963da5ee137a126740036f432c50eecaade78c4a5bc92fe1908a153b15ad92a25","0x9826a9986a35754dfdc31e69bb8b073eb7293aaa747b0990da43c2c04bc001c78257ab3a1a91d3c7f2bb9c8395ed9424","0x854de57710b835c0253eef8a20d2e6f0ef8d260eb4443bbd5c38de0acd38035f0c1ad5d09994744588a497f8eb3b747e","0xadc1109ded58e828f3c992b3d367b8e8d9d5cbe102fb171b4f4dfa66a181ab040f13d15a38b10e50c8c87432904b6e1c","0x87068fec51465d586d65ff531b32fe20d2e02535c08883721654338878b1aee8479fab486a19de804da1f301443f69d0","0x95322a22f4abe8eb0a0f4cf8876c31abeb3684ed984f6b595b9f3b9527b60c5f730d03d4960f5094210a3f6383691348","0xb43fcdad30bb652a82ce6033d6cdd6b004f58eb102d54f4de5a59c17c774c66637e7ed8078b19afe55ed34ac2b969fc7","0x801125a4149f3b2ae29f7745ed91492ebd9de91da253f0a267f864302044310c1f9decede6b1b5a9e1719c36841aff5d","0xa7852f47c6391e4ea0854d59b4a69ac72be49f7f798c19146a787dcc25a48a183ac3902001d0225f242ced6cc09aa378","0xb0c1eb313f3894f5f19ddd7cb3472f015ccf51c24bf4316fae3e8502d3b65132a8d2ac58f7d17eec0a644ef31afda14d","0x8c6ccdc900d78ef20d5b22ad540e73864c858baf068349dafc397cd31c571708ec6ee6afef9e5711a587e3e97f1a50a0","0xa8aa5faaa4bbda5b5e7d610746f27c09bdee3a3f057550bca600ebe1c83749525a135829669a0162c3339ea40dc5525a","0xa7c107c72118446d1dc3c5c1c42f95ca2471dddd61c1461dd8ce028a1dae7656c98c3eca5f6dbeae8f9594e3e652a4d3","0x899eaf183acd5beee0899a58c8ee5fff1dc76df143028d9871d231e8a3999d92098538d070fd1c9db5d9db60f23dfd4a","0x8771579633474fb50075b4c801124f63c4a786e7a618bc50c00122f4fe8c18d1edc123ce9be8436b9bc8159c5d2061ec","0x8416902c51bdb3933ff4e87558121d3fbab9f116f9a5b0ae9cc30c4d145c39dc988f5c0b754da3daeec71fa68144f9b3","0x83f8eb02f40f6369cb8836d521390b06ba91c72618056cd103ede2b6204069ff94c7364c2f24ca1db500ef627be3f1b2","0xb08c6eef8be13656c3963726dc3be95a5087e363fd5e72301322ea73a8840520d51f142cd9d94d0da3b7a6f22d111fd4","0x8374c6a0d41b2da67f26a62120128838ab64f3928769a4280d0650ff18d6262b584e8f68a915bf8e4d1f6e18d72a6ecd","0xb98aeef39fb7eecc46e6cff2632a543757a8bd80bebe409b5d0eafe2922583040749cee9f130cf12eebf85c1dfc0adb4","0x8f9e00f60b9b830e72b7d0b45a3dab2cda1f678880db3b5dc5107e07850dc5146afe8b0999102d4a8bca5cbc27cd8a2c","0xb42800735102f10b3e09c11e9113e0f4955bd19d0c5174f587d446de44230b10c3e8b439fbfc2e47f9e82ac2ade917b3","0x877968c73d43465feea583c7bde8270773fbcdcf9d1e3e4fe492a208e788bb56b329174b0d2539d96877e9d6f5bf1b41","0x915fdf1928be84527b07ceccbc4a278f1e9e010d6f716d8c3a4666bf649411744355ef25b22276c2ab51b3af29c67119","0xa99b23673a9c02a8da9e44fda564aaacabc12fac43b600884e06ff21ca2ece8fb8ca28c593d3966ec6ff427f8f497c05","0x8759613fcfec38cf67297fc0b956382eb403f1b9126d1de3a26e0ee7142346d5457f09c7765d82d49f51726293b3cf7e","0xa0ab65230a0c9a2e2ec267918366deaa93d80068b14e691de2dff126c604e755b72d0865099078870d6a3d47a2f56d14","0xa76186ca2743b7149ab7b5ab83c843d2d724ed85ef13a9e0e23a697ba048cea17acc68d9dda73d1f4ef97b9747e491ec","0xa70362ba9834a49f9f1ffdccf221fc2eb1f7a5cb584bded1d79c44e7e7890ab28d787004c5cc6a45d0e941ae27f1fe39","0xac66effd5784f677ff6fa5cb96d9cf14552d5888a8cd78ff54581b9fb35d3980c9b34cab41f565288812d77e3a44cceb","0x933146088cae286d7d0c2759fab13c1f3e7cea13c05504c006e2ac25f322a779905fe4466f0db965620767d6270ac324","0xb31a6cb5ab165f4b7b66bee6fcab77e410a3c7d7049ca5a6a7bc64b30a1c49bef4a1ed72454b87c8b879c00c57212ac2","0x9570f6171cbc78d58dd8afd84cc2f803ab049dcc15566b4c16406f798b65346f3bb36c45aff846e4604ab79ddba8125f","0x871e9ef179706974e0423fb0a6f17673dd3d91ac9625a5c034d2797c396698489dff3c53abea15b7b5604919fd36acf6","0x879391eff950beb2720f83aa628e43b313ec26e20cad9b75457bd8de5b1883fad8c5f28533ebebac4e377d82145d75da","0xb03bdf830d2cf1c1d8f0bb100fb3d4d399b48ca2e67e8f8513809bdf49beeb4b710438d64bdd9f4d4aebc3cc844e9302","0xadf6fceba8b405cb2a0e853da1a8db38799eaf868a91294a297f0ba4601731a438f1f7a8b15c91cbc7b4f07734d74ac0","0xa931ae0ef4447284cad9e27b334924088b87f489d1c1eb49883cd2f35e4cd445dfac88e564605b32d471b56b4d98a4cb","0xb304ff0820279e94ad069248706d39bddb36cb1ef69e1031f2f0683c69b4e8fe5bee35a64a7d160f8f207253bf6a1080","0xb51c0882970b04879282a60dcfda6577abd62328859c811ad190b4a77b824e4ef7dcfa544f7e76ad0d0c53372e9ba43f","0xa24dd1ce8d1d5af40401a2c2d47027de989313ead893a646456eb4ea9d6e38cf8cd37f75e2dfa631beed89970848a39c","0x943c88ab60e1b649772ebefea93e27bdc89bae1901cb8f181fb813a753861bf7e3c460b909566f30be2ad7ecc7e345aa","0xa2eea192ab4a2213efc58879ce008f8684c3b8da24d7a0124ed33c6ee9d3d12adcac702a938e2ccad79fde467fa413c4","0xa1792fc5047546bc98391908b80fc9b4a790018b580836cfa593426624ab1785d11449a03c93759f34645d277e9f26ee","0xb2f64f70753f79fc04398f220f2ee1a54d14c8bd31c1b27105aae559d5006434135e516e975f57c7a41241ac74ab6aaa","0x86195e4462e04f6e0f4c2545ecc9c0fa812f1ffd6cde31bef2f59c5806d839937d60bd8180c2362555f73aadf6591965","0x8a6d7746a13800bc06e455dc52786c35065e2b08054ab8e569e28391dbef3d2527eea72aa60e1b53a54dc477055bccf2","0x961cc399896c8daecb0784f91943dd32077c9ad661f460f27f048ffc557010b4bd9a4a692306b6f70ff0f597fd31ecbe","0x8edb799cc0407cf8db901082d7fcd613b7dd4ea03caef14073841e54531bdcdf3f661d551edae045b960b506e70b8dc8","0x8eab84a4394a69ff45dad4a17d4a8ce3bb04948c68bc70abbdebdd76c2156507a319d5bf9cfcaf750fe3b4d5c66723ee","0xb4c37ed40d2d3d2ace8ba3e1d0bb1b0651d3d21c3dc5e8a4ef42513d649fc14d6dcd1ba7c8b893a2205f6afc870feb75","0xb02b650ec8c8a75cdb3c8cc64b612c5180aa31e0345ce16b1d9d8e5c7ce28d4feb8ed6bab0be68c13a5acd71f326fab8","0x890bbabc36dc93557dffada73af2e71bd15481fb5345d7b4755498ddb1bd8733f0140cc40007c76ccc8764ba42678d1e","0x96061e58e6b6cf1b5398912930b1057b98d586f2370549ae905cc430a0bec98f76a5729f0cdb63a4933030839c4949dd"],"aggregate_pubkey":"0xab964f788f3b0fa9d9345804f3b8d8fe01cac12b0b0a0168325b6e151c1475b929aa1c0957e1a801bb4725ed17a41dc8"}`), - err: "incorrect length for public keys", + err: "public keys missing", }, { name: "InvalidPubKey", From d3ab971de30cca937b06fcba8c7ccad4cee4b09b Mon Sep 17 00:00:00 2001 From: pk910 Date: Sun, 31 Mar 2024 03:51:49 +0200 Subject: [PATCH 10/18] linter fixes --- http/proposal.go | 1 + spec/altair/beaconstate.go | 10 +++++----- spec/altair/syncaggregate.go | 2 +- spec/altair/synccommittee.go | 2 +- spec/altair/synccommitteecontribution.go | 2 +- spec/bellatrix/beaconstate.go | 10 +++++----- spec/capella/beaconstate.go | 10 +++++----- spec/deneb/beaconstate.go | 10 +++++----- spec/phase0/beaconstate.go | 8 ++++---- spec/phase0/deposit.go | 2 +- 10 files changed, 29 insertions(+), 28 deletions(-) diff --git a/http/proposal.go b/http/proposal.go index 6e2435fb..3835a4df 100644 --- a/http/proposal.go +++ b/http/proposal.go @@ -121,6 +121,7 @@ func (s *Service) Proposal(ctx context.Context, return response, nil } +//nolint:nestif func (s *Service) beaconBlockProposalFromSSZ(res *httpResponse) (*api.Response[*api.VersionedProposal], error) { response := &api.Response[*api.VersionedProposal]{ Data: &api.VersionedProposal{ diff --git a/spec/altair/beaconstate.go b/spec/altair/beaconstate.go index fdbded3b..0160309a 100644 --- a/spec/altair/beaconstate.go +++ b/spec/altair/beaconstate.go @@ -34,16 +34,16 @@ type BeaconState struct { Slot phase0.Slot Fork *phase0.Fork LatestBlockHeader *phase0.BeaconBlockHeader - BlockRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` - StateRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` - HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32"` + BlockRoots []phase0.Root `dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32" ssz-size:"8192,32"` + StateRoots []phase0.Root `dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32" ssz-size:"8192,32"` + HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32"` ETH1Data *phase0.ETH1Data ETH1DataVotes []*phase0.ETH1Data `ssz-max:"2048"` ETH1DepositIndex uint64 Validators []*phase0.Validator `ssz-max:"1099511627776"` Balances []phase0.Gwei `ssz-max:"1099511627776"` - RANDAOMixes []phase0.Root `ssz-size:"65536,32" dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32"` - Slashings []phase0.Gwei `ssz-size:"8192" dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR"` + RANDAOMixes []phase0.Root `dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32" ssz-size:"65536,32"` + Slashings []phase0.Gwei `dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR" ssz-size:"8192"` PreviousEpochParticipation []ParticipationFlags `ssz-max:"1099511627776"` CurrentEpochParticipation []ParticipationFlags `ssz-max:"1099511627776"` JustificationBits bitfield.Bitvector4 `ssz-size:"1"` diff --git a/spec/altair/syncaggregate.go b/spec/altair/syncaggregate.go index cc00ef62..2844bc5c 100644 --- a/spec/altair/syncaggregate.go +++ b/spec/altair/syncaggregate.go @@ -28,7 +28,7 @@ import ( // SyncAggregate is the Ethereum 2 sync aggregate structure. type SyncAggregate struct { - SyncCommitteeBits bitfield.Bitvector512 `ssz-size:"64" dynssz-size:"SYNC_COMMITTEE_SIZE/8"` + SyncCommitteeBits bitfield.Bitvector512 `dynssz-size:"SYNC_COMMITTEE_SIZE/8" ssz-size:"64"` SyncCommitteeSignature phase0.BLSSignature `ssz-size:"96"` } diff --git a/spec/altair/synccommittee.go b/spec/altair/synccommittee.go index 1887d608..c0ffdfbe 100644 --- a/spec/altair/synccommittee.go +++ b/spec/altair/synccommittee.go @@ -27,7 +27,7 @@ import ( // SyncCommittee is the Ethereum 2 sync committee structure. type SyncCommittee struct { - Pubkeys []phase0.BLSPubKey `ssz-size:"512,48" dynssz-size:"SYNC_COMMITTEE_SIZE,48"` + Pubkeys []phase0.BLSPubKey `dynssz-size:"SYNC_COMMITTEE_SIZE,48" ssz-size:"512,48"` AggregatePubkey phase0.BLSPubKey `ssz-size:"48"` } diff --git a/spec/altair/synccommitteecontribution.go b/spec/altair/synccommitteecontribution.go index 32f482b8..ddedaafb 100644 --- a/spec/altair/synccommitteecontribution.go +++ b/spec/altair/synccommitteecontribution.go @@ -33,7 +33,7 @@ type SyncCommitteeContribution struct { BeaconBlockRoot phase0.Root `ssz-size:"32"` SubcommitteeIndex uint64 // AggregationBits size is SYNC_COMMITTEE_SIZE // SYNC_COMMITTEE_SUBNET_COUNT - AggregationBits bitfield.Bitvector128 `ssz-size:"16" dynssz-size:"SYNC_COMMITTEE_SIZE/SYNC_COMMITTEE_SUBNET_COUNT"` + AggregationBits bitfield.Bitvector128 `dynssz-size:"SYNC_COMMITTEE_SIZE/SYNC_COMMITTEE_SUBNET_COUNT" ssz-size:"16"` Signature phase0.BLSSignature `ssz-size:"96"` } diff --git a/spec/bellatrix/beaconstate.go b/spec/bellatrix/beaconstate.go index 2a339960..203b8acc 100644 --- a/spec/bellatrix/beaconstate.go +++ b/spec/bellatrix/beaconstate.go @@ -35,16 +35,16 @@ type BeaconState struct { Slot phase0.Slot Fork *phase0.Fork LatestBlockHeader *phase0.BeaconBlockHeader - BlockRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` - StateRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` - HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32"` + BlockRoots []phase0.Root `dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32" ssz-size:"8192,32"` + StateRoots []phase0.Root `dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32" ssz-size:"8192,32"` + HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32"` ETH1Data *phase0.ETH1Data ETH1DataVotes []*phase0.ETH1Data `ssz-max:"2048"` ETH1DepositIndex uint64 Validators []*phase0.Validator `ssz-max:"1099511627776"` Balances []phase0.Gwei `ssz-max:"1099511627776"` - RANDAOMixes []phase0.Root `ssz-size:"65536,32" dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32"` - Slashings []phase0.Gwei `ssz-size:"8192" dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR"` + RANDAOMixes []phase0.Root `dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32" ssz-size:"65536,32"` + Slashings []phase0.Gwei `dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR" ssz-size:"8192"` PreviousEpochParticipation []altair.ParticipationFlags `ssz-max:"1099511627776"` CurrentEpochParticipation []altair.ParticipationFlags `ssz-max:"1099511627776"` JustificationBits bitfield.Bitvector4 `ssz-size:"1"` diff --git a/spec/capella/beaconstate.go b/spec/capella/beaconstate.go index 43b04f6b..f04362f5 100644 --- a/spec/capella/beaconstate.go +++ b/spec/capella/beaconstate.go @@ -29,16 +29,16 @@ type BeaconState struct { Slot phase0.Slot Fork *phase0.Fork LatestBlockHeader *phase0.BeaconBlockHeader - BlockRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` - StateRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` - HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32"` + BlockRoots []phase0.Root `dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32" ssz-size:"8192,32"` + StateRoots []phase0.Root `dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32" ssz-size:"8192,32"` + HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32"` ETH1Data *phase0.ETH1Data ETH1DataVotes []*phase0.ETH1Data `ssz-max:"2048"` ETH1DepositIndex uint64 Validators []*phase0.Validator `ssz-max:"1099511627776"` Balances []phase0.Gwei `ssz-max:"1099511627776"` - RANDAOMixes []phase0.Root `ssz-size:"65536,32" dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32"` - Slashings []phase0.Gwei `ssz-size:"8192" dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR"` + RANDAOMixes []phase0.Root `dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32" ssz-size:"65536,32"` + Slashings []phase0.Gwei `dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR" ssz-size:"8192"` PreviousEpochParticipation []altair.ParticipationFlags `ssz-max:"1099511627776"` CurrentEpochParticipation []altair.ParticipationFlags `ssz-max:"1099511627776"` JustificationBits bitfield.Bitvector4 `ssz-size:"1"` diff --git a/spec/deneb/beaconstate.go b/spec/deneb/beaconstate.go index cfa0e148..b7c41714 100644 --- a/spec/deneb/beaconstate.go +++ b/spec/deneb/beaconstate.go @@ -30,16 +30,16 @@ type BeaconState struct { Slot phase0.Slot Fork *phase0.Fork LatestBlockHeader *phase0.BeaconBlockHeader - BlockRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` - StateRoots []phase0.Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` - HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32"` + BlockRoots []phase0.Root `dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32" ssz-size:"8192,32"` + StateRoots []phase0.Root `dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32" ssz-size:"8192,32"` + HistoricalRoots []phase0.Root `ssz-max:"16777216" ssz-size:"?,32"` ETH1Data *phase0.ETH1Data ETH1DataVotes []*phase0.ETH1Data `ssz-max:"2048"` ETH1DepositIndex uint64 Validators []*phase0.Validator `ssz-max:"1099511627776"` Balances []phase0.Gwei `ssz-max:"1099511627776"` - RANDAOMixes []phase0.Root `ssz-size:"65536,32" dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32"` - Slashings []phase0.Gwei `ssz-size:"8192" dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR"` + RANDAOMixes []phase0.Root `dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32" ssz-size:"65536,32"` + Slashings []phase0.Gwei `dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR" ssz-size:"8192"` PreviousEpochParticipation []altair.ParticipationFlags `ssz-max:"1099511627776"` CurrentEpochParticipation []altair.ParticipationFlags `ssz-max:"1099511627776"` JustificationBits bitfield.Bitvector4 `ssz-size:"1"` diff --git a/spec/phase0/beaconstate.go b/spec/phase0/beaconstate.go index 07c559f2..49098ce2 100644 --- a/spec/phase0/beaconstate.go +++ b/spec/phase0/beaconstate.go @@ -33,16 +33,16 @@ type BeaconState struct { Slot Slot Fork *Fork LatestBlockHeader *BeaconBlockHeader - BlockRoots []Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` - StateRoots []Root `ssz-size:"8192,32" dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32"` + BlockRoots []Root `dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32" ssz-size:"8192,32"` + StateRoots []Root `dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32" ssz-size:"8192,32"` HistoricalRoots []Root `ssz-max:"16777216" ssz-size:"?,32"` ETH1Data *ETH1Data ETH1DataVotes []*ETH1Data `ssz-max:"2048"` ETH1DepositIndex uint64 Validators []*Validator `ssz-max:"1099511627776"` Balances []Gwei `ssz-max:"1099511627776"` - RANDAOMixes []Root `ssz-size:"65536,32" dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32"` - Slashings []Gwei `ssz-size:"8192" dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR"` + RANDAOMixes []Root `dynssz-size:"EPOCHS_PER_HISTORICAL_VECTOR,32" ssz-size:"65536,32"` + Slashings []Gwei `dynssz-size:"EPOCHS_PER_SLASHINGS_VECTOR" ssz-size:"8192"` PreviousEpochAttestations []*PendingAttestation `ssz-max:"4096"` CurrentEpochAttestations []*PendingAttestation `ssz-max:"4096"` JustificationBits bitfield.Bitvector4 `ssz-size:"1"` diff --git a/spec/phase0/deposit.go b/spec/phase0/deposit.go index fb1e6c8b..deb3bd25 100644 --- a/spec/phase0/deposit.go +++ b/spec/phase0/deposit.go @@ -26,7 +26,7 @@ import ( // Deposit provides information about a deposit. type Deposit struct { - Proof [][]byte `ssz-size:"33,32" dynssz-size:"DEPOSIT_CONTRACT_TREE_DEPTH+1,32"` + Proof [][]byte `dynssz-size:"DEPOSIT_CONTRACT_TREE_DEPTH+1,32" ssz-size:"33,32"` Data *DepositData } From ece29db5ce76cafc021af9cf081d1f7d23fe2a0d Mon Sep 17 00:00:00 2001 From: pk910 Date: Sun, 31 Mar 2024 03:53:33 +0200 Subject: [PATCH 11/18] make linter happy --- spec/phase0/beaconstate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/phase0/beaconstate.go b/spec/phase0/beaconstate.go index 49098ce2..64649ffb 100644 --- a/spec/phase0/beaconstate.go +++ b/spec/phase0/beaconstate.go @@ -35,7 +35,7 @@ type BeaconState struct { LatestBlockHeader *BeaconBlockHeader BlockRoots []Root `dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32" ssz-size:"8192,32"` StateRoots []Root `dynssz-size:"SLOTS_PER_HISTORICAL_ROOT,32" ssz-size:"8192,32"` - HistoricalRoots []Root `ssz-max:"16777216" ssz-size:"?,32"` + HistoricalRoots []Root `ssz-max:"16777216" ssz-size:"?,32"` ETH1Data *ETH1Data ETH1DataVotes []*ETH1Data `ssz-max:"2048"` ETH1DepositIndex uint64 From 60338ca6b1eeadf6cf290541baffa29ca0d9e9bb Mon Sep 17 00:00:00 2001 From: pk910 Date: Sun, 31 Mar 2024 07:43:01 +0200 Subject: [PATCH 12/18] bump dynamic-ssz version --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 720a243a..af96627d 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/holiman/uint256 v1.2.4 github.com/huandu/go-clone v1.6.0 github.com/huandu/go-clone/generic v1.6.0 + github.com/pk910/dynamic-ssz v0.0.1 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.16.0 github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 @@ -35,7 +36,6 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/pk910/dynamic-ssz v0.0.0-20240330223230-eced6836d885 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect diff --git a/go.sum b/go.sum index 3216a8e8..90c400d4 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dz github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/pk910/dynamic-ssz v0.0.0-20240330223230-eced6836d885 h1:7n5NaBz3f5Zb79C3zU8OVuTM0D0XAEwmhfn/Qvi1STU= -github.com/pk910/dynamic-ssz v0.0.0-20240330223230-eced6836d885/go.mod h1:boKvD5unVPTNvyETQV3gDNh0ga4AVCuZ+hJ+ja08QRc= +github.com/pk910/dynamic-ssz v0.0.1 h1:2NBf5sHhaWA4bXozaDzBhwzsPl7B2EoDZT4zL+w8AJU= +github.com/pk910/dynamic-ssz v0.0.1/go.mod h1:boKvD5unVPTNvyETQV3gDNh0ga4AVCuZ+hJ+ja08QRc= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= From 0a11cd0943ff8b1016bc1b46d46c1e9ebf1eb7a3 Mon Sep 17 00:00:00 2001 From: pk910 Date: Mon, 1 Apr 2024 03:02:49 +0200 Subject: [PATCH 13/18] bump `dynamic-ssz` & `go mod tidy` --- go.mod | 5 +++-- go.sum | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index af96627d..4d5aeafe 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/holiman/uint256 v1.2.4 github.com/huandu/go-clone v1.6.0 github.com/huandu/go-clone/generic v1.6.0 - github.com/pk910/dynamic-ssz v0.0.1 + github.com/pk910/dynamic-ssz v0.0.2 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.16.0 github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 @@ -17,6 +17,7 @@ require ( github.com/rs/zerolog v1.32.0 github.com/stretchr/testify v1.8.4 go.opentelemetry.io/otel v1.16.0 + go.opentelemetry.io/otel/trace v1.16.0 golang.org/x/crypto v0.20.0 golang.org/x/sync v0.2.0 ) @@ -42,11 +43,11 @@ require ( github.com/prometheus/procfs v0.10.1 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect golang.org/x/net v0.21.0 // indirect golang.org/x/sys v0.17.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 90c400d4..520296d3 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dz github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/pk910/dynamic-ssz v0.0.1 h1:2NBf5sHhaWA4bXozaDzBhwzsPl7B2EoDZT4zL+w8AJU= -github.com/pk910/dynamic-ssz v0.0.1/go.mod h1:boKvD5unVPTNvyETQV3gDNh0ga4AVCuZ+hJ+ja08QRc= +github.com/pk910/dynamic-ssz v0.0.2 h1:W8PUqjcM7WeLABtQduqthqqaCK5n4g3VzBukI21tmyk= +github.com/pk910/dynamic-ssz v0.0.2/go.mod h1:PpHTmUfKQKTG5X8NJP9uo14eqmZ0akC9AitgrdjeJmY= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -132,6 +132,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/Knetic/govaluate.v3 v3.0.0 h1:18mUyIt4ZlRlFZAAfVetz4/rzlJs9yhN+U02F4u1AOc= +gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E= gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y= gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From f73f89bba8cac0d324bd0b3a409774ac01194ad0 Mon Sep 17 00:00:00 2001 From: pk910 Date: Sat, 6 Apr 2024 17:34:24 +0200 Subject: [PATCH 14/18] implemented suggested changes from review --- http/beaconstate.go | 67 ++++++++++++++++++++------------------- http/proposal.go | 11 +++++-- http/signedbeaconblock.go | 67 ++++++++++++++++++++------------------- 3 files changed, 76 insertions(+), 69 deletions(-) diff --git a/http/beaconstate.go b/http/beaconstate.go index 37edb35d..24e6a744 100644 --- a/http/beaconstate.go +++ b/http/beaconstate.go @@ -55,7 +55,7 @@ func (s *Service) BeaconState(ctx context.Context, switch httpResponse.contentType { case ContentTypeSSZ: - return s.beaconStateFromSSZ(httpResponse) + return s.beaconStateFromSSZ(ctx, httpResponse) case ContentTypeJSON: return s.beaconStateFromJSON(httpResponse) default: @@ -63,7 +63,7 @@ func (s *Service) BeaconState(ctx context.Context, } } -func (s *Service) beaconStateFromSSZ(res *httpResponse) (*api.Response[*spec.VersionedBeaconState], error) { +func (s *Service) beaconStateFromSSZ(ctx context.Context, res *httpResponse) (*api.Response[*spec.VersionedBeaconState], error) { response := &api.Response[*spec.VersionedBeaconState]{ Data: &spec.VersionedBeaconState{ Version: res.consensusVersion, @@ -73,64 +73,65 @@ func (s *Service) beaconStateFromSSZ(res *httpResponse) (*api.Response[*spec.Ver var dynSSZ *dynssz.DynSsz if s.useDynamicSSZ { - dynSSZ = dynssz.NewDynSsz(s.spec) + spec, err := s.Spec(ctx, &api.SpecOpts{}) + if err != nil { + return nil, errors.Join(errors.New("failed to request specs"), err) + } + + dynSSZ = dynssz.NewDynSsz(spec.Data) } + var err error switch res.consensusVersion { case spec.DataVersionPhase0: response.Data.Phase0 = &phase0.BeaconState{} if s.useDynamicSSZ { - if err := dynSSZ.UnmarshalSSZ(response.Data.Phase0, res.body); err != nil { - return nil, errors.Join(errors.New("failed to dynamic decode phase0 beacon state"), err) - } + err = dynSSZ.UnmarshalSSZ(response.Data.Phase0, res.body) } else { - if err := response.Data.Phase0.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode phase0 beacon state"), err) - } + err = response.Data.Phase0.UnmarshalSSZ(res.body) + } + if err != nil { + return nil, errors.Join(errors.New("failed to decode phase0 beacon state"), err) } case spec.DataVersionAltair: response.Data.Altair = &altair.BeaconState{} if s.useDynamicSSZ { - if err := dynSSZ.UnmarshalSSZ(response.Data.Altair, res.body); err != nil { - return nil, errors.Join(errors.New("failed to dynamic decode altair beacon state"), err) - } + err = dynSSZ.UnmarshalSSZ(response.Data.Altair, res.body) } else { - if err := response.Data.Altair.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode altair beacon state"), err) - } + err = response.Data.Altair.UnmarshalSSZ(res.body) + } + if err != nil { + return nil, errors.Join(errors.New("failed to decode altair beacon state"), err) } case spec.DataVersionBellatrix: response.Data.Bellatrix = &bellatrix.BeaconState{} if s.useDynamicSSZ { - if err := dynSSZ.UnmarshalSSZ(response.Data.Bellatrix, res.body); err != nil { - return nil, errors.Join(errors.New("failed to dynamic decode bellatrix beacon state"), err) - } + err = dynSSZ.UnmarshalSSZ(response.Data.Bellatrix, res.body) } else { - if err := response.Data.Bellatrix.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode bellatrix beacon state"), err) - } + err = response.Data.Bellatrix.UnmarshalSSZ(res.body) + } + if err != nil { + return nil, errors.Join(errors.New("failed to decode bellatrix beacon state"), err) } case spec.DataVersionCapella: response.Data.Capella = &capella.BeaconState{} if s.useDynamicSSZ { - if err := dynSSZ.UnmarshalSSZ(response.Data.Capella, res.body); err != nil { - return nil, errors.Join(errors.New("failed to dynamic decode capella beacon state"), err) - } + err = dynSSZ.UnmarshalSSZ(response.Data.Capella, res.body) } else { - if err := response.Data.Capella.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode capella beacon state"), err) - } + err = response.Data.Capella.UnmarshalSSZ(res.body) + } + if err != nil { + return nil, errors.Join(errors.New("failed to decode capella beacon state"), err) } case spec.DataVersionDeneb: response.Data.Deneb = &deneb.BeaconState{} if s.useDynamicSSZ { - if err := dynSSZ.UnmarshalSSZ(response.Data.Deneb, res.body); err != nil { - return nil, errors.Join(errors.New("failed to dynamic decode deneb beacon state"), err) - } + err = dynSSZ.UnmarshalSSZ(response.Data.Deneb, res.body) } else { - if err := response.Data.Deneb.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode deneb beacon state"), err) - } + err = response.Data.Deneb.UnmarshalSSZ(res.body) + } + if err != nil { + return nil, errors.Join(errors.New("failed to decode deneb beacon state"), err) } default: return nil, fmt.Errorf("unhandled state version %s", res.consensusVersion) diff --git a/http/proposal.go b/http/proposal.go index 3835a4df..27173cd7 100644 --- a/http/proposal.go +++ b/http/proposal.go @@ -79,7 +79,7 @@ func (s *Service) Proposal(ctx context.Context, var response *api.Response[*api.VersionedProposal] switch httpResponse.contentType { case ContentTypeSSZ: - response, err = s.beaconBlockProposalFromSSZ(httpResponse) + response, err = s.beaconBlockProposalFromSSZ(ctx, httpResponse) case ContentTypeJSON: response, err = s.beaconBlockProposalFromJSON(httpResponse) default: @@ -122,7 +122,7 @@ func (s *Service) Proposal(ctx context.Context, } //nolint:nestif -func (s *Service) beaconBlockProposalFromSSZ(res *httpResponse) (*api.Response[*api.VersionedProposal], error) { +func (s *Service) beaconBlockProposalFromSSZ(ctx context.Context, res *httpResponse) (*api.Response[*api.VersionedProposal], error) { response := &api.Response[*api.VersionedProposal]{ Data: &api.VersionedProposal{ Version: res.consensusVersion, @@ -138,7 +138,12 @@ func (s *Service) beaconBlockProposalFromSSZ(res *httpResponse) (*api.Response[* var dynSSZ *dynssz.DynSsz if s.useDynamicSSZ { - dynSSZ = dynssz.NewDynSsz(s.spec) + spec, err := s.Spec(ctx, &api.SpecOpts{}) + if err != nil { + return nil, errors.Join(errors.New("failed to request specs"), err) + } + + dynSSZ = dynssz.NewDynSsz(spec.Data) } var err error diff --git a/http/signedbeaconblock.go b/http/signedbeaconblock.go index 62a2e282..c6fe1797 100644 --- a/http/signedbeaconblock.go +++ b/http/signedbeaconblock.go @@ -53,7 +53,7 @@ func (s *Service) SignedBeaconBlock(ctx context.Context, var response *api.Response[*spec.VersionedSignedBeaconBlock] switch httpResponse.contentType { case ContentTypeSSZ: - response, err = s.signedBeaconBlockFromSSZ(httpResponse) + response, err = s.signedBeaconBlockFromSSZ(ctx, httpResponse) case ContentTypeJSON: response, err = s.signedBeaconBlockFromJSON(httpResponse) default: @@ -66,7 +66,7 @@ func (s *Service) SignedBeaconBlock(ctx context.Context, return response, nil } -func (s *Service) signedBeaconBlockFromSSZ(res *httpResponse) (*api.Response[*spec.VersionedSignedBeaconBlock], error) { +func (s *Service) signedBeaconBlockFromSSZ(ctx context.Context, res *httpResponse) (*api.Response[*spec.VersionedSignedBeaconBlock], error) { response := &api.Response[*spec.VersionedSignedBeaconBlock]{ Data: &spec.VersionedSignedBeaconBlock{ Version: res.consensusVersion, @@ -76,64 +76,65 @@ func (s *Service) signedBeaconBlockFromSSZ(res *httpResponse) (*api.Response[*sp var dynSSZ *dynssz.DynSsz if s.useDynamicSSZ { - dynSSZ = dynssz.NewDynSsz(s.spec) + spec, err := s.Spec(ctx, &api.SpecOpts{}) + if err != nil { + return nil, errors.Join(errors.New("failed to request specs"), err) + } + + dynSSZ = dynssz.NewDynSsz(spec.Data) } + var err error switch res.consensusVersion { case spec.DataVersionPhase0: response.Data.Phase0 = &phase0.SignedBeaconBlock{} if s.useDynamicSSZ { - if err := dynSSZ.UnmarshalSSZ(response.Data.Phase0, res.body); err != nil { - return nil, errors.Join(errors.New("failed to dynamic decode phase0 signed beacon block"), err) - } + err = dynSSZ.UnmarshalSSZ(response.Data.Phase0, res.body) } else { - if err := response.Data.Phase0.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode phase0 signed beacon block"), err) - } + err = response.Data.Phase0.UnmarshalSSZ(res.body) + } + if err != nil { + return nil, errors.Join(errors.New("failed to decode phase0 signed beacon block"), err) } case spec.DataVersionAltair: response.Data.Altair = &altair.SignedBeaconBlock{} if s.useDynamicSSZ { - if err := dynSSZ.UnmarshalSSZ(response.Data.Altair, res.body); err != nil { - return nil, errors.Join(errors.New("failed to dynamic decode altair signed beacon block"), err) - } + err = dynSSZ.UnmarshalSSZ(response.Data.Altair, res.body) } else { - if err := response.Data.Altair.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode altair signed beacon block"), err) - } + err = response.Data.Altair.UnmarshalSSZ(res.body) + } + if err != nil { + return nil, errors.Join(errors.New("failed to decode altair signed beacon block"), err) } case spec.DataVersionBellatrix: response.Data.Bellatrix = &bellatrix.SignedBeaconBlock{} if s.useDynamicSSZ { - if err := dynSSZ.UnmarshalSSZ(response.Data.Bellatrix, res.body); err != nil { - return nil, errors.Join(errors.New("failed to dynamic decode bellatrix signed beacon block"), err) - } + err = dynSSZ.UnmarshalSSZ(response.Data.Bellatrix, res.body) } else { - if err := response.Data.Bellatrix.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode bellatrix signed beacon block"), err) - } + err = response.Data.Bellatrix.UnmarshalSSZ(res.body) + } + if err != nil { + return nil, errors.Join(errors.New("failed to decode bellatrix signed beacon block"), err) } case spec.DataVersionCapella: response.Data.Capella = &capella.SignedBeaconBlock{} if s.useDynamicSSZ { - if err := dynSSZ.UnmarshalSSZ(response.Data.Capella, res.body); err != nil { - return nil, errors.Join(errors.New("failed to dynamic decode capella signed beacon block"), err) - } + err = dynSSZ.UnmarshalSSZ(response.Data.Capella, res.body) } else { - if err := response.Data.Capella.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode capella signed beacon block"), err) - } + err = response.Data.Capella.UnmarshalSSZ(res.body) + } + if err != nil { + return nil, errors.Join(errors.New("failed to decode capella signed beacon block"), err) } case spec.DataVersionDeneb: response.Data.Deneb = &deneb.SignedBeaconBlock{} if s.useDynamicSSZ { - if err := dynSSZ.UnmarshalSSZ(response.Data.Deneb, res.body); err != nil { - return nil, errors.Join(errors.New("failed to dynamic decode deneb signed beacon block"), err) - } + err = dynSSZ.UnmarshalSSZ(response.Data.Deneb, res.body) } else { - if err := response.Data.Deneb.UnmarshalSSZ(res.body); err != nil { - return nil, errors.Join(errors.New("failed to decode deneb signed block contents"), err) - } + err = response.Data.Deneb.UnmarshalSSZ(res.body) + } + if err != nil { + return nil, errors.Join(errors.New("failed to decode deneb signed block contents"), err) } default: return nil, fmt.Errorf("unhandled block version %s", res.consensusVersion) From b8f2521ced9d60f4a7a6768f19d4593786796629 Mon Sep 17 00:00:00 2001 From: pk910 Date: Fri, 3 May 2024 12:51:36 +0200 Subject: [PATCH 15/18] fix linter warning --- http/beaconstate.go | 4 ++-- http/proposal.go | 4 ++-- http/signedbeaconblock.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/http/beaconstate.go b/http/beaconstate.go index 996eb3bf..ebf09302 100644 --- a/http/beaconstate.go +++ b/http/beaconstate.go @@ -73,12 +73,12 @@ func (s *Service) beaconStateFromSSZ(ctx context.Context, res *httpResponse) (*a var dynSSZ *dynssz.DynSsz if s.useDynamicSSZ { - spec, err := s.Spec(ctx, &api.SpecOpts{}) + specs, err := s.Spec(ctx, &api.SpecOpts{}) if err != nil { return nil, errors.Join(errors.New("failed to request specs"), err) } - dynSSZ = dynssz.NewDynSsz(spec.Data) + dynSSZ = dynssz.NewDynSsz(specs.Data) } var err error diff --git a/http/proposal.go b/http/proposal.go index bf1e8811..7c340b33 100644 --- a/http/proposal.go +++ b/http/proposal.go @@ -130,12 +130,12 @@ func (s *Service) beaconBlockProposalFromSSZ(ctx context.Context, res *httpRespo var dynSSZ *dynssz.DynSsz if s.useDynamicSSZ { - spec, err := s.Spec(ctx, &api.SpecOpts{}) + specs, err := s.Spec(ctx, &api.SpecOpts{}) if err != nil { return nil, errors.Join(errors.New("failed to request specs"), err) } - dynSSZ = dynssz.NewDynSsz(spec.Data) + dynSSZ = dynssz.NewDynSsz(specs.Data) } var err error diff --git a/http/signedbeaconblock.go b/http/signedbeaconblock.go index eb556931..73e8a5d1 100644 --- a/http/signedbeaconblock.go +++ b/http/signedbeaconblock.go @@ -76,12 +76,12 @@ func (s *Service) signedBeaconBlockFromSSZ(ctx context.Context, res *httpRespons var dynSSZ *dynssz.DynSsz if s.useDynamicSSZ { - spec, err := s.Spec(ctx, &api.SpecOpts{}) + specs, err := s.Spec(ctx, &api.SpecOpts{}) if err != nil { return nil, errors.Join(errors.New("failed to request specs"), err) } - dynSSZ = dynssz.NewDynSsz(spec.Data) + dynSSZ = dynssz.NewDynSsz(specs.Data) } var err error From f3c204010e1641327b411cca636390d2dc85f240 Mon Sep 17 00:00:00 2001 From: pk910 Date: Fri, 3 May 2024 12:55:52 +0200 Subject: [PATCH 16/18] rename `WithDynamicSSZ` to `WithCustomSpecSupport` --- http/beaconstate.go | 12 ++++++------ http/parameters.go | 10 +++++----- http/proposal.go | 18 +++++++++--------- http/service.go | 4 ++-- http/signedbeaconblock.go | 12 ++++++------ 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/http/beaconstate.go b/http/beaconstate.go index ebf09302..065df1ec 100644 --- a/http/beaconstate.go +++ b/http/beaconstate.go @@ -72,7 +72,7 @@ func (s *Service) beaconStateFromSSZ(ctx context.Context, res *httpResponse) (*a } var dynSSZ *dynssz.DynSsz - if s.useDynamicSSZ { + if s.customSpecSupport { specs, err := s.Spec(ctx, &api.SpecOpts{}) if err != nil { return nil, errors.Join(errors.New("failed to request specs"), err) @@ -85,7 +85,7 @@ func (s *Service) beaconStateFromSSZ(ctx context.Context, res *httpResponse) (*a switch res.consensusVersion { case spec.DataVersionPhase0: response.Data.Phase0 = &phase0.BeaconState{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Phase0, res.body) } else { err = response.Data.Phase0.UnmarshalSSZ(res.body) @@ -95,7 +95,7 @@ func (s *Service) beaconStateFromSSZ(ctx context.Context, res *httpResponse) (*a } case spec.DataVersionAltair: response.Data.Altair = &altair.BeaconState{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Altair, res.body) } else { err = response.Data.Altair.UnmarshalSSZ(res.body) @@ -105,7 +105,7 @@ func (s *Service) beaconStateFromSSZ(ctx context.Context, res *httpResponse) (*a } case spec.DataVersionBellatrix: response.Data.Bellatrix = &bellatrix.BeaconState{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Bellatrix, res.body) } else { err = response.Data.Bellatrix.UnmarshalSSZ(res.body) @@ -115,7 +115,7 @@ func (s *Service) beaconStateFromSSZ(ctx context.Context, res *httpResponse) (*a } case spec.DataVersionCapella: response.Data.Capella = &capella.BeaconState{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Capella, res.body) } else { err = response.Data.Capella.UnmarshalSSZ(res.body) @@ -125,7 +125,7 @@ func (s *Service) beaconStateFromSSZ(ctx context.Context, res *httpResponse) (*a } case spec.DataVersionDeneb: response.Data.Deneb = &deneb.BeaconState{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Deneb, res.body) } else { err = response.Data.Deneb.UnmarshalSSZ(res.body) diff --git a/http/parameters.go b/http/parameters.go index b84f0990..d57f277a 100644 --- a/http/parameters.go +++ b/http/parameters.go @@ -33,7 +33,7 @@ type parameters struct { allowDelayedStart bool hooks *Hooks reducedMemoryUsage bool - dynamicSSZ bool + customSpecSupport bool } // Parameter is the interface for service parameters. @@ -125,11 +125,11 @@ func WithReducedMemoryUsage(reducedMemoryUsage bool) Parameter { }) } -// WithDynamicSSZ use dynamic SSZ library, which is able to handle non-mainnet presets. -// Dynamic SSZ en-/decoding is much slower than the static one. Use only if required. -func WithDynamicSSZ(dynamicSSZ bool) Parameter { +// WithCustomSpecSupport switches from the built in static SSZ library to a new dynamic SSZ library, which is able to handle non-mainnet presets. +// Dynamic SSZ en-/decoding is much slower than the static one, so this should only be used if required. +func WithCustomSpecSupport(customSpecSupport bool) Parameter { return parameterFunc(func(p *parameters) { - p.dynamicSSZ = dynamicSSZ + p.customSpecSupport = customSpecSupport }) } diff --git a/http/proposal.go b/http/proposal.go index 7c340b33..738cb5af 100644 --- a/http/proposal.go +++ b/http/proposal.go @@ -129,7 +129,7 @@ func (s *Service) beaconBlockProposalFromSSZ(ctx context.Context, res *httpRespo } var dynSSZ *dynssz.DynSsz - if s.useDynamicSSZ { + if s.customSpecSupport { specs, err := s.Spec(ctx, &api.SpecOpts{}) if err != nil { return nil, errors.Join(errors.New("failed to request specs"), err) @@ -142,14 +142,14 @@ func (s *Service) beaconBlockProposalFromSSZ(ctx context.Context, res *httpRespo switch res.consensusVersion { case spec.DataVersionPhase0: response.Data.Phase0 = &phase0.BeaconBlock{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Phase0, res.body) } else { err = response.Data.Phase0.UnmarshalSSZ(res.body) } case spec.DataVersionAltair: response.Data.Altair = &altair.BeaconBlock{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Altair, res.body) } else { err = response.Data.Altair.UnmarshalSSZ(res.body) @@ -157,14 +157,14 @@ func (s *Service) beaconBlockProposalFromSSZ(ctx context.Context, res *httpRespo case spec.DataVersionBellatrix: if response.Data.Blinded { response.Data.BellatrixBlinded = &apiv1bellatrix.BlindedBeaconBlock{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.BellatrixBlinded, res.body) } else { err = response.Data.BellatrixBlinded.UnmarshalSSZ(res.body) } } else { response.Data.Bellatrix = &bellatrix.BeaconBlock{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Bellatrix, res.body) } else { err = response.Data.Bellatrix.UnmarshalSSZ(res.body) @@ -173,14 +173,14 @@ func (s *Service) beaconBlockProposalFromSSZ(ctx context.Context, res *httpRespo case spec.DataVersionCapella: if response.Data.Blinded { response.Data.CapellaBlinded = &apiv1capella.BlindedBeaconBlock{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.CapellaBlinded, res.body) } else { err = response.Data.CapellaBlinded.UnmarshalSSZ(res.body) } } else { response.Data.Capella = &capella.BeaconBlock{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Capella, res.body) } else { err = response.Data.Capella.UnmarshalSSZ(res.body) @@ -189,14 +189,14 @@ func (s *Service) beaconBlockProposalFromSSZ(ctx context.Context, res *httpRespo case spec.DataVersionDeneb: if response.Data.Blinded { response.Data.DenebBlinded = &apiv1deneb.BlindedBeaconBlock{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.DenebBlinded, res.body) } else { err = response.Data.DenebBlinded.UnmarshalSSZ(res.body) } } else { response.Data.Deneb = &apiv1deneb.BlockContents{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Deneb, res.body) } else { err = response.Data.Deneb.UnmarshalSSZ(res.body) diff --git a/http/service.go b/http/service.go index c2e0a030..bc018a2f 100644 --- a/http/service.go +++ b/http/service.go @@ -73,7 +73,7 @@ type Service struct { enforceJSON bool connectedToDVTMiddleware bool reducedMemoryUsage bool - useDynamicSSZ bool + customSpecSupport bool } // New creates a new Ethereum 2 client service, connecting with a standard HTTP. @@ -127,7 +127,7 @@ func New(ctx context.Context, params ...Parameter) (client.Service, error) { pingSem: semaphore.NewWeighted(1), hooks: parameters.hooks, reducedMemoryUsage: parameters.reducedMemoryUsage, - useDynamicSSZ: parameters.dynamicSSZ, + customSpecSupport: parameters.customSpecSupport, } // Ping the client to see if it is ready to serve requests. diff --git a/http/signedbeaconblock.go b/http/signedbeaconblock.go index 73e8a5d1..766e13a0 100644 --- a/http/signedbeaconblock.go +++ b/http/signedbeaconblock.go @@ -75,7 +75,7 @@ func (s *Service) signedBeaconBlockFromSSZ(ctx context.Context, res *httpRespons } var dynSSZ *dynssz.DynSsz - if s.useDynamicSSZ { + if s.customSpecSupport { specs, err := s.Spec(ctx, &api.SpecOpts{}) if err != nil { return nil, errors.Join(errors.New("failed to request specs"), err) @@ -88,7 +88,7 @@ func (s *Service) signedBeaconBlockFromSSZ(ctx context.Context, res *httpRespons switch res.consensusVersion { case spec.DataVersionPhase0: response.Data.Phase0 = &phase0.SignedBeaconBlock{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Phase0, res.body) } else { err = response.Data.Phase0.UnmarshalSSZ(res.body) @@ -98,7 +98,7 @@ func (s *Service) signedBeaconBlockFromSSZ(ctx context.Context, res *httpRespons } case spec.DataVersionAltair: response.Data.Altair = &altair.SignedBeaconBlock{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Altair, res.body) } else { err = response.Data.Altair.UnmarshalSSZ(res.body) @@ -108,7 +108,7 @@ func (s *Service) signedBeaconBlockFromSSZ(ctx context.Context, res *httpRespons } case spec.DataVersionBellatrix: response.Data.Bellatrix = &bellatrix.SignedBeaconBlock{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Bellatrix, res.body) } else { err = response.Data.Bellatrix.UnmarshalSSZ(res.body) @@ -118,7 +118,7 @@ func (s *Service) signedBeaconBlockFromSSZ(ctx context.Context, res *httpRespons } case spec.DataVersionCapella: response.Data.Capella = &capella.SignedBeaconBlock{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Capella, res.body) } else { err = response.Data.Capella.UnmarshalSSZ(res.body) @@ -128,7 +128,7 @@ func (s *Service) signedBeaconBlockFromSSZ(ctx context.Context, res *httpRespons } case spec.DataVersionDeneb: response.Data.Deneb = &deneb.SignedBeaconBlock{} - if s.useDynamicSSZ { + if s.customSpecSupport { err = dynSSZ.UnmarshalSSZ(response.Data.Deneb, res.body) } else { err = response.Data.Deneb.UnmarshalSSZ(res.body) From 075080d0653ab6527dc59f66aa6a4a35c08f0ff1 Mon Sep 17 00:00:00 2001 From: pk910 Date: Fri, 3 May 2024 13:06:20 +0200 Subject: [PATCH 17/18] removed 2 tests related to removed sync committee size checks --- spec/altair/syncaggregate_test.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/spec/altair/syncaggregate_test.go b/spec/altair/syncaggregate_test.go index 3505cdd2..f19fd575 100644 --- a/spec/altair/syncaggregate_test.go +++ b/spec/altair/syncaggregate_test.go @@ -49,16 +49,6 @@ func TestSyncAggregateJSON(t *testing.T) { input: []byte(`{"sync_committee_bits":"invalid","sync_committee_signature":"0xe63b8ab602266593dbfe7f714891c5fed225e09c214bda8281c86ceddb6ee10727a854f213d33be1f032399e0044db6fa30368b6dc857fa8f12f61fc3bf4113a6e9cefeb11758fb01a9939950e127d71dc9c54a26aec63ef024b6620e6d32e44"}`), err: "invalid value for sync committee bits: encoding/hex: invalid byte: U+0069 'i'", }, - { - name: "SyncCommitteeBitsShort", - input: []byte(`{"sync_committee_bits":"0xfcbc21f184b9b89bfc57cc07232a4fce8e12efee3a8c4967932491267a215cd0aff3e79f19645d6f832592f93d91271071a4e911d3f64447e1f6f68247fdec","sync_committee_signature":"0xe63b8ab602266593dbfe7f714891c5fed225e09c214bda8281c86ceddb6ee10727a854f213d33be1f032399e0044db6fa30368b6dc857fa8f12f61fc3bf4113a6e9cefeb11758fb01a9939950e127d71dc9c54a26aec63ef024b6620e6d32e44"}`), - err: "sync committee bits too short", - }, - { - name: "SyncCommitteeBitsLong", - input: []byte(`{"sync_committee_bits":"0xe7e7fcbc21f184b9b89bfc57cc07232a4fce8e12efee3a8c4967932491267a215cd0aff3e79f19645d6f832592f93d91271071a4e911d3f64447e1f6f68247fdec","sync_committee_signature":"0xe63b8ab602266593dbfe7f714891c5fed225e09c214bda8281c86ceddb6ee10727a854f213d33be1f032399e0044db6fa30368b6dc857fa8f12f61fc3bf4113a6e9cefeb11758fb01a9939950e127d71dc9c54a26aec63ef024b6620e6d32e44"}`), - err: "sync committee bits too long", - }, { name: "SyncCommitteeSignatureMissing", input: []byte(`{"sync_committee_bits":"0xe7fcbc21f184b9b89bfc57cc07232a4fce8e12efee3a8c4967932491267a215cd0aff3e79f19645d6f832592f93d91271071a4e911d3f64447e1f6f68247fdec"}`), From b7b883e07ecae1de7649d8a143d4dda2e1b1a783 Mon Sep 17 00:00:00 2001 From: pk910 Date: Fri, 3 May 2024 13:12:48 +0200 Subject: [PATCH 18/18] bump `pk910/dynamic-ssz` to v0.0.3 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2f4b7864..1b91f74d 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/holiman/uint256 v1.2.4 github.com/huandu/go-clone v1.6.0 github.com/huandu/go-clone/generic v1.6.0 - github.com/pk910/dynamic-ssz v0.0.2 + github.com/pk910/dynamic-ssz v0.0.3 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.16.0 github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e diff --git a/go.sum b/go.sum index b3537ed4..5a89389d 100644 --- a/go.sum +++ b/go.sum @@ -57,8 +57,8 @@ github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dz github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/pk910/dynamic-ssz v0.0.2 h1:W8PUqjcM7WeLABtQduqthqqaCK5n4g3VzBukI21tmyk= -github.com/pk910/dynamic-ssz v0.0.2/go.mod h1:PpHTmUfKQKTG5X8NJP9uo14eqmZ0akC9AitgrdjeJmY= +github.com/pk910/dynamic-ssz v0.0.3 h1:fCWzFowq9P6SYCc7NtJMkZcIHk+r5hSVD+32zVi6Aio= +github.com/pk910/dynamic-ssz v0.0.3/go.mod h1:b6CrLaB2X7pYA+OSEEbkgXDEcRnjLOZIxZTsMuO/Y9c= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=