aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMeng-Ying Yang <garfield@dexon.org>2018-12-25 16:51:08 +0800
committerWei-Ning Huang <w@dexon.org>2019-04-09 21:32:55 +0800
commit0f51629cd2dd0beabd809787453d041ea0d1a25c (patch)
tree7a90b5a04b41448b6276e47139744b761f578591
parent6aee32cd8c3d7f0c7d99bf1fe4951fdf6c534be9 (diff)
downloaddexon-0f51629cd2dd0beabd809787453d041ea0d1a25c.tar.gz
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.go37
-rw-r--r--common/big_test.go95
-rw-r--r--core/types/block.go27
-rw-r--r--core/types/block_test.go93
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)
+ }
+ })
+ }
+}