Browse Source

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
feature/sql-semaphore1
Eduard S 4 years ago
parent
commit
738fa0ac30
3 changed files with 19 additions and 46 deletions
  1. +7
    -21
      apitypes/apitypes.go
  2. +1
    -1
      db/migrations/0001.sql
  3. +11
    -24
      db/utils.go

+ 7
- 21
apitypes/apitypes.go

@ -33,25 +33,12 @@ func NewBigIntStr(bigInt *big.Int) *BigIntStr {
// Scan implements Scanner for database/sql // Scan implements Scanner for database/sql
func (b *BigIntStr) Scan(src interface{}) error { 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) 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 // *big.Int to BigIntStr
bigIntStr := NewBigIntStr(bigInt) bigIntStr := NewBigIntStr(bigInt)
if bigIntStr == nil { if bigIntStr == nil {
@ -64,13 +51,12 @@ func (b *BigIntStr) Scan(src interface{}) error {
// Value implements valuer for database/sql // Value implements valuer for database/sql
func (b BigIntStr) Value() (driver.Value, error) { func (b BigIntStr) Value() (driver.Value, error) {
// string to *big.Int // 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 { if !ok || bigInt == nil {
return nil, errors.New("invalid representation of a *big.Int") 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 // StrBigInt is used to unmarshal BigIntStr directly into an alias of big.Int

+ 1
- 1
db/migrations/0001.sql

@ -526,7 +526,7 @@ FOR EACH ROW EXECUTE PROCEDURE forge_l1_user_txs();
CREATE TABLE rollup_vars ( CREATE TABLE rollup_vars (
eth_block_num BIGINT PRIMARY KEY REFERENCES block (eth_block_num) ON DELETE CASCADE, eth_block_num BIGINT PRIMARY KEY REFERENCES block (eth_block_num) ON DELETE CASCADE,
fee_add_token BYTEA NOT NULL, fee_add_token BYTEA NOT NULL,
forge_l1_timeout BYTEA NOT NULL,
forge_l1_timeout BIGINT NOT NULL,
withdrawal_delay BIGINT NOT NULL, withdrawal_delay BIGINT NOT NULL,
buckets BYTEA buckets BYTEA
); );

+ 11
- 24
db/utils.go

@ -1,7 +1,6 @@
package db package db
import ( import (
"encoding/base64"
"fmt" "fmt"
"math/big" "math/big"
"reflect" "reflect"
@ -95,14 +94,8 @@ func (b BigIntMeddler) PostRead(fieldPtr, scanTarget interface{}) error {
if ptr == nil { if ptr == nil {
return fmt.Errorf("BigIntMeddler.PostRead: nil pointer") 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 := fieldPtr.(**big.Int)
*field = new(big.Int).SetBytes(data)
*field = new(big.Int).SetBytes([]byte(*ptr))
return nil return nil
} }
@ -110,9 +103,7 @@ func (b BigIntMeddler) PostRead(fieldPtr, scanTarget interface{}) error {
func (b BigIntMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}, err error) { func (b BigIntMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}, err error) {
field := fieldPtr.(*big.Int) 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 // 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 // PostRead is called after a Scan operation for fields that have the BigIntNullMeddler
func (b BigIntNullMeddler) PostRead(fieldPtr, scanTarget interface{}) error { 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 // 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 return nil
} }
// not null // 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 return nil
} }
@ -151,7 +138,7 @@ func (b BigIntNullMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}
if field == nil { if field == nil {
return nil, nil return nil, nil
} }
return base64.StdEncoding.EncodeToString(field.Bytes()), nil
return field.Bytes(), nil
} }
// SliceToSlicePtrs converts any []Foo to []*Foo // SliceToSlicePtrs converts any []Foo to []*Foo

Loading…
Cancel
Save