Bitcoin Forum

Bitcoin => Development & Technical Discussion => Topic started by: Armin van Bruggen on November 04, 2016, 10:21:25 AM



Title: sending rawtransaction in bitcoin testnet (double spend)
Post by: Armin van Bruggen on November 04, 2016, 10:21:25 AM
After reading this article:

http://bitzuma.com/posts/how-to-clear-a-stuck-bitcoin-transaction/ (http://bitzuma.com/posts/how-to-clear-a-stuck-bitcoin-transaction/)

I would like to try a double spending (in bitcoin testnetwork).
Creating the transaction and signing it wasn't a problem. Now I'm looking for a way to send the second transaction (the first one was sent with 0.00000000 fee), now I would need to resent the transaction with a fee, so it get's processed by the testnet network of bitcoin.
How to submit now these second transaction?

All services I tried blocked this transaction.
As the article says:
Quote
We can’t publish this new transaction using Coinbin because it will be rejected as a double spend.


Title: Re: sending rawtransaction in bitcoin testnet (double spend)
Post by: Jhanzo on November 04, 2016, 10:38:46 AM
It got rejected because the the node(s) those services are relying on still have the first transaction.  You'll have to wait until they drop it.


Title: Re: sending rawtransaction in bitcoin testnet (double spend)
Post by: Armin van Bruggen on November 04, 2016, 10:43:05 AM
It got rejected because the the node(s) those services are relying on still have the first transaction.  You'll have to wait until they drop it.

In case I want to get this transaction appear too in the network without the first transaction being dropped/processed by the network, how can I do so?


Title: Re: sending rawtransaction in bitcoin testnet (double spend)
Post by: Jhanzo on November 04, 2016, 10:54:46 AM
It got rejected because the the node(s) those services are relying on still have the first transaction.  You'll have to wait until they drop it.

In case I want to get this transaction appear too in the network without the first transaction being dropped/processed by the network, how can I do so?

Unconfirmed transactions rarely gets dropped by the entire network.  There can be more than 1 identical unconfirmed transactions in the network, but not in a nodes mempool.  As long as a node doesn't have the first transaction, it can accept the second transaction and will try to relay it to the rest of the network.  So to answer your question (replacing the word "network" with "nodes"), you can't.

BTW RBF pretty much erased the need to manually double spending a transaction because they're stuck.  Use RBF instead.


Title: Re: sending rawtransaction in bitcoin testnet (double spend)
Post by: Armin van Bruggen on November 04, 2016, 11:10:27 AM
@Jhanzo

First of all, thanks for this detailed answer!

Let me try, what I would like to do, please check this video:

https://www.youtube.com/watch?v=RtGzV_-agcI (https://www.youtube.com/watch?v=RtGzV_-agcI)

I would like to built the same, but open source the code. I'm running bitcoin-classic daemon on my ubuntu server. Now I'm looking for a description how to "double spend" the coins I received from a user (first transaction with no fee, second transaction with small fee, so user receives his depoisted amount nearly full back and a double spend was done). I would like to use testnet for whole script.

Could you explain me how to process the transactions (I know how to create & sign them), but how to send them now?


Title: Re: sending rawtransaction in bitcoin testnet (double spend)
Post by: amaclin on November 06, 2016, 06:25:09 AM
Could you explain me how to process the transactions
(I know how to create & sign them), but how to send them now?

This is very "dirty" piece of code, but it works.
Of course, this one is "for educational purposes only"

Code:
#include <QTimer>
#include <QDebug>
#include <QFile>
#include <QList>
#include <QByteArray>
#include <QDateTime>
#include <QHostAddress>
#include <QCoreApplication>
#include <QDataStream>

#include "Bitcoin.h"

#define _xtrace(X) qDebug ( ) << ( X )
#define _xassert(X) Q_ASSERT ( X )

#define MAGIC_ID  0x709110b

#define TYPE_VERSION ( "version" "\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" )
#define TYPE_VERACK  ( "verack"  "\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" )
#define TYPE_GETDATA ( "getdata" "\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" )
#define TYPE_PING    ( "ping"    "\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" )
#define TYPE_PONG    ( "pong"    "\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" )
#define TYPE_TX      ( "tx"      "\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" )

#define USER_AGENT          "/Satoshi:0.9.1/"
#define PROTO_VERSION       70002
#define PROTO_SERVICES      (1) // can be NODE_NETWORK

Bitcoin::Bitcoin ( const QByteArray& tx, QObject* parent) : QObject ( parent )
{
  this -> children = 0;
  this -> tx = tx;
  QTimer::singleShot ( 10, this, SLOT ( start ( ) ) );
}
//--------------------------------------------------------------
void Bitcoin::start ( )
{
  QFile conf ( "PushTxTool.conf" );
  _xassert ( conf.open ( QIODevice::ReadOnly ) );
  QByteArray data ( conf.readAll ( ) );
  data.replace ( '\n', ' ' );
  data.replace ( '\r', ' ' );
  data.replace ( '\t', ' ' );
  const QList<QByteArray> list ( data.split ( ' ' ) );
  for ( int i ( 0 ); i < list.size ( ); i++ )
    if ( !list.at ( i ).isEmpty ( ) )
    {
      static QSet<QByteArray> set;
      if ( !set.contains ( list.at ( i ) ) )
      {
        new NetSocket ( list.at ( i ), tx, this );
        children++;
        set.insert ( list.at ( i ) );
      }
      else
        _xtrace ( QString ( "err %1 ..." ).arg ( list.at ( i ).constData ( ) ) );
    }
}
//--------------------------------------------------------------
void Bitcoin::finished ( )
{
  if ( --children == 0 )
    QTimer::singleShot ( 10, this, SLOT ( done ( ) ) );
}
//--------------------------------------------------------------
void Bitcoin::done ( )
{
  _xtrace ( "-----------done------------" );
  QCoreApplication::exit ( );
}
//==============================================================
NetSocket::NetSocket ( const QByteArray& host, const QByteArray& tx, QObject* parent ) : QObject ( parent )
{
  this -> host = host;
  _xtrace ( QString ( "%1 ..." ).arg ( host.constData ( ) ) );
  this -> tx = tx;
  this -> socket = new QTcpSocket ( this );
  connect ( this, SIGNAL ( destroyed ( ) ), parent, SLOT ( finished ( ) ) );
  QTimer::singleShot ( 1, this, SLOT ( start ( ) ) );
}
//--------------------------------------------------------------
void NetSocket::start ( )
{
  _xtrace ( QString ( "%1 start ..." ).arg ( host.constData ( ) ) );
  connect ( socket, SIGNAL ( connected ( ) ), this, SLOT ( onConnected ( ) ) );
  connect ( socket, SIGNAL ( readyRead ( ) ), this, SLOT ( onReadyRead ( ) ) );
  connect ( socket, SIGNAL ( error ( QAbstractSocket::SocketError ) ), this, SLOT ( onError ( QAbstractSocket::SocketError ) ) );
  socket -> connectToHost ( host.constData ( ), 18333 );
}
//--------------------------------------------------------------
void NetSocket::onConnected ( )
{
  _xtrace ( QString ( "%1 connected" ).arg ( host.constData ( ) ) );
  write ( packet ( TYPE_VERSION, versionPacket ( 600000, USER_AGENT ) ) );
}
//--------------------------------------------------------------
void NetSocket::onReadyRead ( )
{
  QDataStream in ( socket );
  for ( qint64 length; (length = socket -> bytesAvailable ( )) >= 0; )
  {
    char data [length];
    const int read ( in.readRawData ( data, length ) );
    if ( read > 0 )
      buf.append ( data, read );
    else
      break;
  }
  for ( QByteArray b; buf.readPacket ( b ); )
    proc ( b );
  buf.squeeze ( );
}
//--------------------------------------------------------------
void NetSocket::proc ( const QByteArray& data )
{
  const char* type = data.constData ( ) + 4;
  if ( !strcmp ( type, "version" ) ) { procVersionPacket ( data ); return; }
  if ( !strcmp ( type, "verack"  ) ) { procVerackPacket  ( data ); return; }
}
//--------------------------------------------------------------
void NetSocket::onError ( QAbstractSocket::SocketError code )
{
  _xtrace ( QString ( "%1 : error %2" ).arg ( host.constData ( ) ).arg ( code ) );
  deleteLater ( );
}
//--------------------------------------------------------------
const QByteArray NetSocket::packet ( const char* type, const QByteArray& payload )
{
  return MyByteArray ( )
    .putInt32 ( MAGIC_ID )
    .putAscii_12 ( type )
    .putInt32 ( payload.size ( ) )
    .append ( MyKey32 ( payload.constData ( ), payload.size ( ) ).constData ( ), 4 )
    .append ( payload );
}
//--------------------------------------------------------------
const QByteArray NetSocket::versionPacket ( const int known, const char* ua ) const
{
  return MyByteArray ( )
    .putInt32 ( PROTO_VERSION )
    .putInt64 ( PROTO_SERVICES )
    .putInt64 ( QDateTime::currentMSecsSinceEpoch ( ) / 1000 )
    .putInt64 ( PROTO_SERVICES )
    .putInt64 ( 0 ) // date
    .putInt32 ( 0xFFFF0000 )
    .putInt32_be ( socket -> peerAddress ( ).toIPv4Address ( ) )
    .putInt16_be ( socket -> peerPort ( ) )
    .putInt64 ( 0 )
    .putInt64 ( 0 )
    .putInt32 ( 0xFFFF0000 )
    .putInt32 ( 0 )
    .putInt16_be ( 18333 )
    .putInt64 ( (quint64)qrand ( ) ^ QDateTime::currentMSecsSinceEpoch ( ) )
    .putVarAscii ( ua )
    .putInt32 ( known )
    .putInt8 ( 1 );
}
//--------------------------------------------------------------
void NetSocket::procVersionPacket ( const QByteArray& )
{
  write ( packet ( TYPE_VERACK, verackPacket ( ) ) );
}
//--------------------------------------------------------------
void NetSocket::procVerackPacket ( const QByteArray& )
{
  write ( packet ( TYPE_TX, txPacket ( tx ) ) );
  _xtrace ( QString ( "%1 sent %2" ).arg ( host.constData ( ) ).arg ( MyKey32 ( tx.constData ( ), tx.size ( ) ).toString ( ) ) );
  QTimer::singleShot ( 0, this, SLOT ( deleteLater ( ) ) );
}
//--------------------------------------------------------------
MyByteArray& MyByteArray::putVarInt ( const unsigned value )
{
  return ( value < 0xFD )    ? putInt8 ( value ) :
         ( value <= 0xFFFF ) ? putInt8 ( 0xFD ).putInt16 ( value ) :
                               putInt8 ( 0xFE ).putInt32 ( value );
}
//--------------------------------------------------------------
bool MyByteArray::readPacket ( QByteArray& buf )
{
  if ( size ( ) > 20 )
  {
    _xassert ( *(quint32*)(constData ( )) == MAGIC_ID );
    const int sz ( *(qint32*)(constData ( ) + 16) );
    if ( size ( ) >= ( 24 + sz ) )
    {
      buf = QByteArray ( constData ( ), 24 + sz );
      remove ( 0, 24 + sz );
      return true;
    }
  }
  return false;
}


Title: Re: sending rawtransaction in bitcoin testnet (double spend)
Post by: Armin van Bruggen on November 06, 2016, 06:00:25 PM
Could you explain me how to process the transactions
(I know how to create & sign them), but how to send them now?

This is very "dirty" piece of code, but it works.
Of course, this one is "for educational purposes only"

Code:
#include <QTimer>
#include <QDebug>
#include <QFile>
#include <QList>
#include <QByteArray>
#include <QDateTime>
#include <QHostAddress>
#include <QCoreApplication>
#include <QDataStream>

#include "Bitcoin.h"

#define _xtrace(X) qDebug ( ) << ( X )
#define _xassert(X) Q_ASSERT ( X )

#define MAGIC_ID  0x709110b

#define TYPE_VERSION ( "version" "\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" )
#define TYPE_VERACK  ( "verack"  "\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" )
#define TYPE_GETDATA ( "getdata" "\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" )
#define TYPE_PING    ( "ping"    "\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" )
#define TYPE_PONG    ( "pong"    "\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" )
#define TYPE_TX      ( "tx"      "\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" )

#define USER_AGENT          "/Satoshi:0.9.1/"
#define PROTO_VERSION       70002
#define PROTO_SERVICES      (1) // can be NODE_NETWORK

Bitcoin::Bitcoin ( const QByteArray& tx, QObject* parent) : QObject ( parent )
{
  this -> children = 0;
  this -> tx = tx;
  QTimer::singleShot ( 10, this, SLOT ( start ( ) ) );
}
//--------------------------------------------------------------
void Bitcoin::start ( )
{
  QFile conf ( "PushTxTool.conf" );
  _xassert ( conf.open ( QIODevice::ReadOnly ) );
  QByteArray data ( conf.readAll ( ) );
  data.replace ( '\n', ' ' );
  data.replace ( '\r', ' ' );
  data.replace ( '\t', ' ' );
  const QList<QByteArray> list ( data.split ( ' ' ) );
  for ( int i ( 0 ); i < list.size ( ); i++ )
    if ( !list.at ( i ).isEmpty ( ) )
    {
      static QSet<QByteArray> set;
      if ( !set.contains ( list.at ( i ) ) )
      {
        new NetSocket ( list.at ( i ), tx, this );
        children++;
        set.insert ( list.at ( i ) );
      }
      else
        _xtrace ( QString ( "err %1 ..." ).arg ( list.at ( i ).constData ( ) ) );
    }
}
//--------------------------------------------------------------
void Bitcoin::finished ( )
{
  if ( --children == 0 )
    QTimer::singleShot ( 10, this, SLOT ( done ( ) ) );
}
//--------------------------------------------------------------
void Bitcoin::done ( )
{
  _xtrace ( "-----------done------------" );
  QCoreApplication::exit ( );
}
//==============================================================
NetSocket::NetSocket ( const QByteArray& host, const QByteArray& tx, QObject* parent ) : QObject ( parent )
{
  this -> host = host;
  _xtrace ( QString ( "%1 ..." ).arg ( host.constData ( ) ) );
  this -> tx = tx;
  this -> socket = new QTcpSocket ( this );
  connect ( this, SIGNAL ( destroyed ( ) ), parent, SLOT ( finished ( ) ) );
  QTimer::singleShot ( 1, this, SLOT ( start ( ) ) );
}
//--------------------------------------------------------------
void NetSocket::start ( )
{
  _xtrace ( QString ( "%1 start ..." ).arg ( host.constData ( ) ) );
  connect ( socket, SIGNAL ( connected ( ) ), this, SLOT ( onConnected ( ) ) );
  connect ( socket, SIGNAL ( readyRead ( ) ), this, SLOT ( onReadyRead ( ) ) );
  connect ( socket, SIGNAL ( error ( QAbstractSocket::SocketError ) ), this, SLOT ( onError ( QAbstractSocket::SocketError ) ) );
  socket -> connectToHost ( host.constData ( ), 18333 );
}
//--------------------------------------------------------------
void NetSocket::onConnected ( )
{
  _xtrace ( QString ( "%1 connected" ).arg ( host.constData ( ) ) );
  write ( packet ( TYPE_VERSION, versionPacket ( 600000, USER_AGENT ) ) );
}
//--------------------------------------------------------------
void NetSocket::onReadyRead ( )
{
  QDataStream in ( socket );
  for ( qint64 length; (length = socket -> bytesAvailable ( )) >= 0; )
  {
    char data [length];
    const int read ( in.readRawData ( data, length ) );
    if ( read > 0 )
      buf.append ( data, read );
    else
      break;
  }
  for ( QByteArray b; buf.readPacket ( b ); )
    proc ( b );
  buf.squeeze ( );
}
//--------------------------------------------------------------
void NetSocket::proc ( const QByteArray& data )
{
  const char* type = data.constData ( ) + 4;
  if ( !strcmp ( type, "version" ) ) { procVersionPacket ( data ); return; }
  if ( !strcmp ( type, "verack"  ) ) { procVerackPacket  ( data ); return; }
}
//--------------------------------------------------------------
void NetSocket::onError ( QAbstractSocket::SocketError code )
{
  _xtrace ( QString ( "%1 : error %2" ).arg ( host.constData ( ) ).arg ( code ) );
  deleteLater ( );
}
//--------------------------------------------------------------
const QByteArray NetSocket::packet ( const char* type, const QByteArray& payload )
{
  return MyByteArray ( )
    .putInt32 ( MAGIC_ID )
    .putAscii_12 ( type )
    .putInt32 ( payload.size ( ) )
    .append ( MyKey32 ( payload.constData ( ), payload.size ( ) ).constData ( ), 4 )
    .append ( payload );
}
//--------------------------------------------------------------
const QByteArray NetSocket::versionPacket ( const int known, const char* ua ) const
{
  return MyByteArray ( )
    .putInt32 ( PROTO_VERSION )
    .putInt64 ( PROTO_SERVICES )
    .putInt64 ( QDateTime::currentMSecsSinceEpoch ( ) / 1000 )
    .putInt64 ( PROTO_SERVICES )
    .putInt64 ( 0 ) // date
    .putInt32 ( 0xFFFF0000 )
    .putInt32_be ( socket -> peerAddress ( ).toIPv4Address ( ) )
    .putInt16_be ( socket -> peerPort ( ) )
    .putInt64 ( 0 )
    .putInt64 ( 0 )
    .putInt32 ( 0xFFFF0000 )
    .putInt32 ( 0 )
    .putInt16_be ( 18333 )
    .putInt64 ( (quint64)qrand ( ) ^ QDateTime::currentMSecsSinceEpoch ( ) )
    .putVarAscii ( ua )
    .putInt32 ( known )
    .putInt8 ( 1 );
}
//--------------------------------------------------------------
void NetSocket::procVersionPacket ( const QByteArray& )
{
  write ( packet ( TYPE_VERACK, verackPacket ( ) ) );
}
//--------------------------------------------------------------
void NetSocket::procVerackPacket ( const QByteArray& )
{
  write ( packet ( TYPE_TX, txPacket ( tx ) ) );
  _xtrace ( QString ( "%1 sent %2" ).arg ( host.constData ( ) ).arg ( MyKey32 ( tx.constData ( ), tx.size ( ) ).toString ( ) ) );
  QTimer::singleShot ( 0, this, SLOT ( deleteLater ( ) ) );
}
//--------------------------------------------------------------
MyByteArray& MyByteArray::putVarInt ( const unsigned value )
{
  return ( value < 0xFD )    ? putInt8 ( value ) :
         ( value <= 0xFFFF ) ? putInt8 ( 0xFD ).putInt16 ( value ) :
                               putInt8 ( 0xFE ).putInt32 ( value );
}
//--------------------------------------------------------------
bool MyByteArray::readPacket ( QByteArray& buf )
{
  if ( size ( ) > 20 )
  {
    _xassert ( *(quint32*)(constData ( )) == MAGIC_ID );
    const int sz ( *(qint32*)(constData ( ) + 16) );
    if ( size ( ) >= ( 24 + sz ) )
    {
      buf = QByteArray ( constData ( ), 24 + sz );
      remove ( 0, 24 + sz );
      return true;
    }
  }
  return false;
}

Isn't there a way to use the bitcoin daemon I run on a server in testnetmode to send a double spend transaction?


Title: Re: sending rawtransaction in bitcoin testnet (double spend)
Post by: amaclin on November 06, 2016, 06:34:24 PM
Isn't there a way to use the bitcoin daemon I run on a server in testnetmode to send a double spend transaction?

Sorry.
I thought that you are asking "how to send conflicting transaction?"
not "how to send conflicting transaction with custom bitcoin client?"


Title: Re: sending rawtransaction in bitcoin testnet (double spend)
Post by: Armin van Bruggen on November 06, 2016, 06:39:56 PM
Isn't there a way to use the bitcoin daemon I run on a server in testnetmode to send a double spend transaction?

Sorry.
I thought that you are asking "how to send conflicting transaction?"
not "how to send conflicting transaction with custom bitcoin client?"

Would be fine if you could show me how to do this using bitcoind command set:

https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_calls_list

Would drop you a tip if working of course ;)


Title: Re: sending rawtransaction in bitcoin testnet (double spend)
Post by: amaclin on November 06, 2016, 08:02:34 PM
Would be fine if you could show me how to do this using bitcoind command set:
https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_calls_list
Would drop you a tip if working of course ;)
I can not. I never used bitcoin client for sending transactions.
I gave you a program written in C++ for broadcasting raw transactions for a number of nodes.
(Sorry, I havent't looked the sources for a couple of years - the program works and there is no reason to remember how  ;D )