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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
package common
import (
"io"
"github.com/dexon-foundation/dexon/common"
)
// StorageReader implements io.Reader on Storage.
// Notice that we have cache in Reader, so it become invalid after any writes
// to Storage or StateDB.
type StorageReader struct {
storage *Storage
contract common.Address
cursor common.Hash
buffer []byte
}
// assert io.Reader interface is implemented.
var _ io.Reader = (*StorageReader)(nil)
// NewStorageReader create a Reader on Storage.
func NewStorageReader(
storage *Storage,
contract common.Address,
startPos common.Hash,
) *StorageReader {
return &StorageReader{
storage: storage,
contract: contract,
cursor: startPos,
}
}
// Read implements the function defined in io.Reader interface.
func (r *StorageReader) Read(p []byte) (n int, err error) {
copyBuffer := func() {
lenCopy := len(p)
if lenCopy > len(r.buffer) {
lenCopy = len(r.buffer)
}
copy(p[:lenCopy], r.buffer[:lenCopy])
p = p[lenCopy:]
r.buffer = r.buffer[lenCopy:]
n += lenCopy
}
// Flush old buffer first.
copyBuffer()
for len(p) > 0 {
// Read slot by slot.
r.buffer = r.storage.GetState(r.contract, r.cursor).Bytes()
r.cursor = r.storage.ShiftHashUint64(r.cursor, 1)
copyBuffer()
}
return
}
// StorageWriter implements io.Writer on Storage.
type StorageWriter struct {
storage *Storage
contract common.Address
cursor common.Hash
byteShift int // bytes already written in last slot. value: 0 ~ 31
}
// assert io.Writer interface is implemented.
var _ io.Writer = (*StorageWriter)(nil)
// NewStorageWriter create a Writer on Storage.
func NewStorageWriter(
storage *Storage,
contract common.Address,
startPos common.Hash,
) *StorageWriter {
return &StorageWriter{
storage: storage,
contract: contract,
cursor: startPos,
}
}
// Write implements the function defined in io.Writer interface.
func (w *StorageWriter) Write(p []byte) (n int, err error) {
var payload common.Hash
for len(p) > 0 {
// Setup common.Hash to write.
remain := common.HashLength - w.byteShift
lenCopy := remain
if lenCopy > len(p) {
lenCopy = len(p)
}
if lenCopy != common.HashLength {
// Not writing an entire slot, need load first.
payload = w.storage.GetState(w.contract, w.cursor)
}
b := payload.Bytes()
start := w.byteShift
end := w.byteShift + lenCopy
copy(b[start:end], p[:lenCopy])
payload.SetBytes(b)
w.storage.SetState(w.contract, w.cursor, payload)
// Update state.
p = p[lenCopy:]
n += lenCopy
w.byteShift += lenCopy
if w.byteShift == common.HashLength {
w.byteShift = 0
w.cursor = w.storage.ShiftHashUint64(w.cursor, 1)
}
}
return
}
|