From 738fa0ac30ac1185a56b941565a09803a314642d Mon Sep 17 00:00:00 2001 From: Eduard S Date: Wed, 18 Nov 2020 12:54:45 +0100 Subject: [PATCH] Update SQL types, improve SQL *big.Int - In SQL Tables, set rollup_vars.forge_l1_timeout to BIGINT (instead of BYTEA) - In "bigint" encoding/decoding used with meddler, store the *big.Int as raw bytes, instead of base64 to be more space efficient --- apitypes/apitypes.go | 28 +++++++--------------------- db/migrations/0001.sql | 2 +- db/utils.go | 35 +++++++++++------------------------ 3 files changed, 19 insertions(+), 46 deletions(-) diff --git a/apitypes/apitypes.go b/apitypes/apitypes.go index db4b624..b8753ef 100644 --- a/apitypes/apitypes.go +++ b/apitypes/apitypes.go @@ -33,25 +33,12 @@ func NewBigIntStr(bigInt *big.Int) *BigIntStr { // Scan implements Scanner for database/sql func (b *BigIntStr) Scan(src interface{}) error { - // decode base64 src - var decoded []byte - var err error - if srcStr, ok := src.(string); ok { - // src is a string - decoded, err = base64.StdEncoding.DecodeString(srcStr) - } else if srcBytes, ok := src.([]byte); ok { - // src is []byte - decoded, err = base64.StdEncoding.DecodeString(string(srcBytes)) - } else { - // unexpected src + srcBytes, ok := src.([]byte) + if !ok { return fmt.Errorf("can't scan %T into apitypes.BigIntStr", src) } - if err != nil { - return err - } - // decoded bytes to *big.Int - bigInt := &big.Int{} - bigInt = bigInt.SetBytes(decoded) + // bytes to *big.Int + bigInt := new(big.Int).SetBytes(srcBytes) // *big.Int to BigIntStr bigIntStr := NewBigIntStr(bigInt) if bigIntStr == nil { @@ -64,13 +51,12 @@ func (b *BigIntStr) Scan(src interface{}) error { // Value implements valuer for database/sql func (b BigIntStr) Value() (driver.Value, error) { // string to *big.Int - bigInt := &big.Int{} - bigInt, ok := bigInt.SetString(string(b), 10) + bigInt, ok := new(big.Int).SetString(string(b), 10) if !ok || bigInt == nil { return nil, errors.New("invalid representation of a *big.Int") } - // *big.Int to base64 - return base64.StdEncoding.EncodeToString(bigInt.Bytes()), nil + // *big.Int to bytes + return bigInt.Bytes(), nil } // StrBigInt is used to unmarshal BigIntStr directly into an alias of big.Int diff --git a/db/migrations/0001.sql b/db/migrations/0001.sql index 93d0f85..b237eee 100644 --- a/db/migrations/0001.sql +++ b/db/migrations/0001.sql @@ -526,7 +526,7 @@ FOR EACH ROW EXECUTE PROCEDURE forge_l1_user_txs(); CREATE TABLE rollup_vars ( eth_block_num BIGINT PRIMARY KEY REFERENCES block (eth_block_num) ON DELETE CASCADE, fee_add_token BYTEA NOT NULL, - forge_l1_timeout BYTEA NOT NULL, + forge_l1_timeout BIGINT NOT NULL, withdrawal_delay BIGINT NOT NULL, buckets BYTEA ); diff --git a/db/utils.go b/db/utils.go index 8f3e1e1..0e3a594 100644 --- a/db/utils.go +++ b/db/utils.go @@ -1,7 +1,6 @@ package db import ( - "encoding/base64" "fmt" "math/big" "reflect" @@ -95,14 +94,8 @@ func (b BigIntMeddler) PostRead(fieldPtr, scanTarget interface{}) error { if ptr == nil { return fmt.Errorf("BigIntMeddler.PostRead: nil pointer") } - - data, err := base64.StdEncoding.DecodeString(*ptr) - if err != nil { - return fmt.Errorf("big.Int decode error: %v", err) - } field := fieldPtr.(**big.Int) - *field = new(big.Int).SetBytes(data) - + *field = new(big.Int).SetBytes([]byte(*ptr)) return nil } @@ -110,9 +103,7 @@ func (b BigIntMeddler) PostRead(fieldPtr, scanTarget interface{}) error { func (b BigIntMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}, err error) { field := fieldPtr.(*big.Int) - str := base64.StdEncoding.EncodeToString(field.Bytes()) - - return str, nil + return field.Bytes(), nil } // BigIntNullMeddler encodes or decodes the field value to or from JSON @@ -125,23 +116,19 @@ func (b BigIntNullMeddler) PreRead(fieldAddr interface{}) (scanTarget interface{ // PostRead is called after a Scan operation for fields that have the BigIntNullMeddler func (b BigIntNullMeddler) PostRead(fieldPtr, scanTarget interface{}) error { - sv := reflect.ValueOf(scanTarget) - if sv.Elem().IsNil() { + field := fieldPtr.(**big.Int) + ptrPtr := scanTarget.(*interface{}) + if *ptrPtr == nil { // null column, so set target to be zero value - fv := reflect.ValueOf(fieldPtr) - fv.Elem().Set(reflect.Zero(fv.Elem().Type())) + *field = nil return nil } // not null - encoded := new([]byte) - refEnc := reflect.ValueOf(encoded) - refEnc.Elem().Set(sv.Elem().Elem()) - data, err := base64.StdEncoding.DecodeString(string(*encoded)) - if err != nil { - return fmt.Errorf("big.Int decode error: %v", err) + ptr := (*ptrPtr).([]byte) + if ptr == nil { + return fmt.Errorf("BigIntMeddler.PostRead: nil pointer") } - field := fieldPtr.(**big.Int) - *field = new(big.Int).SetBytes(data) + *field = new(big.Int).SetBytes(ptr) return nil } @@ -151,7 +138,7 @@ func (b BigIntNullMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{} if field == nil { return nil, nil } - return base64.StdEncoding.EncodeToString(field.Bytes()), nil + return field.Bytes(), nil } // SliceToSlicePtrs converts any []Foo to []*Foo