aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/sqlvm/common/storage_rw.go
blob: 1ac16c746e412efdf551cb98364bcc2a3a14b3a1 (plain) (blame)
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
}