github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/whisper/whisperv6/envelope.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:46</date>
    10  //</624450125246238720>
    11  
    12  
    13  //包含Whisper协议信封元素。
    14  
    15  package whisperv6
    16  
    17  import (
    18  	"crypto/ecdsa"
    19  	"encoding/binary"
    20  	"fmt"
    21  	gmath "math"
    22  	"math/big"
    23  	"time"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/common/math"
    27  	"github.com/ethereum/go-ethereum/crypto"
    28  	"github.com/ethereum/go-ethereum/crypto/ecies"
    29  	"github.com/ethereum/go-ethereum/rlp"
    30  )
    31  
    32  //信封表示一个明文数据包,通过耳语进行传输。
    33  //网络。其内容可以加密或不加密和签名。
    34  type Envelope struct {
    35  	Expiry uint32
    36  	TTL    uint32
    37  	Topic  TopicType
    38  	Data   []byte
    39  	Nonce  uint64
    40  
    41  pow float64 //消息特定的POW,如Whisper规范中所述。
    42  
    43  //不应直接访问以下变量,请改用相应的函数:hash()、bloom()。
    44  hash  common.Hash //信封的缓存哈希,以避免每次重新刷新。
    45  	bloom []byte
    46  }
    47  
    48  //大小返回信封发送时的大小(即仅公共字段)
    49  func (e *Envelope) size() int {
    50  	return EnvelopeHeaderLength + len(e.Data)
    51  }
    52  
    53  //rlpwithoutnonce返回rlp编码的信封内容,nonce除外。
    54  func (e *Envelope) rlpWithoutNonce() []byte {
    55  	res, _ := rlp.EncodeToBytes([]interface{}{e.Expiry, e.TTL, e.Topic, e.Data})
    56  	return res
    57  }
    58  
    59  //newenvelope用过期和目标数据包装了一条私语消息
    60  //包含在信封中,用于网络转发。
    61  func NewEnvelope(ttl uint32, topic TopicType, msg *sentMessage) *Envelope {
    62  	env := Envelope{
    63  		Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()),
    64  		TTL:    ttl,
    65  		Topic:  topic,
    66  		Data:   msg.Raw,
    67  		Nonce:  0,
    68  	}
    69  
    70  	return &env
    71  }
    72  
    73  //Seal通过花费所需的时间作为证据来关闭信封
    74  //关于散列数据的工作。
    75  func (e *Envelope) Seal(options *MessageParams) error {
    76  	if options.PoW == 0 {
    77  //不需要POW
    78  		return nil
    79  	}
    80  
    81  	var target, bestBit int
    82  	if options.PoW < 0 {
    83  //未设置目标-函数应运行一段时间
    84  //工作时间参数中指定的时间。因为我们可以预测
    85  //执行时间,我们也可以调整到期时间。
    86  		e.Expiry += options.WorkTime
    87  	} else {
    88  		target = e.powToFirstBit(options.PoW)
    89  	}
    90  
    91  	buf := make([]byte, 64)
    92  	h := crypto.Keccak256(e.rlpWithoutNonce())
    93  	copy(buf[:32], h)
    94  
    95  	finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano()
    96  	for nonce := uint64(0); time.Now().UnixNano() < finish; {
    97  		for i := 0; i < 1024; i++ {
    98  			binary.BigEndian.PutUint64(buf[56:], nonce)
    99  			d := new(big.Int).SetBytes(crypto.Keccak256(buf))
   100  			firstBit := math.FirstBitSet(d)
   101  			if firstBit > bestBit {
   102  				e.Nonce, bestBit = nonce, firstBit
   103  				if target > 0 && bestBit >= target {
   104  					return nil
   105  				}
   106  			}
   107  			nonce++
   108  		}
   109  	}
   110  
   111  	if target > 0 && bestBit < target {
   112  		return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime)
   113  	}
   114  
   115  	return nil
   116  }
   117  
   118  //POW计算(如有必要)并返回工作证明目标
   119  //信封的。
   120  func (e *Envelope) PoW() float64 {
   121  	if e.pow == 0 {
   122  		e.calculatePoW(0)
   123  	}
   124  	return e.pow
   125  }
   126  
   127  func (e *Envelope) calculatePoW(diff uint32) {
   128  	buf := make([]byte, 64)
   129  	h := crypto.Keccak256(e.rlpWithoutNonce())
   130  	copy(buf[:32], h)
   131  	binary.BigEndian.PutUint64(buf[56:], e.Nonce)
   132  	d := new(big.Int).SetBytes(crypto.Keccak256(buf))
   133  	firstBit := math.FirstBitSet(d)
   134  	x := gmath.Pow(2, float64(firstBit))
   135  	x /= float64(e.size())
   136  	x /= float64(e.TTL + diff)
   137  	e.pow = x
   138  }
   139  
   140  func (e *Envelope) powToFirstBit(pow float64) int {
   141  	x := pow
   142  	x *= float64(e.size())
   143  	x *= float64(e.TTL)
   144  	bits := gmath.Log2(x)
   145  	bits = gmath.Ceil(bits)
   146  	res := int(bits)
   147  	if res < 1 {
   148  		res = 1
   149  	}
   150  	return res
   151  }
   152  
   153  //hash返回信封的sha3散列,如果还没有完成,则计算它。
   154  func (e *Envelope) Hash() common.Hash {
   155  	if (e.hash == common.Hash{}) {
   156  		encoded, _ := rlp.EncodeToBytes(e)
   157  		e.hash = crypto.Keccak256Hash(encoded)
   158  	}
   159  	return e.hash
   160  }
   161  
   162  //decoderlp从rlp数据流解码信封。
   163  func (e *Envelope) DecodeRLP(s *rlp.Stream) error {
   164  	raw, err := s.Raw()
   165  	if err != nil {
   166  		return err
   167  	}
   168  //信封的解码使用结构字段,但也需要
   169  //计算整个RLP编码信封的散列值。这个
   170  //类型具有与信封相同的结构,但不是
   171  //rlp.decoder(不实现decoderlp函数)。
   172  //只对公共成员进行编码。
   173  	type rlpenv Envelope
   174  	if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil {
   175  		return err
   176  	}
   177  	e.hash = crypto.Keccak256Hash(raw)
   178  	return nil
   179  }
   180  
   181  //OpenAsymmetric试图解密一个信封,可能用一个特定的密钥加密。
   182  func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) {
   183  	message := &ReceivedMessage{Raw: e.Data}
   184  	err := message.decryptAsymmetric(key)
   185  	switch err {
   186  	case nil:
   187  		return message, nil
   188  case ecies.ErrInvalidPublicKey: //写给别人的
   189  		return nil, err
   190  	default:
   191  		return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err)
   192  	}
   193  }
   194  
   195  //opensymmetric试图解密一个可能用特定密钥加密的信封。
   196  func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) {
   197  	msg = &ReceivedMessage{Raw: e.Data}
   198  	err = msg.decryptSymmetric(key)
   199  	if err != nil {
   200  		msg = nil
   201  	}
   202  	return msg, err
   203  }
   204  
   205  //open试图解密信封,并在成功时填充消息字段。
   206  func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) {
   207  	if watcher == nil {
   208  		return nil
   209  	}
   210  
   211  //API接口禁止过滤器同时进行对称和非对称加密。
   212  	if watcher.expectsAsymmetricEncryption() && watcher.expectsSymmetricEncryption() {
   213  		return nil
   214  	}
   215  
   216  	if watcher.expectsAsymmetricEncryption() {
   217  		msg, _ = e.OpenAsymmetric(watcher.KeyAsym)
   218  		if msg != nil {
   219  			msg.Dst = &watcher.KeyAsym.PublicKey
   220  		}
   221  	} else if watcher.expectsSymmetricEncryption() {
   222  		msg, _ = e.OpenSymmetric(watcher.KeySym)
   223  		if msg != nil {
   224  			msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym)
   225  		}
   226  	}
   227  
   228  	if msg != nil {
   229  		ok := msg.ValidateAndParse()
   230  		if !ok {
   231  			return nil
   232  		}
   233  		msg.Topic = e.Topic
   234  		msg.PoW = e.PoW()
   235  		msg.TTL = e.TTL
   236  		msg.Sent = e.Expiry - e.TTL
   237  		msg.EnvelopeHash = e.Hash()
   238  	}
   239  	return msg
   240  }
   241  
   242  //Bloom将4字节主题映射到64字节的Bloom过滤器中,并设置了3位(最多)。
   243  func (e *Envelope) Bloom() []byte {
   244  	if e.bloom == nil {
   245  		e.bloom = TopicToBloom(e.Topic)
   246  	}
   247  	return e.bloom
   248  }
   249  
   250  //TopicToBloom将主题(4字节)转换为Bloom筛选器(64字节)
   251  func TopicToBloom(topic TopicType) []byte {
   252  	b := make([]byte, BloomFilterSize)
   253  	var index [3]int
   254  	for j := 0; j < 3; j++ {
   255  		index[j] = int(topic[j])
   256  		if (topic[3] & (1 << uint(j))) != 0 {
   257  			index[j] += 256
   258  		}
   259  	}
   260  
   261  	for j := 0; j < 3; j++ {
   262  		byteIndex := index[j] / 8
   263  		bitIndex := index[j] % 8
   264  		b[byteIndex] = (1 << uint(bitIndex))
   265  	}
   266  	return b
   267  }
   268  
   269  //GetEnvelope通过其哈希从消息队列中检索信封。
   270  //如果找不到信封,则返回零。
   271  func (w *Whisper) GetEnvelope(hash common.Hash) *Envelope {
   272  	w.poolMu.RLock()
   273  	defer w.poolMu.RUnlock()
   274  	return w.envelopes[hash]
   275  }
   276