github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/core/wavm/utils/compress.go (about) 1 // Copyright 2019 The go-vnt Authors 2 // This file is part of the go-vnt library. 3 // 4 // The go-vnt library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-vnt library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-vnt library. If not, see <http://www.gnu.org/licenses/>. 16 17 package utils 18 19 import ( 20 "bytes" 21 "compress/gzip" 22 "compress/zlib" 23 "encoding/binary" 24 "io" 25 "io/ioutil" 26 "time" 27 28 "github.com/vntchain/go-vnt/common" 29 "github.com/vntchain/go-vnt/core/wavm/contract" 30 "github.com/vntchain/go-vnt/log" 31 "github.com/vntchain/go-vnt/rlp" 32 ) 33 34 const ( 35 HEADERLEN int = 6 36 MAGIC uint32 = 0x6d736101 37 MagicBase64 uint32 = 0x7a464741 38 ZLIBUTIL uint16 = 0x01 39 GZIPUTIL uint16 = 0x02 40 ) 41 42 func Compress(src []byte) []byte { 43 log.Debug("before compress", "code length", len(src)) 44 defer func(start time.Time) { log.Debug("Compress finished", "runtime", time.Since(start)) }(time.Now()) 45 // now only support zlib compression 46 dst := compressZlib(src) 47 log.Debug("after compress", "compressed len", len(dst), "src length", len(src)) 48 49 // have a check if the compress is worth it 50 isCompressed := len(dst)+HEADERLEN < len(src) 51 52 // if compress is ok, add the header in front of the code 53 if isCompressed { 54 compressType := make([]byte, 2) 55 binary.LittleEndian.PutUint16(compressType, ZLIBUTIL) 56 dst = append(compressType, dst...) 57 return dst 58 } 59 60 log.Debug("after compress", "code length", len(src)) 61 // if not compressed, return the raw bytes 62 return src 63 } 64 65 func DeCompress(src []byte) ([]byte, error) { 66 defer func(start time.Time) { log.Debug("DeCompress finished", "runtime", time.Since(start)) }(time.Now()) 67 if len(src) == 0 { 68 return src, nil 69 } 70 71 log.Debug("before decompress", "code length", len(src)) 72 73 compressType, err := readCompressType(src) 74 if err != nil { 75 return nil, err 76 } 77 78 log.Debug("during decompress", "compressType", compressType) 79 // get rid of the compress type bytes 80 src = src[2:] 81 var dst []byte 82 switch compressType { 83 case ZLIBUTIL: 84 dst, err = deZlib(src) 85 case GZIPUTIL: 86 dst, err = deGzip(src) 87 default: 88 dst, err = src, nil 89 } 90 91 // log.Debug("after decompress", "decompressed code", dst, "err", err) 92 log.Debug("after decompress", "decompressed length", len(dst), "src length", len(src)) 93 return dst, err 94 } 95 96 func compressZlib(src []byte) []byte { 97 var b bytes.Buffer 98 w := zlib.NewWriter(&b) 99 defer w.Close() 100 101 w.Write(src) 102 w.Flush() 103 dst := b.Bytes() 104 return dst 105 } 106 107 func CompressZlib(src []byte) []byte { 108 return compressZlib(src) 109 } 110 111 func deZlib(src []byte) (dst []byte, err error) { 112 var out bytes.Buffer 113 b := bytes.NewReader(src) 114 r, err := zlib.NewReader(b) 115 if err != nil { 116 return nil, err 117 } 118 defer r.Close() 119 io.Copy(&out, r) 120 return out.Bytes(), nil 121 } 122 123 func deGzip(src []byte) (dst []byte, err error) { 124 b := bytes.NewReader(src) 125 r, _ := gzip.NewReader(b) 126 defer r.Close() 127 128 dst, err = ioutil.ReadAll(r) 129 return 130 } 131 132 func ReadMagic(src []byte) (uint32, error) { 133 r := bytes.NewBuffer(src) 134 var buf [4]byte 135 _, err := io.ReadFull(r, buf[:]) 136 if err != nil { 137 return 0, err 138 } 139 log.Debug("read magic", "magic", common.ToHex(buf[:])) 140 return binary.LittleEndian.Uint32(buf[:]), nil 141 } 142 143 func readCompressType(src []byte) (uint16, error) { 144 r := bytes.NewBuffer(src) 145 var buf [2]byte 146 _, err := io.ReadFull(r, buf[:]) 147 if err != nil { 148 return 0, err 149 } 150 log.Debug("read CompressType", "CompressType", common.ToHex(buf[:])) 151 return binary.LittleEndian.Uint16(buf[:]), nil 152 } 153 154 //将abi和wasm压缩后进行rlp编码 155 func CompressWasmAndAbi(abijson, wasm, compiled []byte) []byte { 156 wasmcode := contract.WasmCode{ 157 Code: wasm, 158 Abi: abijson, 159 Compiled: compiled, 160 } 161 res, err := rlp.EncodeToBytes(wasmcode) 162 if err != nil { 163 panic(err) 164 } 165 rlpcps := Compress(res) 166 cpsres, err := rlp.EncodeToBytes(rlpcps) 167 if err != nil { 168 panic(err) 169 } 170 magic := make([]byte, 4) 171 binary.LittleEndian.PutUint32(magic, MAGIC) 172 return append(magic, cpsres...) 173 }