forked from gitter-badger/go-vnt
/
compress.go
173 lines (151 loc) · 4.3 KB
/
compress.go
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// Copyright 2019 The go-vnt Authors
// This file is part of the go-vnt library.
//
// The go-vnt library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-vnt library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-vnt library. If not, see <http://www.gnu.org/licenses/>.
package utils
import (
"bytes"
"compress/gzip"
"compress/zlib"
"encoding/binary"
"io"
"io/ioutil"
"time"
"github.com/vntchain/go-vnt/common"
"github.com/vntchain/go-vnt/core/wavm/contract"
"github.com/vntchain/go-vnt/log"
"github.com/vntchain/go-vnt/rlp"
)
const (
HEADERLEN int = 6
MAGIC uint32 = 0x6d736101
MagicBase64 uint32 = 0x7a464741
ZLIBUTIL uint16 = 0x01
GZIPUTIL uint16 = 0x02
)
func Compress(src []byte) []byte {
log.Debug("before compress", "code length", len(src))
defer func(start time.Time) { log.Debug("Compress finished", "runtime", time.Since(start)) }(time.Now())
// now only support zlib compression
dst := compressZlib(src)
log.Debug("after compress", "compressed len", len(dst), "src length", len(src))
// have a check if the compress is worth it
isCompressed := len(dst)+HEADERLEN < len(src)
// if compress is ok, add the header in front of the code
if isCompressed {
compressType := make([]byte, 2)
binary.LittleEndian.PutUint16(compressType, ZLIBUTIL)
dst = append(compressType, dst...)
return dst
}
log.Debug("after compress", "code length", len(src))
// if not compressed, return the raw bytes
return src
}
func DeCompress(src []byte) ([]byte, error) {
defer func(start time.Time) { log.Debug("DeCompress finished", "runtime", time.Since(start)) }(time.Now())
if len(src) == 0 {
return src, nil
}
log.Debug("before decompress", "code length", len(src))
compressType, err := readCompressType(src)
if err != nil {
return nil, err
}
log.Debug("during decompress", "compressType", compressType)
// get rid of the compress type bytes
src = src[2:]
var dst []byte
switch compressType {
case ZLIBUTIL:
dst, err = deZlib(src)
case GZIPUTIL:
dst, err = deGzip(src)
default:
dst, err = src, nil
}
// log.Debug("after decompress", "decompressed code", dst, "err", err)
log.Debug("after decompress", "decompressed length", len(dst), "src length", len(src))
return dst, err
}
func compressZlib(src []byte) []byte {
var b bytes.Buffer
w := zlib.NewWriter(&b)
defer w.Close()
w.Write(src)
w.Flush()
dst := b.Bytes()
return dst
}
func CompressZlib(src []byte) []byte {
return compressZlib(src)
}
func deZlib(src []byte) (dst []byte, err error) {
var out bytes.Buffer
b := bytes.NewReader(src)
r, err := zlib.NewReader(b)
if err != nil {
return nil, err
}
defer r.Close()
io.Copy(&out, r)
return out.Bytes(), nil
}
func deGzip(src []byte) (dst []byte, err error) {
b := bytes.NewReader(src)
r, _ := gzip.NewReader(b)
defer r.Close()
dst, err = ioutil.ReadAll(r)
return
}
func ReadMagic(src []byte) (uint32, error) {
r := bytes.NewBuffer(src)
var buf [4]byte
_, err := io.ReadFull(r, buf[:])
if err != nil {
return 0, err
}
log.Debug("read magic", "magic", common.ToHex(buf[:]))
return binary.LittleEndian.Uint32(buf[:]), nil
}
func readCompressType(src []byte) (uint16, error) {
r := bytes.NewBuffer(src)
var buf [2]byte
_, err := io.ReadFull(r, buf[:])
if err != nil {
return 0, err
}
log.Debug("read CompressType", "CompressType", common.ToHex(buf[:]))
return binary.LittleEndian.Uint16(buf[:]), nil
}
//将abi和wasm压缩后进行rlp编码
func CompressWasmAndAbi(abijson, wasm, compiled []byte) []byte {
wasmcode := contract.WasmCode{
Code: wasm,
Abi: abijson,
Compiled: compiled,
}
res, err := rlp.EncodeToBytes(wasmcode)
if err != nil {
panic(err)
}
rlpcps := Compress(res)
cpsres, err := rlp.EncodeToBytes(rlpcps)
if err != nil {
panic(err)
}
magic := make([]byte, 4)
binary.LittleEndian.PutUint32(magic, MAGIC)
return append(magic, cpsres...)
}