// Bitcoin specific type checking func isClassA(tx *btcutil.Tx) bool { mtx := tx.MsgTx() for _, txOut := range mtx.TxOut { _, scriptType := mscutil.GetAddrs(txOut.PkScript) if scriptType == btcscript.MultiSigTy { return false } } // If it wasn't multi sig it's class a return true }
// Parse transaction takes care of testing the tx for certain rules; class A/B checking // Fundraiser checks and Dex messages as well as properly delegating the raw messages to // the proper object which. After a full Msg has been assembled it will return the Msg // or an error with a description. Whoever called this function should delegate the msg // to the proper object handler. func (mp *MsgParser) ParseTx(tx *btcutil.Tx, height, time int64) (msgs []*Msg, err error) { sender, _ := mscutil.FindSender(tx.MsgTx().TxIn, mp.btcdb) // Check if this is a Class A transaction if isClassA(tx) { mscutil.Logger.Println("Got 'Class A' transaction with hash", tx.Sha()) // Create a simple send transaction simpleSend, e := mscutil.MakeClassASimpleSend(sender, mscutil.GetAddrsClassA(tx)) err = e if simpleSend != nil { mscutil.Logger.Println("Decoded Simple Send transaction:", simpleSend, simpleSend.Data) msgs = append(msgs, &Msg{msg: simpleSend}) } } else { mscutil.Logger.Println("Got 'Class B' tx with hash", tx.Sha()) // Parse addresses from the tx using class B rules plainTextKeys, receiver, e := mscutil.GetAddrsClassB(tx, sender) err = e if err == nil { // Receiver is first, data is second in the slice // Let's change 00000014h to 22d data := plainTextKeys[0][2:10] f, _ := hex.DecodeString(data) messageType := int(f[3]) switch messageType { case mscutil.TxMsgTy: simpleSend, e := mscutil.MakeClassBSimpleSend(plainTextKeys, receiver, sender) err = e if simpleSend != nil { // TODO: Do we want to add the sender and receiver to the simple send message? mscutil.Logger.Println("Got Simple Send Class B from", sender, "to", receiver) msgs = append(msgs, &Msg{msg: simpleSend}) } default: err = fmt.Errorf("Unknown message type %d. Support for transaction type not implemented yet.\n", messageType) return nil, err } } } if height <= mscutil.FundraiserEndBlock { // Collect the addresses and values for every input used for this transaction highestAddress, _ := mscutil.FindSender(tx.MsgTx().TxIn, mp.btcdb) var totalSpend int64 for _, txOut := range tx.MsgTx().TxOut { addr, _ := mscutil.GetAddrs(txOut.PkScript) if addr[0].Addr == mscutil.ExodusAddress { totalSpend += txOut.Value } } fundraiserTx, e := mscutil.NewFundraiserTransaction(highestAddress, totalSpend, time) err = e msgs = append(msgs, &Msg{msg: fundraiserTx}) } // If nothing has been found it check for Payment for accept DEx message. if len(msgs) == 0 { // TODO: } return }
// Parse transaction takes care of testing the tx for certain rules; class A/B checking // Fundraiser checks and Dex messages as well as properly delegating the raw messages to // the proper object which. After a full Msg has been assembled it will return the Msg // or an error with a description. Whoever called this function should delegate the msg // to the proper object handler. func (mp *MsgParser) ParseTx(tx *btcutil.Tx, height, time int64) (msg *Msg, err error) { sender, _ := mscutil.FindSender(tx.MsgTx().TxIn, mp.server.btcdb) // Check if this is a Class A transaction if isClassA(tx) { mscutil.Logger.Println("Got 'Class A' transaction with hash", tx.Sha()) highestAddress, _ := mscutil.FindSender(tx.MsgTx().TxIn, mp.server.btcdb) // Create a simple send transaction simpleSend, e := mscutil.MakeClassASimpleSend(highestAddress, mscutil.GetAddrsClassA(tx)) err = e if simpleSend != nil { mscutil.Logger.Println("Decoded Simple Send transaction:", simpleSend, simpleSend.Data) msg = &Msg{msg: simpleSend} mscutil.Logger.Fatal("SHUTDOWN") } } else { mscutil.Logger.Println("Got 'Class B' tx") // Parse addresses from the tx using class B rules plainTextKeys, receiver, err := mscutil.GetAddrsClassB(tx, sender) if err == nil { // Receiver is first, data is second in the slice data := plainTextKeys[0][1] // Figure out the message type msgType := mscutil.GetTypeFromAddress(string(data)) switch msgType { case mscutil.TxMsgTy: simpleSend, e := mscutil.MakeClassBSimpleSend(plainTextKeys, receiver) err = e if simpleSend != nil { mscutil.Logger.Println("Got simple send class b transaction") msg = &Msg{msg: simpleSend} } case mscutil.DexMsgTy: default: mscutil.Logger.Println("Unknown message type %d. FIXME or erroneus.\n", int(msgType)) } } } // If nothing has been found it is either a Exodus Kickstarter / Payment for accept DEx message. if msg == nil && err != nil { if height <= mscutil.FundraiserEndBlock { // Collect the addresses and values for every input used for this transaction highestAddress, _ := mscutil.FindSender(tx.MsgTx().TxIn, mp.server.btcdb) var totalSpend int64 for _, txOut := range tx.MsgTx().TxOut { addr, _ := mscutil.GetAddrs(txOut.PkScript) if addr[0].Addr == mscutil.ExodusAddress { totalSpend += txOut.Value } } fundraiserTx, e := mscutil.NewFundraiserTransaction(highestAddress, totalSpend, time) err = e msg = &Msg{msg: fundraiserTx} } else { //MakeDexMessage(outputs) } } return }