diff options
author | Meng-Ying Yang <garfield@dexon.org> | 2018-12-25 16:51:08 +0800 |
---|---|---|
committer | Wei-Ning Huang <w@dexon.org> | 2019-04-09 21:32:55 +0800 |
commit | 0f51629cd2dd0beabd809787453d041ea0d1a25c (patch) | |
tree | 7a90b5a04b41448b6276e47139744b761f578591 | |
parent | 6aee32cd8c3d7f0c7d99bf1fe4951fdf6c534be9 (diff) | |
download | dexon-0f51629cd2dd0beabd809787453d041ea0d1a25c.tar dexon-0f51629cd2dd0beabd809787453d041ea0d1a25c.tar.gz dexon-0f51629cd2dd0beabd809787453d041ea0d1a25c.tar.bz2 dexon-0f51629cd2dd0beabd809787453d041ea0d1a25c.tar.lz dexon-0f51629cd2dd0beabd809787453d041ea0d1a25c.tar.xz dexon-0f51629cd2dd0beabd809787453d041ea0d1a25c.tar.zst dexon-0f51629cd2dd0beabd809787453d041ea0d1a25c.zip |
core: add database/sql support for more types (#102)
* core: types: add database/sql support for BlockNonce
* common: add database/sql support with Big
New Big type is declared to let big.Int support database/sql by
implementing Scan() and Value() on new type.
-rw-r--r-- | common/big.go | 37 | ||||
-rw-r--r-- | common/big_test.go | 95 | ||||
-rw-r--r-- | core/types/block.go | 27 | ||||
-rw-r--r-- | core/types/block_test.go | 93 |
4 files changed, 243 insertions, 9 deletions
diff --git a/common/big.go b/common/big.go index 65d4377bf..dcc5269a7 100644 --- a/common/big.go +++ b/common/big.go @@ -16,7 +16,11 @@ package common -import "math/big" +import ( + "database/sql/driver" + "fmt" + "math/big" +) // Common big integers often used var ( @@ -28,3 +32,34 @@ var ( Big256 = big.NewInt(256) Big257 = big.NewInt(257) ) + +// Big support database/sql Scan and Value. +type Big big.Int + +// Scan implements Scanner for database/sql. +func (b *Big) Scan(src interface{}) error { + newB := new(big.Int) + switch t := src.(type) { + case int64: + *b = Big(*newB.SetInt64(t)) + case uint64: + *b = Big(*newB.SetUint64(t)) + case []byte: + *b = Big(*newB.SetBytes(t)) + case string: + v, ok := newB.SetString(t, 10) + if !ok { + return fmt.Errorf("invalid string format %v", src) + } + *b = Big(*v) + default: + return fmt.Errorf("can't scan %T into Big", src) + } + return nil +} + +// Value implements valuer for database/sql. +func (b Big) Value() (driver.Value, error) { + b2 := big.Int(b) + return (&b2).String(), nil +} diff --git a/common/big_test.go b/common/big_test.go new file mode 100644 index 000000000..0339b4760 --- /dev/null +++ b/common/big_test.go @@ -0,0 +1,95 @@ +package common + +import ( + "database/sql/driver" + "math/big" + "reflect" + "testing" +) + +func TestBig_Scan(t *testing.T) { + type args struct { + src interface{} + } + tests := []struct { + name string + args args + value Big + wantErr bool + }{ + { + name: "scan int64", + args: args{src: int64(-10)}, + value: Big(*big.NewInt(-10)), + wantErr: false, + }, + { + name: "scan uint64", + args: args{src: uint64(10)}, + value: Big(*big.NewInt(10)), + wantErr: false, + }, + { + name: "scan bytes", + args: args{src: []byte{0x0a}}, + value: Big(*big.NewInt(10)), + wantErr: false, + }, + { + name: "scan string", + args: args{src: "-10"}, + value: Big(*big.NewInt(-10)), + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &Big{} + if err := b.Scan(tt.args.src); (err != nil) != tt.wantErr { + t.Errorf("Big.Scan() error = %v, wantErr %v", err, tt.wantErr) + } + + if !tt.wantErr { + if !reflect.DeepEqual(*b, tt.value) { + t.Errorf( + "Big.Scan() wrong value (got: %v, want: %v)", + *b, tt.value, + ) + } + } + }) + } + +} +func TestBig_Value(t *testing.T) { + r := "12345" + b := Big(*big.NewInt(12345)) + tests := []struct { + name string + b Big + want driver.Value + wantErr bool + }{ + { + name: "working value", + b: b, + want: r, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.b.Value() + if (err != nil) != tt.wantErr { + t.Errorf("Big.Value() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Hash.Value() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/core/types/block.go b/core/types/block.go index 23da3ea77..96df245b7 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -18,7 +18,9 @@ package types import ( + "database/sql/driver" "encoding/binary" + "fmt" "io" "math/big" "sort" @@ -37,10 +39,15 @@ var ( EmptyUncleHash = CalcUncleHash(nil) ) +const ( + // Length of block nonce in bytes. + BlockNonceLength = 8 +) + // A BlockNonce is a 64-bit hash which proves (combined with the // mix-hash) that a sufficient amount of computation has been carried // out on a block. -type BlockNonce [8]byte +type BlockNonce [BlockNonceLength]byte // EncodeNonce converts the given integer to a block nonce. func EncodeNonce(i uint64) BlockNonce { @@ -64,6 +71,24 @@ func (n *BlockNonce) UnmarshalText(input []byte) error { return hexutil.UnmarshalFixedText("BlockNonce", input, n[:]) } +// Scan implements Scanner for database/sql. +func (n *BlockNonce) Scan(src interface{}) error { + srcB, ok := src.([]byte) + if !ok { + return fmt.Errorf("can't scan %T into BlockNonce", src) + } + if len(srcB) != BlockNonceLength { + return fmt.Errorf("can't scan []byte of len %d into BlockNonce, want %d", len(srcB), BlockNonceLength) + } + copy(n[:], srcB) + return nil +} + +// Value implements valuer for database/sql. +func (n BlockNonce) Value() (driver.Value, error) { + return n[:], nil +} + // WitnessData represents the witness data. type WitnessData struct { Root common.Hash diff --git a/core/types/block_test.go b/core/types/block_test.go index b2ac5485c..8e1165a99 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -16,18 +16,14 @@ package types -/* import ( - "bytes" - "fmt" - "math/big" + "database/sql/driver" "reflect" "testing" - - "github.com/dexon-foundation/dexon/common" - "github.com/dexon-foundation/dexon/rlp" ) +/* + // from bcValidBlockTest.json, "SimpleTx" func TestBlockEncoding(t *testing.T) { blockEnc := common.FromHex("f90260f901f9a083cafc574e1f51ba9dc0568fc617a08ea2429fb384059c972f13b19fa1c8dd55a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a05fe50b260da6308036625b850b5d6ced6d0a9f814c0688bc91ffb7b7a3a54b67a0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4f861f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1c0") @@ -70,3 +66,86 @@ func TestBlockEncoding(t *testing.T) { } } */ + +func TestBlockNonce_Scan(t *testing.T) { + type args struct { + src interface{} + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "working scan", + args: args{src: []byte{ + 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, + }}, + wantErr: false, + }, + { + name: "non working scan", + args: args{src: int64(1234567890)}, + wantErr: true, + }, + { + name: "invalid length scan", + args: args{src: []byte{ + 0xb2, 0x6f, 0x2b, 0x34, 0x2a, + }}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := &BlockNonce{} + if err := n.Scan(tt.args.src); (err != nil) != tt.wantErr { + t.Errorf("BlockNonce.Scan() error = %v, wantErr %v", err, tt.wantErr) + } + + if !tt.wantErr { + for i := range n { + if n[i] != tt.args.src.([]byte)[i] { + t.Errorf( + "BlockNonce.Scan() didn't scan the %d src correctly (have %X, want %X)", + i, n[i], tt.args.src.([]byte)[i], + ) + } + } + } + }) + } +} + +func TestBlockNonce_Value(t *testing.T) { + b := []byte{ + 0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, + } + var nonce BlockNonce + nonce.UnmarshalText([]byte("0xb26f2b342aab24bc")) + tests := []struct { + name string + n BlockNonce + want driver.Value + wantErr bool + }{ + { + name: "Working value", + n: nonce, + want: b, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.n.Value() + if (err != nil) != tt.wantErr { + t.Errorf("BlockNonce.Value() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("BlockNonce.Value() = %v, want %v", got, tt.want) + } + }) + } +} |