Vermeidung von Eigentumszyklen in Verträgen

Ich stehe wiederholt vor diesem Problem mit dem Code für die Strukturierung von Verträgen:

contract Allower {
    Allowed allowed;

    function doSth() onlyallowed;

    modifier onlyallowed {
        if (msg.sender != address(allowed))
            throw;
        _
    }
}

contract Allowed {
    Allower allower;

    function doSthOnAllower() {
        allower.doSth();
    }
}

Um durchzusetzen, dass nur eine bestimmte Instanz von Allowedausgeführt Allower.doSthwird, müssen die Verträge gegenseitige Referenzen beibehalten (vorausgesetzt, wir mögen die 1-1-Beziehung, möchten diese Verträge aber dennoch getrennt halten). Um nun beide Verträge bereitzustellen und zum Laufen zu bringen, müssen wir mehr oder weniger hinzufügen:

contract Allower {
    // snip...
    function Allower(Allowed _allowed) {
        allowed = _allowed;
        allowed.setAllower(this);
    }
}

contract Allowed {
    // snip...
    function setAllower(Allower _allower) allowernotset {
        allower = _allower;
    }
}

Gibt es ein Muster, das es ermöglichen würde, die Notwendigkeit von zu umgehen setAllower? Es scheint nur ein Anti-Pattern zu sein, wenn sich solche "Set"-Methoden ausbreiten.

Antworten (2)

Laut hier :

Beachten Sie, dass es uns die neue Vertragsadresse gegeben hat. Woher kommt diese Adresse? Es ist der sha3-Hash der RLP-Kodierung der Liste [Adresse des Absenders, Sequenznummer des Absenders].

Wenn Sie im Voraus wissen, zu welcher TX-Nonce Sie bereitstellen werden, Allowerund Sie diese RLP-Berechnung selbst durchführen können, können Sie die Adresse berechnen, die Sie an den Konstrukteur Ihres AllowedVertrags weitergeben. Und umgekehrt.

Lassen Sie uns dieses Python-Skript in Javascript reproduzieren :

#!/usr/bin/nodejs

var ethJsUtil = require('ethereumjs-util');

var account = "0x6ac7ea33f8831ea9dcc53393aaa88b25a785dbf0";
console.log("nonce0=" + ethJsUtil.bufferToHex(ethJsUtil.generateAddress(account, 0)));
console.log("nonce1=" + ethJsUtil.bufferToHex(ethJsUtil.generateAddress(account, 1)));
console.log("nonce2=" + ethJsUtil.bufferToHex(ethJsUtil.generateAddress(account, 2)));
console.log("nonce3=" + ethJsUtil.bufferToHex(ethJsUtil.generateAddress(account, 3)));

Mein Interesse stieg, ich habe hier auch ein kleines Truffle-Projekt erstellt, wo ich für die Bereitstellung Folgendes mache:

module.exports = Funktion (Bereitsteller) {
    // Sie müssen npm install -g ethereumjs-util ausführen
    var ethJsUtil = require('/usr/lib/node_modules/ethereumjs-util/');

    var currentNonce = web3.eth.getTransactionCount(web3.eth.accounts[0]);
    var futureLeftNonce = aktuelleNonce;
    var futureLeftAddress = ethJsUtil.bufferToHex(ethJsUtil.generateAddress(
        web3.eth.accounts[0], futureLeftNonce));
    var futureRightNonce = futureLeftNonce + 1;
    var futureRightAddress = ethJsUtil.bufferToHex(ethJsUtil.generateAddress(
        web3.eth.accounts[0], futureRightNonce));

    deployer.deploy (links, futureRightAddress);
    deployer.deploy (Rechts, futureLeftAddress);
};

Ich bin mir nicht sicher, inwieweit es das Problem beheben würde, aber man kann erwägen, die "1-1-Beziehung" in einen separaten Vertrag aufzunehmen, der vor beiden Allowerund eingesetzt wird Allowed.

contract Handcuffs {
    address left;
    address right;

    // set() must be called by both handcuffed contracts
    function set() {
        if (left == 0x0)
            left = msg.sender;
        else if (right == 0x0)
            right = msg.sender;
        else
            throw;
    }

    // once handcuffed, get() always returns the other contract
    function get() constant returns (address partner) {
        if (msg.sender == left && right != 0)
            return right;
        else if (msg.sender == right && left != 0)
            return left;
        else
            throw;
    }
}

contract Allower {
    Handcuffs allowed;

    function Allower(Handcuffs _allowed) {
        allowed = _allowed;
        allowed.set();
    }

    function doSth() onlyallowed;

    modifier onlyallowed {
        if (msg.sender != allowed.get())
            throw;
        _
    }
}

contract Allowed {
    Handcuffs allower;

    function Allowed (Handcuffs _allower) {
        allower = _allower;
        allower.set();
    }

    function doSthOnAllower() {
        var allowerContract = Allower(allower.get());
        allowerContract.doSth();
    }
}

Eine Alternative dazu wäre, den Deployer-Aufruf explizit setzen zu lassen und somit Allowervon Allowedjeglicher Verantwortung zu befreien:

contract Handcuffs {
    // snip...
    function set(address _left, address _right) onlydeployer onlyonce {
        left = _left;
        right = _right;
    }
    // snip...
}