1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use xdr_codec::{Pack, Write, Result, pack_flex};
use ::xdr::ToXdr;
use ::transaction::{Transaction, TransactionEnvelope, TaggedTransactionBuffer};


impl<W: Write> Pack<W> for Transaction {
    fn pack(&self, out: &mut W) -> Result<usize> {
        let seqnum = self.seqnum();
        let op = self.operations();
        Ok(self.source().pack(out)? + self.fee().pack(out)? + seqnum.pack(out)? +
           self.time_bounds().pack(out)? + self.memo().pack(out)? +
           pack_flex(&op, Some(100), out)? + (0 as i32).pack(out)?)
    }
}

impl ToXdr for Transaction {
    fn to_writer<W: Write>(&self, mut buf: W) -> ::error::Result<usize> {
        let r = self.pack(&mut buf)?;
        Ok(r)
    }
}

impl<W: Write> Pack<W> for TransactionEnvelope {
    fn pack(&self, out: &mut W) -> Result<usize> {
        let signatures = self.signatures();
        Ok(self.transaction().pack(out)? + pack_flex(&signatures, Some(20), out)?)
    }
}

impl ToXdr for TransactionEnvelope {
    fn to_writer<W: Write>(&self, mut buf: W) -> ::error::Result<usize> {
        let r = self.pack(&mut buf)?;
        Ok(r)
    }
}


impl<W: Write> Pack<W> for TaggedTransactionBuffer {
    fn pack(&self, out: &mut W) -> Result<usize> {
        let tag = self.tag().clone() as i32;
        let size = tag.pack(out)?;
        let total = size + self.transaction_buffer().len();
        out.write_all(&self.transaction_buffer())?;
        Ok(total)
    }
}

impl ToXdr for TaggedTransactionBuffer {
    fn to_writer<W: Write>(&self, mut buf: W) -> ::error::Result<usize> {
        let r = self.pack(&mut buf)?;
        Ok(r)
    }
}

#[cfg(test)]
mod tests {
    use ::xdr::ToXdr;
    use KeyPair;
    use Account;
    use Memo;
    use Network;
    use TimeBounds;
    use TransactionBuilder;

    #[test]
    fn test_time_bounds() {
        let tb1 = TimeBounds::new(None, None);
        let s1 = tb1.to_base64().unwrap();
        assert_eq!(s1, "AAAAAAAAAAAAAAAAAAAAAA==");

        let tb2 = TimeBounds::new(Some(1515283530), None);
        let s2 = tb2.to_base64().unwrap();
        assert_eq!(s2, "AAAAAFpRZEoAAAAAAAAAAA==");

        let tb3 = TimeBounds::new(None, Some(1515283530));
        let s3 = tb3.to_base64().unwrap();
        assert_eq!(s3, "AAAAAAAAAAAAAAAAWlFkSg==");

        let tb4 = TimeBounds::new(Some(1515283530), Some(1515283530));
        let s4 = tb4.to_base64().unwrap();
        assert_eq!(s4, "AAAAAFpRZEoAAAAAWlFkSg==");
    }

    #[test]
    fn test_transaction_no_time_bounds() {
        let mut account =
            Account::from_account_id("GCLDNMHZTEY6PUYQBYOVERBBZ2W3RLMYOSZWHAMY5R4YW2N6MM4LFA72",
                                     999)
                .unwrap();

        let memo = Memo::Text("test post please ignore".to_string());
        let tx = TransactionBuilder::new(&mut account)
            .with_memo(memo)
            .with_fee(200)
            .build()
            .unwrap();
        let s = tx.to_base64().unwrap();
        assert_eq!(s,
                   "AAAAAJY2sPmZMefTEA4dUkQhzq24rZh0s2OBmOx5i2m+YziyAAAAAAAAAAAAAAPoAAAAAAAAAAEAAAAXdGVzdCBwb3N0IHBsZWFzZSBpZ25vcmUAAAAAAAAAAAA=");
    }

    #[test]
    fn test_transaction() {
        let mut account =
            Account::from_account_id("GCLDNMHZTEY6PUYQBYOVERBBZ2W3RLMYOSZWHAMY5R4YW2N6MM4LFA72",
                                     999)
                .unwrap();

        let memo = Memo::Text("test post please ignore".to_string());
        let tx = TransactionBuilder::new(&mut account)
            .with_memo(memo)
            .with_fee(200)
            .with_lower_time_bound(0)
            .with_upper_time_bound(12345678)
            .build()
            .unwrap();
        let s = tx.to_base64().unwrap();
        assert_eq!(s,
                   "AAAAAJY2sPmZMefTEA4dUkQhzq24rZh0s2OBmOx5i2m+YziyAAAAAAAAAAAAAAPoAAAAAQAAAAAAAAAAAAAAAAC8YU4AAAABAAAAF3Rlc3QgcG9zdCBwbGVhc2UgaWdub3JlAAAAAAAAAAAA");
    }

    #[test]
    fn test_transaction_signatures() {
        let kp1 = KeyPair::from_secret("SASMDWFIDNQ23SWYZC5CLAIULQB65XK37XUX5SCAVJ3UTLCSLMCLSXNA")
            .unwrap();
        let kp2 = KeyPair::from_secret("SAB4OGFUWU5IDNACQ7MIAELTZENUVKMIBMZ2D5QKI6N4EOBHAHWCZWJ6")
            .unwrap();
        let pk = kp1.public_key();
        let mut account = Account::new(&pk, 0).unwrap();

        let memo = Memo::Text("test post please ignore".to_string());
        let tx = TransactionBuilder::new(&mut account)
            .with_memo(memo)
            .build()
            .unwrap();
        let mut sig_tx = tx.sign_with_network(&kp1, Network::test_network()).unwrap();
        sig_tx.sign(&kp2).unwrap();
        assert_eq!(sig_tx.to_base64().unwrap(),
                   "AAAAAO7K8WLSyKYleTjmxO/WUGH4s53oedi6EOO2xeL1MmwbAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAXdGVzdCBwb3N0IHBsZWFzZSBpZ25vcmUAAAAAAAAAAAAAAAAC9TJsGwAAAEDAHLteLpJqU4T/zFp6dR+waNza2aZeNJ8e4Q9387vUf1IDZ2YBqXPZvuaSF8TQpKLpfoB83Akq8FSjDuGr3H0Fl7gdXQAAAEBDeS+OY7ezW06xToI0hSGJAqDc6Vfzg4PftYB54Gx7IMUgTwAioS7JamR87O0nZrX+EoGZEEHJ6ZoDBvdlmWwO");
    }
}