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
use xdr_codec::{Pack, Write, Result};
use ::xdr::ToXdr;
use ::strkey::StrKey;
use ::operation::Operation;

fn operation_tag(op: &Operation) -> i32 {
    match *op {
        Operation::CreateAccount { .. } => 0,
        Operation::Payment { .. } => 1,
        Operation::PathPayment { .. } => 2,
        Operation::ManageOffer { .. } => 3,
        Operation::CreatePassiveOffer { .. } => 4,
        Operation::SetOptions { .. } => 5,
        Operation::ChangeTrust { .. } => 6,
        Operation::AllowTrust { .. } => 7,
        Operation::AccountMerge { .. } => 8,
        Operation::Inflation { .. } => 9,
        Operation::ManageData { .. } => 10,
    }
}

fn operation_source(op: &Operation) -> &Option<StrKey> {
    match *op {
        Operation::CreateAccount { ref source, .. } => source,
        Operation::Payment { ref source, .. } => source,
        Operation::PathPayment { ref source, .. } => source,
        Operation::ManageOffer { ref source, .. } => source,
        Operation::CreatePassiveOffer { ref source, .. } => source,
        Operation::SetOptions { ref source, .. } => source,
        Operation::ChangeTrust { ref source, .. } => source,
        Operation::AllowTrust { ref source, .. } => source,
        Operation::AccountMerge { ref source, .. } => source,
        Operation::Inflation { ref source, .. } => source,
        Operation::ManageData { ref source, .. } => source,
    }
}

impl<W: Write> Pack<W> for Operation {
    fn pack(&self, out: &mut W) -> Result<usize> {
        let tag = operation_tag(self);
        let source = operation_source(self);
        let header_size = source.pack(out)? + tag.pack(out)?;
        let body_size = match *self {
            Operation::CreateAccount { ref destination, ref amount, .. } => {
                destination.pack(out)? + amount.pack(out)?
            }            
            Operation::Payment { ref destination, ref asset, ref amount, .. } => {
                destination.pack(out)? + asset.pack(out)? + amount.pack(out)?
            }
            // Operation::PathPayment {} => 2,
            // Operation::ManageOffer {} => 3,
            // Operation::CreatePassiveOffer {} => 4,
            // Operation::SetOptions {} => 5,
            // Operation::ChangeTrust {} => 6,
            // Operation::AllowTrust {} => 7,
            Operation::AccountMerge { ref destination, .. } => destination.pack(out)?,
            Operation::Inflation { .. } => 0, // void
            // Operation::ManageData { ref name, ref value, .. } => 10,
            _ => unimplemented!(),            
        };
        Ok(header_size + body_size)
    }
}

impl ToXdr for Operation {
    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 Amount;
    use Asset;
    use StrKey;
    use Operation;

    #[test]
    fn test_inflation() {
        let op = Operation::inflation();
        assert_eq!(op.to_base64().unwrap(), "AAAAAAAAAAk=");
    }

    #[test]
    fn test_create_account() {
        let dest =
            StrKey::from_account_id("GCLDNMHZTEY6PUYQBYOVERBBZ2W3RLMYOSZWHAMY5R4YW2N6MM4LFA72")
                .unwrap();
        let op = Operation::create_account(dest, Amount::from_i64(20));
        assert_eq!(op.to_base64().unwrap(),
                   "AAAAAAAAAAAAAAAAljaw+Zkx59MQDh1SRCHOrbitmHSzY4GY7HmLab5jOLIAAAAAC+vCAA==");
    }

    #[test]
    fn test_payment() {
        let dest =
            StrKey::from_account_id("GCLDNMHZTEY6PUYQBYOVERBBZ2W3RLMYOSZWHAMY5R4YW2N6MM4LFA72")
                .unwrap();
        let op = Operation::payment(dest, Asset::native(), Amount::from_i64(100));
        assert_eq!(op.to_base64().unwrap(),
                   "AAAAAAAAAAEAAAAAljaw+Zkx59MQDh1SRCHOrbitmHSzY4GY7HmLab5jOLIAAAAAAAAAADuaygA=");

    }
}