Sendevorgänge atomar ausführen

Ich habe drei Adressen a1, a2, a3an die ich ein Drittel des Saldos eines Vertrags in der minimalen Anzahl von Transaktionen (idealerweise nur eine) und ohne Speicherung senden möchte. Ich könnte eine Funktion wie folgt haben:

function withdraw() {
    uint split = this.balance/3;

    a1.send(split);
    a2.send(split);
    a3.send(split);
}

Das Problem betrifft die Atomarität und das Ausgasen. Soweit ich weiß , wird eine Gasmangel-Ausnahme den Betrieb rückgängig machen, aber der sendBetrieb ist eine Ausnahme:

Wenn in einem Unteraufruf Ausnahmen auftreten, „sprudeln“ sie automatisch (dh Ausnahmen werden erneut ausgelöst). Ausnahmen von dieser Regel sind sendund die Low-Level-Funktionen call, delegatecallund callcode– diese kehren falseim Ausnahmefall zurück, anstatt „hervorzusprudeln“.

So ist es möglich a1, immer wieder withdraw()mit gerade genug Gas für den ersten sendzu callen und damit den Vertrag für sich selbst aufzubrauchen.

Man könnte versuchen, einen Mechanismus so zu gestalten, dass sich der Anrufer zuletzt zurückzieht. Zum Beispiel:

function withdraw() {
    if(msg.sender != a1 && msg.sender != a2 && msg.sender != a3) return;
    uint split = this.balance/3;

    if(msg.sender != a1) a1.send(split);
    if(msg.sender != a2) a2.send(split);
    if(msg.sender != a3) a3.send(split);

    // msg.sender goes last
    msg.sender.send(split);
}

Das Problem hier ist, dass a1und a3heimliche Absprachen treffen können, um zu betrügen a2. In der Tat a3kann wiederholter Anruf withdrawgerade genug Gas geben, um den Vertrag zu leeren a1.

Ich schätze, es ist möglich, Abhebungen zu verfolgen, die mit der Speicherung aufgetreten sind, aber das scheint übertrieben zu sein.

Gibt es eine Möglichkeit, mehrere sendOperationen atomar durchzuführen, ähnlich wie Bitcoin mehrere UTXOs in einer einzigen Transaktion haben kann?

Antworten (1)

Sie haben Recht mit dem DoS-Risiko von einem der Empfänger.

Beschränken Sie Funktionsinteraktionen in der Regel auf jeweils einen nicht vertrauenswürdigen Vertrag.

Stellen Sie sich Ihre withdraw()Funktion so vor, dass Sie sich jeweils nur mit einem von ihnen befassen. Sie werden individuell ihren Anspruch geltend machen.

Etwas wie:

function withdraw(uint amount) returns(bool success) {
  amount = balance[msg.sender]
  balance[msg.sender] = 0;
  if(amount==0) throw;
  LogWithdrawal(msg.sender, amount);
  msg.sender.transfer(amount);
  return true;
}

Ich hoffe es hilft.