Skip to content
This repository has been archived by the owner on Jan 21, 2021. It is now read-only.

Create New SSZ Factory for Arrays of Roots #91

Merged
merged 31 commits into from
Oct 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d1a3773
experiment working
rauljordan Oct 16, 2019
91dac05
fully optimized for changing indices!
rauljordan Oct 17, 2019
6c0a0e4
new logic for roots array
rauljordan Oct 18, 2019
eb2269c
use new root impl
rauljordan Oct 18, 2019
777d51a
rem
rauljordan Oct 18, 2019
1eae37a
as fast as caching
rauljordan Oct 18, 2019
7c01739
namespace
rauljordan Oct 18, 2019
cd1c90e
include field name in ssz root func sig
rauljordan Oct 18, 2019
8f7b97c
use maps and field name
rauljordan Oct 18, 2019
9b94d14
use maps properly
rauljordan Oct 18, 2019
260f396
working and acting optimally with namespaced tries
rauljordan Oct 18, 2019
ebf5d35
radically improved times
rauljordan Oct 18, 2019
ccd60bd
gaz and active index roots
rauljordan Oct 18, 2019
60bcc69
comments
rauljordan Oct 18, 2019
09708e6
impl marshal unmarshal
rauljordan Oct 19, 2019
d5140d4
fix build
rauljordan Oct 19, 2019
eed1ee1
better unmarshal
rauljordan Oct 19, 2019
7dbc4ee
edit
rauljordan Oct 19, 2019
8944f39
fix up unmarshaling
rauljordan Oct 20, 2019
1027a38
fix up the broken tests
rauljordan Oct 20, 2019
eb21d7e
add helper for disabling ssz cache in between runs
rauljordan Oct 20, 2019
e90e27f
add ccache todo
rauljordan Oct 20, 2019
4afb6ac
namespace by the hashkey to avoid collisions
rauljordan Oct 20, 2019
d6a3f55
exp
rauljordan Oct 20, 2019
a9781b3
bah slow again
rauljordan Oct 20, 2019
af32a7e
leaves
rauljordan Oct 20, 2019
740f1a3
all pass
rauljordan Oct 20, 2019
ebe35a3
comment
rauljordan Oct 21, 2019
8a7ef68
default disable
rauljordan Oct 21, 2019
971071d
cache enable
rauljordan Oct 21, 2019
f39ed31
prep for merge
rauljordan Oct 21, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions spectests/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ go_test(
tags = ["spectest"],
deps = [
"//:go_default_library",
"//types:go_default_library",
"@com_github_ghodss_yaml//:go_default_library",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
],
Expand Down
5 changes: 5 additions & 0 deletions spectests/ssz_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@ import (
"github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/ghodss/yaml"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/go-ssz/types"
)

func init() {
types.ToggleCache(false)
}

// sszComparisonConfig is used to specify the value to marshal, unmarshal into,
// as well as the expected results from the spec test YAML files.
type sszComparisonConfig struct {
Expand Down
4 changes: 2 additions & 2 deletions ssz.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func HashTreeRoot(val interface{}) ([32]byte, error) {
if err != nil {
return [32]byte{}, errors.Wrapf(err, "could not generate tree hasher for type: %v", rval.Type())
}
return factory.Root(rval, rval.Type(), 0)
return factory.Root(rval, rval.Type(), "", 0)
}

// HashTreeRootBitlist determines the root hash of a bitfield.Bitlist type using SSZ's Merkleization.
Expand Down Expand Up @@ -162,7 +162,7 @@ func HashTreeRootWithCapacity(val interface{}, maxCapacity uint64) ([32]byte, er
if err != nil {
return [32]byte{}, errors.Wrapf(err, "could not generate tree hasher for type: %v", rval.Type())
}
return factory.Root(rval, rval.Type(), maxCapacity)
return factory.Root(rval, rval.Type(), "", maxCapacity)
}

// SigningRoot truncates the last property of the struct passed in
Expand Down
73 changes: 73 additions & 0 deletions ssz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"encoding/hex"
"reflect"
"strconv"
"sync"
"testing"

Expand All @@ -12,6 +13,10 @@ import (
"github.com/prysmaticlabs/go-ssz/types"
)

type beaconState struct {
BlockRoots [][]byte `ssz-size:"65536,32"`
}

type fork struct {
PreviousVersion [4]byte
CurrentVersion [4]byte
Expand Down Expand Up @@ -694,6 +699,74 @@ func TestSigningRoot_ConcurrentAccess(t *testing.T) {
wg.Wait()
}

func BenchmarkSSZ_NoCache(b *testing.B) {
b.StopTimer()
bs := &beaconState{
BlockRoots: make([][]byte, 65536),
}
for i := 0; i < len(bs.BlockRoots); i++ {
newItem := [32]byte{1, 2, 3}
bs.BlockRoots[i] = newItem[:]
}
b.StartTimer()
for i := 0; i < b.N; i++ {
if _, err := HashTreeRoot(bs); err != nil {
b.Fatal(err)
}
}
types.ToggleCache(true)
}

func BenchmarkSSZ_WithCache(b *testing.B) {
b.StopTimer()
types.ToggleCache(true)
bs := &beaconState{
BlockRoots: make([][]byte, 65536),
}
for i := 0; i < len(bs.BlockRoots); i++ {
newItem := [32]byte{1, 2, 3}
bs.BlockRoots[i] = newItem[:]
}
b.StartTimer()
for i := 0; i < b.N; i++ {
if _, err := HashTreeRoot(bs); err != nil {
b.Fatal(err)
}
}
types.ToggleCache(false)
}

func BenchmarkSSZ_SingleElementChanged(b *testing.B) {
b.StopTimer()
types.ToggleCache(true)
bs := &beaconState{
BlockRoots: make([][]byte, 65536),
}
for i := 0; i < len(bs.BlockRoots); i++ {
newItem := [32]byte{1, 2, 3}
bs.BlockRoots[i] = newItem[:]
}
if _, err := HashTreeRoot(bs); err != nil {
b.Fatal(err)
}
b.StartTimer()
for i := 0; i < b.N; i++ {
newItem := []byte(strconv.Itoa(i))
newRoot := toBytes32(newItem)
bs.BlockRoots[i%len(bs.BlockRoots)] = newRoot[:]
if _, err := HashTreeRoot(bs); err != nil {
b.Fatal(err)
}
}
types.ToggleCache(false)
}

func toBytes32(x []byte) [32]byte {
var y [32]byte
copy(y[:], x)
return y
}

func hexDecodeOrDie(t *testing.T, s string) []byte {
res, err := hex.DecodeString(s)
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion types/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go_library(
srcs = [
"array_basic.go",
"array_composite.go",
"array_roots.go",
"basic.go",
"determine_size.go",
"factory.go",
Expand All @@ -30,7 +31,7 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"array_basic_test.go",
"array_roots_test.go",
"helpers_test.go",
"struct_test.go",
],
Expand Down
27 changes: 7 additions & 20 deletions types/array_basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,18 @@ func newBasicArraySSZ() *basicArraySSZ {
}
}

func (b *basicArraySSZ) Root(val reflect.Value, typ reflect.Type, maxCapacity uint64) ([32]byte, error) {
func (b *basicArraySSZ) Root(val reflect.Value, typ reflect.Type, fieldName string, maxCapacity uint64) ([32]byte, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need fieldName ? it isnt used in basicArraySSZ

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to add it everywhere because all of these functions need to meet the same interface, and it could be useful down the line for further caching or namespacing

numItems := val.Len()
hashKeyElements := make([]byte, BytesPerChunk*numItems)
emptyKey := highwayhash.Sum(hashKeyElements, fastSumHashKey[:])
leaves := make([][]byte, numItems)
elemKind := typ.Elem().Kind()
offset := 0
var factory SSZAble
var err error
if numItems > 0 {
factory, err = SSZFactory(val.Index(0), typ.Elem())
if err != nil {
return [32]byte{}, err
}
factory, err := SSZFactory(val.Index(0), typ.Elem())
if err != nil {
return [32]byte{}, err
}
for i := 0; i < numItems; i++ {
// If we are marshaling an byte array of length 32, we shortcut the computations and
// simply return it as an identity root.
if elemKind == reflect.Array && typ.Elem().Elem().Kind() == reflect.Uint8 && val.Index(i).Len() == 32 {
leaves[i] = val.Index(i).Bytes()
copy(hashKeyElements[offset:offset+32], leaves[i])
offset += 32
continue
}
r, err := factory.Root(val.Index(i), typ.Elem(), 0)
r, err := factory.Root(val.Index(i), typ.Elem(), "", 0)
if err != nil {
return [32]byte{}, err
}
Expand All @@ -58,7 +45,7 @@ func (b *basicArraySSZ) Root(val reflect.Value, typ reflect.Type, maxCapacity ui
offset += 32
}
hashKey := highwayhash.Sum(hashKeyElements, fastSumHashKey[:])
if hashKey != emptyKey {
if enableCache && hashKey != emptyKey {
b.lock.Lock()
res := b.hashCache.Get(string(hashKey[:]))
b.lock.Unlock()
Expand All @@ -74,7 +61,7 @@ func (b *basicArraySSZ) Root(val reflect.Value, typ reflect.Type, maxCapacity ui
if err != nil {
return [32]byte{}, err
}
if hashKey != emptyKey {
if enableCache && hashKey != emptyKey {
b.lock.Lock()
b.hashCache.Set(string(hashKey[:]), root, time.Hour)
b.lock.Unlock()
Expand Down
25 changes: 0 additions & 25 deletions types/array_basic_test.go

This file was deleted.

4 changes: 2 additions & 2 deletions types/array_composite.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func newCompositeArraySSZ() *compositeArraySSZ {
return &compositeArraySSZ{}
}

func (b *compositeArraySSZ) Root(val reflect.Value, typ reflect.Type, maxCapacity uint64) ([32]byte, error) {
func (b *compositeArraySSZ) Root(val reflect.Value, typ reflect.Type, fieldName string, maxCapacity uint64) ([32]byte, error) {
var factory SSZAble
var err error
numItems := val.Len()
Expand All @@ -30,7 +30,7 @@ func (b *compositeArraySSZ) Root(val reflect.Value, typ reflect.Type, maxCapacit
}
limit := (uint64(val.Len())*elemSize + 31) / 32
for i := 0; i < val.Len(); i++ {
r, err := factory.Root(val.Index(i), typ.Elem(), 0)
r, err := factory.Root(val.Index(i), typ.Elem(), "", 0)
if err != nil {
return [32]byte{}, err
}
Expand Down
Loading