github.com/iotexproject/iotex-core@v1.14.1-rc1/action/rlp_tx.go (about) 1 package action 2 3 import ( 4 "encoding/hex" 5 "math/big" 6 "strings" 7 8 "github.com/ethereum/go-ethereum/core/types" 9 "github.com/ethereum/go-ethereum/rlp" 10 "github.com/iotexproject/go-pkgs/crypto" 11 "github.com/iotexproject/go-pkgs/hash" 12 "github.com/iotexproject/iotex-proto/golang/iotextypes" 13 "github.com/pkg/errors" 14 ) 15 16 func rlpRawHash(rawTx *types.Transaction, signer types.Signer) (hash.Hash256, error) { 17 h := signer.Hash(rawTx) 18 return hash.BytesToHash256(h[:]), nil 19 } 20 21 func rlpSignedHash(tx *types.Transaction, signer types.Signer, sig []byte) (hash.Hash256, error) { 22 signedTx, err := RawTxToSignedTx(tx, signer, sig) 23 if err != nil { 24 return hash.ZeroHash256, err 25 } 26 h := signedTx.Hash() 27 return hash.BytesToHash256(h[:]), nil 28 } 29 30 // RawTxToSignedTx converts the raw tx to corresponding signed tx 31 func RawTxToSignedTx(rawTx *types.Transaction, signer types.Signer, sig []byte) (*types.Transaction, error) { 32 if len(sig) != 65 { 33 return nil, errors.Errorf("invalid signature length = %d, expecting 65", len(sig)) 34 } 35 sc := make([]byte, 65) 36 copy(sc, sig) 37 if sc[64] >= 27 { 38 sc[64] -= 27 39 } 40 41 signedTx, err := rawTx.WithSignature(signer, sc) 42 if err != nil { 43 return nil, err 44 } 45 return signedTx, nil 46 } 47 48 // DecodeRawTx decodes raw data string into eth tx 49 func DecodeRawTx(rawData string, chainID uint32) (tx *types.Transaction, sig []byte, pubkey crypto.PublicKey, err error) { 50 //remove Hex prefix and decode string to byte 51 rawData = strings.Replace(rawData, "0x", "", -1) 52 rawData = strings.Replace(rawData, "0X", "", -1) 53 var dataInString []byte 54 dataInString, err = hex.DecodeString(rawData) 55 if err != nil { 56 return 57 } 58 59 // decode raw data into rlp tx 60 tx = &types.Transaction{} 61 err = rlp.DecodeBytes(dataInString, tx) 62 if err != nil { 63 return 64 } 65 66 // extract signature and recover pubkey 67 v, r, s := tx.RawSignatureValues() 68 recID := uint32(v.Int64()) - 2*chainID - 8 69 sig = make([]byte, 65) 70 rSize := len(r.Bytes()) 71 copy(sig[32-rSize:32], r.Bytes()) 72 sSize := len(s.Bytes()) 73 copy(sig[64-sSize:], s.Bytes()) 74 sig[64] = byte(recID) 75 76 // recover public key 77 rawHash := types.NewEIP155Signer(big.NewInt(int64(chainID))).Hash(tx) 78 pubkey, err = crypto.RecoverPubkey(rawHash[:], sig) 79 return 80 } 81 82 // NewEthSigner returns the proper signer for Eth-compatible tx 83 func NewEthSigner(txType iotextypes.Encoding, chainID uint32) (types.Signer, error) { 84 switch txType { 85 case iotextypes.Encoding_IOTEX_PROTOBUF, iotextypes.Encoding_ETHEREUM_UNPROTECTED: 86 // native tx use same signature format as that of Homestead (for pre-EIP155 unprotected tx) 87 return types.HomesteadSigner{}, nil 88 case iotextypes.Encoding_ETHEREUM_EIP155: 89 return types.NewEIP2930Signer(big.NewInt(int64(chainID))), nil 90 default: 91 return nil, ErrInvalidAct 92 } 93 } 94 95 // DecodeEtherTx decodes raw data string into eth tx 96 func DecodeEtherTx(rawData string) (*types.Transaction, error) { 97 //remove Hex prefix and decode string to byte 98 if strings.HasPrefix(rawData, "0x") || strings.HasPrefix(rawData, "0X") { 99 rawData = rawData[2:] 100 } 101 rawTxBytes, err := hex.DecodeString(rawData) 102 if err != nil { 103 return nil, err 104 } 105 106 // decode raw data into eth tx 107 tx := types.Transaction{} 108 if err = tx.UnmarshalBinary(rawTxBytes); err != nil { 109 return nil, err 110 } 111 return &tx, nil 112 } 113 114 // ExtractTypeSigPubkey extracts tx type, signature, and pubkey 115 func ExtractTypeSigPubkey(tx *types.Transaction) (iotextypes.Encoding, []byte, crypto.PublicKey, error) { 116 var ( 117 encoding iotextypes.Encoding 118 signer = types.NewEIP2930Signer(tx.ChainId()) // by default assume latest signer 119 V, R, S = tx.RawSignatureValues() 120 ) 121 // extract correct V value 122 switch tx.Type() { 123 case types.LegacyTxType: 124 if tx.Protected() { 125 chainIDMul := tx.ChainId() 126 V = new(big.Int).Sub(V, new(big.Int).Lsh(chainIDMul, 1)) 127 V.Sub(V, big.NewInt(8)) 128 encoding = iotextypes.Encoding_ETHEREUM_EIP155 129 } else { 130 // tx has pre-EIP155 signature 131 encoding = iotextypes.Encoding_ETHEREUM_UNPROTECTED 132 signer = types.HomesteadSigner{} 133 } 134 default: 135 return encoding, nil, nil, ErrNotSupported 136 } 137 138 // construct signature 139 if V.BitLen() > 8 { 140 return encoding, nil, nil, ErrNotSupported 141 } 142 143 var ( 144 r, s = R.Bytes(), S.Bytes() 145 sig = make([]byte, 65) 146 pubkey crypto.PublicKey 147 err error 148 ) 149 copy(sig[32-len(r):32], r) 150 copy(sig[64-len(s):64], s) 151 sig[64] = byte(V.Uint64()) 152 153 // recover public key 154 rawHash := signer.Hash(tx) 155 pubkey, err = crypto.RecoverPubkey(rawHash[:], sig) 156 return encoding, sig, pubkey, err 157 }