1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
package common
import (
"math/big"
"github.com/shopspring/decimal"
"golang.org/x/crypto/sha3"
"github.com/dexon-foundation/dexon/common"
"github.com/dexon-foundation/dexon/core/state"
"github.com/dexon-foundation/dexon/core/vm/sqlvm/ast"
"github.com/dexon-foundation/dexon/core/vm/sqlvm/schema"
"github.com/dexon-foundation/dexon/crypto"
"github.com/dexon-foundation/dexon/rlp"
)
// Storage holds SQLVM required data and method.
type Storage struct {
state.StateDB
Schema schema.Schema
}
// NewStorage return Storage instance.
func NewStorage(state *state.StateDB) Storage {
s := Storage{*state, schema.Schema{}}
return s
}
func convertIDtoBytes(id uint64) []byte {
bigIntID := new(big.Int).SetUint64(id)
decimalID := decimal.NewFromBigInt(bigIntID, 0)
dt := ast.ComposeDataType(ast.DataTypeMajorUint, 7)
byteID, _ := ast.DecimalEncode(dt, decimalID)
return byteID
}
// GetPrimaryKeyHash return primary key hash.
func (s Storage) GetPrimaryKeyHash(tableName []byte, id uint64) (h common.Hash) {
key := [][]byte{
[]byte("tables"),
tableName,
[]byte("primary"),
convertIDtoBytes(id),
}
hw := sha3.NewLegacyKeccak256()
rlp.Encode(hw, key)
// length of common.Hash is 256bit,
// so it can properly match the size of hw.Sum
hw.Sum(h[:0])
return
}
// ShiftHashUint64 shift hash in uint64.
func (s Storage) ShiftHashUint64(hash common.Hash, shift uint64) common.Hash {
bigIntOffset := new(big.Int)
bigIntOffset.SetUint64(shift)
return s.ShiftHashBigInt(hash, bigIntOffset)
}
// ShiftHashBigInt shift hash in big.Int
func (s Storage) ShiftHashBigInt(hash common.Hash, shift *big.Int) common.Hash {
head := hash.Big()
head.Add(head, shift)
return common.BytesToHash(head.Bytes())
}
func getDByteSize(data common.Hash) uint64 {
bytes := data.Bytes()
lastByte := bytes[len(bytes)-1]
if lastByte&0x1 == 0 {
return uint64(lastByte / 2)
}
return new(big.Int).Div(new(big.Int).Sub(
data.Big(), big.NewInt(1)), big.NewInt(2)).Uint64()
}
// DecodeDByteBySlot given contract address and slot return the dynamic bytes data.
func (s Storage) DecodeDByteBySlot(address common.Address, slot common.Hash) []byte {
data := s.GetState(address, slot)
length := getDByteSize(data)
if length < common.HashLength {
return data[:length]
}
ptr := crypto.Keccak256Hash(slot.Bytes())
slotNum := (length-1)/common.HashLength + 1
rVal := make([]byte, slotNum*common.HashLength)
for i := uint64(0); i < slotNum; i++ {
start := i * common.HashLength
copy(rVal[start:start+common.HashLength], s.GetState(address, ptr).Bytes())
ptr = s.ShiftHashUint64(ptr, 1)
}
return rVal[:length]
}
|