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  }