github.com/iotexproject/iotex-core@v1.14.1-rc1/action/sealedenvelope.go (about) 1 package action 2 3 import ( 4 "encoding/hex" 5 6 "github.com/iotexproject/go-pkgs/crypto" 7 "github.com/iotexproject/go-pkgs/hash" 8 "github.com/iotexproject/iotex-address/address" 9 "github.com/iotexproject/iotex-proto/golang/iotextypes" 10 "github.com/pkg/errors" 11 "go.uber.org/zap" 12 "google.golang.org/protobuf/proto" 13 14 "github.com/iotexproject/iotex-core/pkg/log" 15 "github.com/iotexproject/iotex-core/pkg/util/byteutil" 16 ) 17 18 // SealedEnvelope is a signed action envelope. 19 type SealedEnvelope struct { 20 Envelope 21 encoding iotextypes.Encoding 22 evmNetworkID uint32 23 srcPubkey crypto.PublicKey 24 signature []byte 25 srcAddress address.Address 26 hash hash.Hash256 27 } 28 29 // envelopeHash returns the raw hash of embedded Envelope (this is the hash to be signed) 30 // an all-0 return value means the transaction is invalid 31 func (sealed *SealedEnvelope) envelopeHash() (hash.Hash256, error) { 32 switch sealed.encoding { 33 case iotextypes.Encoding_ETHEREUM_EIP155, iotextypes.Encoding_ETHEREUM_UNPROTECTED: 34 act, ok := sealed.Action().(EthCompatibleAction) 35 if !ok { 36 return hash.ZeroHash256, ErrInvalidAct 37 } 38 tx, err := act.ToEthTx(sealed.evmNetworkID) 39 if err != nil { 40 return hash.ZeroHash256, err 41 } 42 signer, err := NewEthSigner(sealed.encoding, sealed.evmNetworkID) 43 if err != nil { 44 return hash.ZeroHash256, err 45 } 46 return rlpRawHash(tx, signer) 47 case iotextypes.Encoding_IOTEX_PROTOBUF: 48 return hash.Hash256b(byteutil.Must(proto.Marshal(sealed.Envelope.Proto()))), nil 49 default: 50 return hash.ZeroHash256, errors.Errorf("unknown encoding type %v", sealed.encoding) 51 } 52 } 53 54 // Hash returns the hash value of SealedEnvelope. 55 // an all-0 return value means the transaction is invalid 56 func (sealed *SealedEnvelope) Hash() (hash.Hash256, error) { 57 if sealed.hash == hash.ZeroHash256 { 58 hashVal, hashErr := sealed.calcHash() 59 if hashErr == nil { 60 sealed.hash = hashVal 61 } 62 return sealed.hash, hashErr 63 } 64 return sealed.hash, nil 65 } 66 67 func (sealed *SealedEnvelope) calcHash() (hash.Hash256, error) { 68 switch sealed.encoding { 69 case iotextypes.Encoding_ETHEREUM_EIP155, iotextypes.Encoding_ETHEREUM_UNPROTECTED: 70 act, ok := sealed.Action().(EthCompatibleAction) 71 if !ok { 72 return hash.ZeroHash256, ErrInvalidAct 73 } 74 tx, err := act.ToEthTx(sealed.evmNetworkID) 75 if err != nil { 76 return hash.ZeroHash256, err 77 } 78 signer, err := NewEthSigner(sealed.encoding, sealed.evmNetworkID) 79 if err != nil { 80 return hash.ZeroHash256, err 81 } 82 return rlpSignedHash(tx, signer, sealed.Signature()) 83 case iotextypes.Encoding_IOTEX_PROTOBUF: 84 return hash.Hash256b(byteutil.Must(proto.Marshal(sealed.Proto()))), nil 85 default: 86 return hash.ZeroHash256, errors.Errorf("unknown encoding type %v", sealed.encoding) 87 } 88 } 89 90 // SrcPubkey returns the source public key 91 func (sealed *SealedEnvelope) SrcPubkey() crypto.PublicKey { return sealed.srcPubkey } 92 93 // SenderAddress returns address of the source public key 94 func (sealed *SealedEnvelope) SenderAddress() address.Address { 95 if sealed.srcAddress == nil { 96 sealed.srcAddress = sealed.srcPubkey.Address() 97 } 98 return sealed.srcAddress 99 } 100 101 // Signature returns signature bytes 102 func (sealed *SealedEnvelope) Signature() []byte { 103 sig := make([]byte, len(sealed.signature)) 104 copy(sig, sealed.signature) 105 return sig 106 } 107 108 // Encoding returns the encoding 109 func (sealed *SealedEnvelope) Encoding() uint32 { 110 return uint32(sealed.encoding) 111 } 112 113 // Proto converts it to it's proto scheme. 114 func (sealed *SealedEnvelope) Proto() *iotextypes.Action { 115 return &iotextypes.Action{ 116 Core: sealed.Envelope.Proto(), 117 SenderPubKey: sealed.srcPubkey.Bytes(), 118 Signature: sealed.signature, 119 Encoding: sealed.encoding, 120 } 121 } 122 123 // loadProto loads from proto scheme. 124 func (sealed *SealedEnvelope) loadProto(pbAct *iotextypes.Action, evmID uint32) error { 125 if pbAct == nil { 126 return ErrNilProto 127 } 128 if sealed == nil { 129 return ErrNilAction 130 } 131 sigSize := len(pbAct.GetSignature()) 132 if sigSize != 65 { 133 return errors.Errorf("invalid signature length = %d, expecting 65", sigSize) 134 } 135 136 var elp Envelope = &envelope{} 137 if err := elp.LoadProto(pbAct.GetCore()); err != nil { 138 return err 139 } 140 // populate pubkey and signature 141 srcPub, err := crypto.BytesToPublicKey(pbAct.GetSenderPubKey()) 142 if err != nil { 143 return err 144 } 145 encoding := pbAct.GetEncoding() 146 switch encoding { 147 case iotextypes.Encoding_ETHEREUM_EIP155, iotextypes.Encoding_ETHEREUM_UNPROTECTED: 148 // verify action type can support RLP-encoding 149 act, ok := elp.Action().(EthCompatibleAction) 150 if !ok { 151 return ErrInvalidAct 152 } 153 tx, err := act.ToEthTx(evmID) 154 if err != nil { 155 return err 156 } 157 signer, err := NewEthSigner(encoding, evmID) 158 if err != nil { 159 return err 160 } 161 if _, err = rlpSignedHash(tx, signer, pbAct.GetSignature()); err != nil { 162 return err 163 } 164 sealed.evmNetworkID = evmID 165 case iotextypes.Encoding_IOTEX_PROTOBUF: 166 break 167 default: 168 return errors.Errorf("unknown encoding type %v", encoding) 169 } 170 171 // clear 'sealed' and populate new value 172 sealed.Envelope = elp 173 sealed.srcPubkey = srcPub 174 sealed.signature = make([]byte, sigSize) 175 copy(sealed.signature, pbAct.GetSignature()) 176 sealed.encoding = encoding 177 sealed.hash = hash.ZeroHash256 178 sealed.srcAddress = nil 179 return nil 180 } 181 182 // VerifySignature verifies the action using sender's public key 183 func (sealed *SealedEnvelope) VerifySignature() error { 184 if sealed.SrcPubkey() == nil { 185 return errors.New("empty public key") 186 } 187 h, err := sealed.envelopeHash() 188 if err != nil { 189 return errors.Wrap(err, "failed to generate envelope hash") 190 } 191 if !sealed.SrcPubkey().Verify(h[:], sealed.Signature()) { 192 log.L().Info("failed to verify action hash", 193 zap.String("hash", hex.EncodeToString(h[:])), 194 zap.String("signature", hex.EncodeToString(sealed.Signature()))) 195 return ErrInvalidSender 196 } 197 return nil 198 }